netwerk/sctp/src/netinet/sctp_asconf.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rwxr-xr-x

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /*-
michael@0 2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
michael@0 3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
michael@0 4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
michael@0 5 *
michael@0 6 * Redistribution and use in source and binary forms, with or without
michael@0 7 * modification, are permitted provided that the following conditions are met:
michael@0 8 *
michael@0 9 * a) Redistributions of source code must retain the above copyright notice,
michael@0 10 * this list of conditions and the following disclaimer.
michael@0 11 *
michael@0 12 * b) Redistributions in binary form must reproduce the above copyright
michael@0 13 * notice, this list of conditions and the following disclaimer in
michael@0 14 * the documentation and/or other materials provided with the distribution.
michael@0 15 *
michael@0 16 * c) Neither the name of Cisco Systems, Inc. nor the names of its
michael@0 17 * contributors may be used to endorse or promote products derived
michael@0 18 * from this software without specific prior written permission.
michael@0 19 *
michael@0 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
michael@0 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
michael@0 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
michael@0 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
michael@0 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
michael@0 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
michael@0 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
michael@0 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
michael@0 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
michael@0 30 * THE POSSIBILITY OF SUCH DAMAGE.
michael@0 31 */
michael@0 32
michael@0 33 #ifdef __FreeBSD__
michael@0 34 #include <sys/cdefs.h>
michael@0 35 __FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 257803 2013-11-07 17:08:09Z tuexen $");
michael@0 36 #endif
michael@0 37
michael@0 38 #include <netinet/sctp_os.h>
michael@0 39 #include <netinet/sctp_var.h>
michael@0 40 #include <netinet/sctp_sysctl.h>
michael@0 41 #include <netinet/sctp_pcb.h>
michael@0 42 #include <netinet/sctp_header.h>
michael@0 43 #include <netinet/sctputil.h>
michael@0 44 #include <netinet/sctp_output.h>
michael@0 45 #include <netinet/sctp_asconf.h>
michael@0 46 #include <netinet/sctp_timer.h>
michael@0 47
michael@0 48 /*
michael@0 49 * debug flags:
michael@0 50 * SCTP_DEBUG_ASCONF1: protocol info, general info and errors
michael@0 51 * SCTP_DEBUG_ASCONF2: detailed info
michael@0 52 */
michael@0 53
michael@0 54 #if defined(__APPLE__)
michael@0 55 #define APPLE_FILE_NO 1
michael@0 56 #endif
michael@0 57
michael@0 58 /*
michael@0 59 * RFC 5061
michael@0 60 *
michael@0 61 * An ASCONF parameter queue exists per asoc which holds the pending address
michael@0 62 * operations. Lists are updated upon receipt of ASCONF-ACK.
michael@0 63 *
michael@0 64 * A restricted_addrs list exists per assoc to hold local addresses that are
michael@0 65 * not (yet) usable by the assoc as a source address. These addresses are
michael@0 66 * either pending an ASCONF operation (and exist on the ASCONF parameter
michael@0 67 * queue), or they are permanently restricted (the peer has returned an
michael@0 68 * ERROR indication to an ASCONF(ADD), or the peer does not support ASCONF).
michael@0 69 *
michael@0 70 * Deleted addresses are always immediately removed from the lists as they will
michael@0 71 * (shortly) no longer exist in the kernel. We send ASCONFs as a courtesy,
michael@0 72 * only if allowed.
michael@0 73 */
michael@0 74
michael@0 75 /*
michael@0 76 * ASCONF parameter processing.
michael@0 77 * response_required: set if a reply is required (eg. SUCCESS_REPORT).
michael@0 78 * returns a mbuf to an "error" response parameter or NULL/"success" if ok.
michael@0 79 * FIX: allocating this many mbufs on the fly is pretty inefficient...
michael@0 80 */
michael@0 81 static struct mbuf *
michael@0 82 sctp_asconf_success_response(uint32_t id)
michael@0 83 {
michael@0 84 struct mbuf *m_reply = NULL;
michael@0 85 struct sctp_asconf_paramhdr *aph;
michael@0 86
michael@0 87 m_reply = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_paramhdr),
michael@0 88 0, M_NOWAIT, 1, MT_DATA);
michael@0 89 if (m_reply == NULL) {
michael@0 90 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 91 "asconf_success_response: couldn't get mbuf!\n");
michael@0 92 return (NULL);
michael@0 93 }
michael@0 94 aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
michael@0 95 aph->correlation_id = id;
michael@0 96 aph->ph.param_type = htons(SCTP_SUCCESS_REPORT);
michael@0 97 aph->ph.param_length = sizeof(struct sctp_asconf_paramhdr);
michael@0 98 SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
michael@0 99 aph->ph.param_length = htons(aph->ph.param_length);
michael@0 100
michael@0 101 return (m_reply);
michael@0 102 }
michael@0 103
michael@0 104 static struct mbuf *
michael@0 105 sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t *error_tlv,
michael@0 106 uint16_t tlv_length)
michael@0 107 {
michael@0 108 struct mbuf *m_reply = NULL;
michael@0 109 struct sctp_asconf_paramhdr *aph;
michael@0 110 struct sctp_error_cause *error;
michael@0 111 uint8_t *tlv;
michael@0 112
michael@0 113 m_reply = sctp_get_mbuf_for_msg((sizeof(struct sctp_asconf_paramhdr) +
michael@0 114 tlv_length +
michael@0 115 sizeof(struct sctp_error_cause)),
michael@0 116 0, M_NOWAIT, 1, MT_DATA);
michael@0 117 if (m_reply == NULL) {
michael@0 118 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 119 "asconf_error_response: couldn't get mbuf!\n");
michael@0 120 return (NULL);
michael@0 121 }
michael@0 122 aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
michael@0 123 error = (struct sctp_error_cause *)(aph + 1);
michael@0 124
michael@0 125 aph->correlation_id = id;
michael@0 126 aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND);
michael@0 127 error->code = htons(cause);
michael@0 128 error->length = tlv_length + sizeof(struct sctp_error_cause);
michael@0 129 aph->ph.param_length = error->length +
michael@0 130 sizeof(struct sctp_asconf_paramhdr);
michael@0 131
michael@0 132 if (aph->ph.param_length > MLEN) {
michael@0 133 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 134 "asconf_error_response: tlv_length (%xh) too big\n",
michael@0 135 tlv_length);
michael@0 136 sctp_m_freem(m_reply); /* discard */
michael@0 137 return (NULL);
michael@0 138 }
michael@0 139 if (error_tlv != NULL) {
michael@0 140 tlv = (uint8_t *) (error + 1);
michael@0 141 memcpy(tlv, error_tlv, tlv_length);
michael@0 142 }
michael@0 143 SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
michael@0 144 error->length = htons(error->length);
michael@0 145 aph->ph.param_length = htons(aph->ph.param_length);
michael@0 146
michael@0 147 return (m_reply);
michael@0 148 }
michael@0 149
michael@0 150 static struct mbuf *
michael@0 151 sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *aph,
michael@0 152 struct sctp_tcb *stcb, int send_hb, int response_required)
michael@0 153 {
michael@0 154 struct sctp_nets *net;
michael@0 155 struct mbuf *m_reply = NULL;
michael@0 156 struct sockaddr_storage sa_store;
michael@0 157 struct sctp_paramhdr *ph;
michael@0 158 uint16_t param_type, aparam_length;
michael@0 159 #if defined(INET) || defined(INET6)
michael@0 160 uint16_t param_length;
michael@0 161 #endif
michael@0 162 struct sockaddr *sa;
michael@0 163 int zero_address = 0;
michael@0 164 int bad_address = 0;
michael@0 165 #ifdef INET
michael@0 166 struct sockaddr_in *sin;
michael@0 167 struct sctp_ipv4addr_param *v4addr;
michael@0 168 #endif
michael@0 169 #ifdef INET6
michael@0 170 struct sockaddr_in6 *sin6;
michael@0 171 struct sctp_ipv6addr_param *v6addr;
michael@0 172 #endif
michael@0 173
michael@0 174 aparam_length = ntohs(aph->ph.param_length);
michael@0 175 ph = (struct sctp_paramhdr *)(aph + 1);
michael@0 176 param_type = ntohs(ph->param_type);
michael@0 177 #if defined(INET) || defined(INET6)
michael@0 178 param_length = ntohs(ph->param_length);
michael@0 179 #endif
michael@0 180 sa = (struct sockaddr *)&sa_store;
michael@0 181 switch (param_type) {
michael@0 182 #ifdef INET
michael@0 183 case SCTP_IPV4_ADDRESS:
michael@0 184 if (param_length != sizeof(struct sctp_ipv4addr_param)) {
michael@0 185 /* invalid param size */
michael@0 186 return (NULL);
michael@0 187 }
michael@0 188 v4addr = (struct sctp_ipv4addr_param *)ph;
michael@0 189 sin = (struct sockaddr_in *)&sa_store;
michael@0 190 bzero(sin, sizeof(*sin));
michael@0 191 sin->sin_family = AF_INET;
michael@0 192 #ifdef HAVE_SIN_LEN
michael@0 193 sin->sin_len = sizeof(struct sockaddr_in);
michael@0 194 #endif
michael@0 195 sin->sin_port = stcb->rport;
michael@0 196 sin->sin_addr.s_addr = v4addr->addr;
michael@0 197 if ((sin->sin_addr.s_addr == INADDR_BROADCAST) ||
michael@0 198 IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
michael@0 199 bad_address = 1;
michael@0 200 }
michael@0 201 if (sin->sin_addr.s_addr == INADDR_ANY)
michael@0 202 zero_address = 1;
michael@0 203 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding ");
michael@0 204 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
michael@0 205 break;
michael@0 206 #endif
michael@0 207 #ifdef INET6
michael@0 208 case SCTP_IPV6_ADDRESS:
michael@0 209 if (param_length != sizeof(struct sctp_ipv6addr_param)) {
michael@0 210 /* invalid param size */
michael@0 211 return (NULL);
michael@0 212 }
michael@0 213 v6addr = (struct sctp_ipv6addr_param *)ph;
michael@0 214 sin6 = (struct sockaddr_in6 *)&sa_store;
michael@0 215 bzero(sin6, sizeof(*sin6));
michael@0 216 sin6->sin6_family = AF_INET6;
michael@0 217 #ifdef HAVE_SIN6_LEN
michael@0 218 sin6->sin6_len = sizeof(struct sockaddr_in6);
michael@0 219 #endif
michael@0 220 sin6->sin6_port = stcb->rport;
michael@0 221 memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
michael@0 222 sizeof(struct in6_addr));
michael@0 223 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
michael@0 224 bad_address = 1;
michael@0 225 }
michael@0 226 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
michael@0 227 zero_address = 1;
michael@0 228 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding ");
michael@0 229 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
michael@0 230 break;
michael@0 231 #endif
michael@0 232 default:
michael@0 233 m_reply = sctp_asconf_error_response(aph->correlation_id,
michael@0 234 SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph,
michael@0 235 aparam_length);
michael@0 236 return (m_reply);
michael@0 237 } /* end switch */
michael@0 238
michael@0 239 /* if 0.0.0.0/::0, add the source address instead */
michael@0 240 if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
michael@0 241 sa = src;
michael@0 242 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 243 "process_asconf_add_ip: using source addr ");
michael@0 244 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
michael@0 245 }
michael@0 246 /* add the address */
michael@0 247 if (bad_address) {
michael@0 248 m_reply = sctp_asconf_error_response(aph->correlation_id,
michael@0 249 SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph,
michael@0 250 aparam_length);
michael@0 251 } else if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE,
michael@0 252 SCTP_ADDR_DYNAMIC_ADDED) != 0) {
michael@0 253 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 254 "process_asconf_add_ip: error adding address\n");
michael@0 255 m_reply = sctp_asconf_error_response(aph->correlation_id,
michael@0 256 SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *) aph,
michael@0 257 aparam_length);
michael@0 258 } else {
michael@0 259 /* notify upper layer */
michael@0 260 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
michael@0 261 if (response_required) {
michael@0 262 m_reply =
michael@0 263 sctp_asconf_success_response(aph->correlation_id);
michael@0 264 }
michael@0 265 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
michael@0 266 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
michael@0 267 stcb, net);
michael@0 268 if (send_hb) {
michael@0 269 sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
michael@0 270 }
michael@0 271 }
michael@0 272 return (m_reply);
michael@0 273 }
michael@0 274
michael@0 275 static int
michael@0 276 sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
michael@0 277 {
michael@0 278 struct sctp_nets *src_net, *net;
michael@0 279
michael@0 280 /* make sure the source address exists as a destination net */
michael@0 281 src_net = sctp_findnet(stcb, src);
michael@0 282 if (src_net == NULL) {
michael@0 283 /* not found */
michael@0 284 return (-1);
michael@0 285 }
michael@0 286
michael@0 287 /* delete all destination addresses except the source */
michael@0 288 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
michael@0 289 if (net != src_net) {
michael@0 290 /* delete this address */
michael@0 291 sctp_remove_net(stcb, net);
michael@0 292 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 293 "asconf_del_remote_addrs_except: deleting ");
michael@0 294 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1,
michael@0 295 (struct sockaddr *)&net->ro._l_addr);
michael@0 296 /* notify upper layer */
michael@0 297 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
michael@0 298 (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED);
michael@0 299 }
michael@0 300 }
michael@0 301 return (0);
michael@0 302 }
michael@0 303
michael@0 304 static struct mbuf *
michael@0 305 sctp_process_asconf_delete_ip(struct sockaddr *src,
michael@0 306 struct sctp_asconf_paramhdr *aph,
michael@0 307 struct sctp_tcb *stcb, int response_required)
michael@0 308 {
michael@0 309 struct mbuf *m_reply = NULL;
michael@0 310 struct sockaddr_storage sa_store;
michael@0 311 struct sctp_paramhdr *ph;
michael@0 312 uint16_t param_type, aparam_length;
michael@0 313 #if defined(INET) || defined(INET6)
michael@0 314 uint16_t param_length;
michael@0 315 #endif
michael@0 316 struct sockaddr *sa;
michael@0 317 int zero_address = 0;
michael@0 318 int result;
michael@0 319 #ifdef INET
michael@0 320 struct sockaddr_in *sin;
michael@0 321 struct sctp_ipv4addr_param *v4addr;
michael@0 322 #endif
michael@0 323 #ifdef INET6
michael@0 324 struct sockaddr_in6 *sin6;
michael@0 325 struct sctp_ipv6addr_param *v6addr;
michael@0 326 #endif
michael@0 327
michael@0 328 aparam_length = ntohs(aph->ph.param_length);
michael@0 329 ph = (struct sctp_paramhdr *)(aph + 1);
michael@0 330 param_type = ntohs(ph->param_type);
michael@0 331 #if defined(INET) || defined(INET6)
michael@0 332 param_length = ntohs(ph->param_length);
michael@0 333 #endif
michael@0 334 sa = (struct sockaddr *)&sa_store;
michael@0 335 switch (param_type) {
michael@0 336 #ifdef INET
michael@0 337 case SCTP_IPV4_ADDRESS:
michael@0 338 if (param_length != sizeof(struct sctp_ipv4addr_param)) {
michael@0 339 /* invalid param size */
michael@0 340 return (NULL);
michael@0 341 }
michael@0 342 v4addr = (struct sctp_ipv4addr_param *)ph;
michael@0 343 sin = (struct sockaddr_in *)&sa_store;
michael@0 344 bzero(sin, sizeof(*sin));
michael@0 345 sin->sin_family = AF_INET;
michael@0 346 #ifdef HAVE_SIN_LEN
michael@0 347 sin->sin_len = sizeof(struct sockaddr_in);
michael@0 348 #endif
michael@0 349 sin->sin_port = stcb->rport;
michael@0 350 sin->sin_addr.s_addr = v4addr->addr;
michael@0 351 if (sin->sin_addr.s_addr == INADDR_ANY)
michael@0 352 zero_address = 1;
michael@0 353 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 354 "process_asconf_delete_ip: deleting ");
michael@0 355 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
michael@0 356 break;
michael@0 357 #endif
michael@0 358 #ifdef INET6
michael@0 359 case SCTP_IPV6_ADDRESS:
michael@0 360 if (param_length != sizeof(struct sctp_ipv6addr_param)) {
michael@0 361 /* invalid param size */
michael@0 362 return (NULL);
michael@0 363 }
michael@0 364 v6addr = (struct sctp_ipv6addr_param *)ph;
michael@0 365 sin6 = (struct sockaddr_in6 *)&sa_store;
michael@0 366 bzero(sin6, sizeof(*sin6));
michael@0 367 sin6->sin6_family = AF_INET6;
michael@0 368 #ifdef HAVE_SIN6_LEN
michael@0 369 sin6->sin6_len = sizeof(struct sockaddr_in6);
michael@0 370 #endif
michael@0 371 sin6->sin6_port = stcb->rport;
michael@0 372 memcpy(&sin6->sin6_addr, v6addr->addr,
michael@0 373 sizeof(struct in6_addr));
michael@0 374 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
michael@0 375 zero_address = 1;
michael@0 376 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 377 "process_asconf_delete_ip: deleting ");
michael@0 378 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
michael@0 379 break;
michael@0 380 #endif
michael@0 381 default:
michael@0 382 m_reply = sctp_asconf_error_response(aph->correlation_id,
michael@0 383 SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
michael@0 384 aparam_length);
michael@0 385 return (m_reply);
michael@0 386 }
michael@0 387
michael@0 388 /* make sure the source address is not being deleted */
michael@0 389 if (sctp_cmpaddr(sa, src)) {
michael@0 390 /* trying to delete the source address! */
michael@0 391 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete source addr\n");
michael@0 392 m_reply = sctp_asconf_error_response(aph->correlation_id,
michael@0 393 SCTP_CAUSE_DELETING_SRC_ADDR, (uint8_t *) aph,
michael@0 394 aparam_length);
michael@0 395 return (m_reply);
michael@0 396 }
michael@0 397
michael@0 398 /* if deleting 0.0.0.0/::0, delete all addresses except src addr */
michael@0 399 if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
michael@0 400 result = sctp_asconf_del_remote_addrs_except(stcb, src);
michael@0 401
michael@0 402 if (result) {
michael@0 403 /* src address did not exist? */
michael@0 404 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: src addr does not exist?\n");
michael@0 405 /* what error to reply with?? */
michael@0 406 m_reply =
michael@0 407 sctp_asconf_error_response(aph->correlation_id,
michael@0 408 SCTP_CAUSE_REQUEST_REFUSED, (uint8_t *) aph,
michael@0 409 aparam_length);
michael@0 410 } else if (response_required) {
michael@0 411 m_reply =
michael@0 412 sctp_asconf_success_response(aph->correlation_id);
michael@0 413 }
michael@0 414 return (m_reply);
michael@0 415 }
michael@0 416
michael@0 417 /* delete the address */
michael@0 418 result = sctp_del_remote_addr(stcb, sa);
michael@0 419 /*
michael@0 420 * note if result == -2, the address doesn't exist in the asoc but
michael@0 421 * since it's being deleted anyways, we just ack the delete -- but
michael@0 422 * this probably means something has already gone awry
michael@0 423 */
michael@0 424 if (result == -1) {
michael@0 425 /* only one address in the asoc */
michael@0 426 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete last IP addr!\n");
michael@0 427 m_reply = sctp_asconf_error_response(aph->correlation_id,
michael@0 428 SCTP_CAUSE_DELETING_LAST_ADDR, (uint8_t *) aph,
michael@0 429 aparam_length);
michael@0 430 } else {
michael@0 431 if (response_required) {
michael@0 432 m_reply = sctp_asconf_success_response(aph->correlation_id);
michael@0 433 }
michael@0 434 /* notify upper layer */
michael@0 435 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
michael@0 436 }
michael@0 437 return (m_reply);
michael@0 438 }
michael@0 439
michael@0 440 static struct mbuf *
michael@0 441 sctp_process_asconf_set_primary(struct sockaddr *src,
michael@0 442 struct sctp_asconf_paramhdr *aph,
michael@0 443 struct sctp_tcb *stcb, int response_required)
michael@0 444 {
michael@0 445 struct mbuf *m_reply = NULL;
michael@0 446 struct sockaddr_storage sa_store;
michael@0 447 struct sctp_paramhdr *ph;
michael@0 448 uint16_t param_type, aparam_length;
michael@0 449 #if defined(INET) || defined(INET6)
michael@0 450 uint16_t param_length;
michael@0 451 #endif
michael@0 452 struct sockaddr *sa;
michael@0 453 int zero_address = 0;
michael@0 454 #ifdef INET
michael@0 455 struct sockaddr_in *sin;
michael@0 456 struct sctp_ipv4addr_param *v4addr;
michael@0 457 #endif
michael@0 458 #ifdef INET6
michael@0 459 struct sockaddr_in6 *sin6;
michael@0 460 struct sctp_ipv6addr_param *v6addr;
michael@0 461 #endif
michael@0 462
michael@0 463 aparam_length = ntohs(aph->ph.param_length);
michael@0 464 ph = (struct sctp_paramhdr *)(aph + 1);
michael@0 465 param_type = ntohs(ph->param_type);
michael@0 466 #if defined(INET) || defined(INET6)
michael@0 467 param_length = ntohs(ph->param_length);
michael@0 468 #endif
michael@0 469 sa = (struct sockaddr *)&sa_store;
michael@0 470 switch (param_type) {
michael@0 471 #ifdef INET
michael@0 472 case SCTP_IPV4_ADDRESS:
michael@0 473 if (param_length != sizeof(struct sctp_ipv4addr_param)) {
michael@0 474 /* invalid param size */
michael@0 475 return (NULL);
michael@0 476 }
michael@0 477 v4addr = (struct sctp_ipv4addr_param *)ph;
michael@0 478 sin = (struct sockaddr_in *)&sa_store;
michael@0 479 bzero(sin, sizeof(*sin));
michael@0 480 sin->sin_family = AF_INET;
michael@0 481 #ifdef HAVE_SIN_LEN
michael@0 482 sin->sin_len = sizeof(struct sockaddr_in);
michael@0 483 #endif
michael@0 484 sin->sin_addr.s_addr = v4addr->addr;
michael@0 485 if (sin->sin_addr.s_addr == INADDR_ANY)
michael@0 486 zero_address = 1;
michael@0 487 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
michael@0 488 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
michael@0 489 break;
michael@0 490 #endif
michael@0 491 #ifdef INET6
michael@0 492 case SCTP_IPV6_ADDRESS:
michael@0 493 if (param_length != sizeof(struct sctp_ipv6addr_param)) {
michael@0 494 /* invalid param size */
michael@0 495 return (NULL);
michael@0 496 }
michael@0 497 v6addr = (struct sctp_ipv6addr_param *)ph;
michael@0 498 sin6 = (struct sockaddr_in6 *)&sa_store;
michael@0 499 bzero(sin6, sizeof(*sin6));
michael@0 500 sin6->sin6_family = AF_INET6;
michael@0 501 #ifdef HAVE_SIN6_LEN
michael@0 502 sin6->sin6_len = sizeof(struct sockaddr_in6);
michael@0 503 #endif
michael@0 504 memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
michael@0 505 sizeof(struct in6_addr));
michael@0 506 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
michael@0 507 zero_address = 1;
michael@0 508 SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
michael@0 509 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
michael@0 510 break;
michael@0 511 #endif
michael@0 512 default:
michael@0 513 m_reply = sctp_asconf_error_response(aph->correlation_id,
michael@0 514 SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
michael@0 515 aparam_length);
michael@0 516 return (m_reply);
michael@0 517 }
michael@0 518
michael@0 519 /* if 0.0.0.0/::0, use the source address instead */
michael@0 520 if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
michael@0 521 sa = src;
michael@0 522 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 523 "process_asconf_set_primary: using source addr ");
michael@0 524 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
michael@0 525 }
michael@0 526 /* set the primary address */
michael@0 527 if (sctp_set_primary_addr(stcb, sa, NULL) == 0) {
michael@0 528 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 529 "process_asconf_set_primary: primary address set\n");
michael@0 530 /* notify upper layer */
michael@0 531 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
michael@0 532 if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) &&
michael@0 533 (!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) &&
michael@0 534 (stcb->asoc.alternate)) {
michael@0 535 sctp_free_remote_addr(stcb->asoc.alternate);
michael@0 536 stcb->asoc.alternate = NULL;
michael@0 537 }
michael@0 538 if (response_required) {
michael@0 539 m_reply = sctp_asconf_success_response(aph->correlation_id);
michael@0 540 }
michael@0 541 /* Mobility adaptation.
michael@0 542 Ideally, when the reception of SET PRIMARY with DELETE IP
michael@0 543 ADDRESS of the previous primary destination, unacknowledged
michael@0 544 DATA are retransmitted immediately to the new primary
michael@0 545 destination for seamless handover.
michael@0 546 If the destination is UNCONFIRMED and marked to REQ_PRIM,
michael@0 547 The retransmission occur when reception of the
michael@0 548 HEARTBEAT-ACK. (See sctp_handle_heartbeat_ack in
michael@0 549 sctp_input.c)
michael@0 550 Also, when change of the primary destination, it is better
michael@0 551 that all subsequent new DATA containing already queued DATA
michael@0 552 are transmitted to the new primary destination. (by micchie)
michael@0 553 */
michael@0 554 if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 555 SCTP_MOBILITY_BASE) ||
michael@0 556 sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 557 SCTP_MOBILITY_FASTHANDOFF)) &&
michael@0 558 sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 559 SCTP_MOBILITY_PRIM_DELETED) &&
michael@0 560 (stcb->asoc.primary_destination->dest_state &
michael@0 561 SCTP_ADDR_UNCONFIRMED) == 0) {
michael@0 562
michael@0 563 sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER+SCTP_LOC_7);
michael@0 564 if (sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 565 SCTP_MOBILITY_FASTHANDOFF)) {
michael@0 566 sctp_assoc_immediate_retrans(stcb,
michael@0 567 stcb->asoc.primary_destination);
michael@0 568 }
michael@0 569 if (sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 570 SCTP_MOBILITY_BASE)) {
michael@0 571 sctp_move_chunks_from_net(stcb,
michael@0 572 stcb->asoc.deleted_primary);
michael@0 573 }
michael@0 574 sctp_delete_prim_timer(stcb->sctp_ep, stcb,
michael@0 575 stcb->asoc.deleted_primary);
michael@0 576 }
michael@0 577 } else {
michael@0 578 /* couldn't set the requested primary address! */
michael@0 579 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 580 "process_asconf_set_primary: set primary failed!\n");
michael@0 581 /* must have been an invalid address, so report */
michael@0 582 m_reply = sctp_asconf_error_response(aph->correlation_id,
michael@0 583 SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
michael@0 584 aparam_length);
michael@0 585 }
michael@0 586
michael@0 587 return (m_reply);
michael@0 588 }
michael@0 589
michael@0 590 /*
michael@0 591 * handles an ASCONF chunk.
michael@0 592 * if all parameters are processed ok, send a plain (empty) ASCONF-ACK
michael@0 593 */
michael@0 594 void
michael@0 595 sctp_handle_asconf(struct mbuf *m, unsigned int offset,
michael@0 596 struct sockaddr *src,
michael@0 597 struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb,
michael@0 598 int first)
michael@0 599 {
michael@0 600 struct sctp_association *asoc;
michael@0 601 uint32_t serial_num;
michael@0 602 struct mbuf *n, *m_ack, *m_result, *m_tail;
michael@0 603 struct sctp_asconf_ack_chunk *ack_cp;
michael@0 604 struct sctp_asconf_paramhdr *aph, *ack_aph;
michael@0 605 struct sctp_ipv6addr_param *p_addr;
michael@0 606 unsigned int asconf_limit, cnt;
michael@0 607 int error = 0; /* did an error occur? */
michael@0 608
michael@0 609 /* asconf param buffer */
michael@0 610 uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
michael@0 611 struct sctp_asconf_ack *ack, *ack_next;
michael@0 612
michael@0 613 /* verify minimum length */
michael@0 614 if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) {
michael@0 615 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 616 "handle_asconf: chunk too small = %xh\n",
michael@0 617 ntohs(cp->ch.chunk_length));
michael@0 618 return;
michael@0 619 }
michael@0 620 asoc = &stcb->asoc;
michael@0 621 serial_num = ntohl(cp->serial_number);
michael@0 622
michael@0 623 if (SCTP_TSN_GE(asoc->asconf_seq_in, serial_num)) {
michael@0 624 /* got a duplicate ASCONF */
michael@0 625 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 626 "handle_asconf: got duplicate serial number = %xh\n",
michael@0 627 serial_num);
michael@0 628 return;
michael@0 629 } else if (serial_num != (asoc->asconf_seq_in + 1)) {
michael@0 630 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: incorrect serial number = %xh (expected next = %xh)\n",
michael@0 631 serial_num, asoc->asconf_seq_in + 1);
michael@0 632 return;
michael@0 633 }
michael@0 634
michael@0 635 /* it's the expected "next" sequence number, so process it */
michael@0 636 asoc->asconf_seq_in = serial_num; /* update sequence */
michael@0 637 /* get length of all the param's in the ASCONF */
michael@0 638 asconf_limit = offset + ntohs(cp->ch.chunk_length);
michael@0 639 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 640 "handle_asconf: asconf_limit=%u, sequence=%xh\n",
michael@0 641 asconf_limit, serial_num);
michael@0 642
michael@0 643 if (first) {
michael@0 644 /* delete old cache */
michael@0 645 SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: Now processing first ASCONF. Try to delete old cache\n");
michael@0 646
michael@0 647 TAILQ_FOREACH_SAFE(ack, &asoc->asconf_ack_sent, next, ack_next) {
michael@0 648 if (ack->serial_number == serial_num)
michael@0 649 break;
michael@0 650 SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: delete old(%u) < first(%u)\n",
michael@0 651 ack->serial_number, serial_num);
michael@0 652 TAILQ_REMOVE(&asoc->asconf_ack_sent, ack, next);
michael@0 653 if (ack->data != NULL) {
michael@0 654 sctp_m_freem(ack->data);
michael@0 655 }
michael@0 656 SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), ack);
michael@0 657 }
michael@0 658 }
michael@0 659
michael@0 660 m_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_ack_chunk), 0,
michael@0 661 M_NOWAIT, 1, MT_DATA);
michael@0 662 if (m_ack == NULL) {
michael@0 663 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 664 "handle_asconf: couldn't get mbuf!\n");
michael@0 665 return;
michael@0 666 }
michael@0 667 m_tail = m_ack; /* current reply chain's tail */
michael@0 668
michael@0 669 /* fill in ASCONF-ACK header */
michael@0 670 ack_cp = mtod(m_ack, struct sctp_asconf_ack_chunk *);
michael@0 671 ack_cp->ch.chunk_type = SCTP_ASCONF_ACK;
michael@0 672 ack_cp->ch.chunk_flags = 0;
michael@0 673 ack_cp->serial_number = htonl(serial_num);
michael@0 674 /* set initial lengths (eg. just an ASCONF-ACK), ntohx at the end! */
michael@0 675 SCTP_BUF_LEN(m_ack) = sizeof(struct sctp_asconf_ack_chunk);
michael@0 676 ack_cp->ch.chunk_length = sizeof(struct sctp_asconf_ack_chunk);
michael@0 677
michael@0 678 /* skip the lookup address parameter */
michael@0 679 offset += sizeof(struct sctp_asconf_chunk);
michael@0 680 p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), (uint8_t *)&aparam_buf);
michael@0 681 if (p_addr == NULL) {
michael@0 682 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 683 "handle_asconf: couldn't get lookup addr!\n");
michael@0 684 /* respond with a missing/invalid mandatory parameter error */
michael@0 685 return;
michael@0 686 }
michael@0 687 /* param_length is already validated in process_control... */
michael@0 688 offset += ntohs(p_addr->ph.param_length); /* skip lookup addr */
michael@0 689
michael@0 690 /* get pointer to first asconf param in ASCONF-ACK */
michael@0 691 ack_aph = (struct sctp_asconf_paramhdr *)(mtod(m_ack, caddr_t) + sizeof(struct sctp_asconf_ack_chunk));
michael@0 692 if (ack_aph == NULL) {
michael@0 693 SCTPDBG(SCTP_DEBUG_ASCONF1, "Gak in asconf2\n");
michael@0 694 return;
michael@0 695 }
michael@0 696 /* get pointer to first asconf param in ASCONF */
michael@0 697 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf);
michael@0 698 if (aph == NULL) {
michael@0 699 SCTPDBG(SCTP_DEBUG_ASCONF1, "Empty ASCONF received?\n");
michael@0 700 goto send_reply;
michael@0 701 }
michael@0 702 /* process through all parameters */
michael@0 703 cnt = 0;
michael@0 704 while (aph != NULL) {
michael@0 705 unsigned int param_length, param_type;
michael@0 706
michael@0 707 param_type = ntohs(aph->ph.param_type);
michael@0 708 param_length = ntohs(aph->ph.param_length);
michael@0 709 if (offset + param_length > asconf_limit) {
michael@0 710 /* parameter goes beyond end of chunk! */
michael@0 711 sctp_m_freem(m_ack);
michael@0 712 return;
michael@0 713 }
michael@0 714 m_result = NULL;
michael@0 715
michael@0 716 if (param_length > sizeof(aparam_buf)) {
michael@0 717 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) larger than buffer size!\n", param_length);
michael@0 718 sctp_m_freem(m_ack);
michael@0 719 return;
michael@0 720 }
michael@0 721 if (param_length <= sizeof(struct sctp_paramhdr)) {
michael@0 722 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) too short\n", param_length);
michael@0 723 sctp_m_freem(m_ack);
michael@0 724 }
michael@0 725 /* get the entire parameter */
michael@0 726 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
michael@0 727 if (aph == NULL) {
michael@0 728 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: couldn't get entire param\n");
michael@0 729 sctp_m_freem(m_ack);
michael@0 730 return;
michael@0 731 }
michael@0 732 switch (param_type) {
michael@0 733 case SCTP_ADD_IP_ADDRESS:
michael@0 734 asoc->peer_supports_asconf = 1;
michael@0 735 m_result = sctp_process_asconf_add_ip(src, aph, stcb,
michael@0 736 (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error);
michael@0 737 cnt++;
michael@0 738 break;
michael@0 739 case SCTP_DEL_IP_ADDRESS:
michael@0 740 asoc->peer_supports_asconf = 1;
michael@0 741 m_result = sctp_process_asconf_delete_ip(src, aph, stcb,
michael@0 742 error);
michael@0 743 break;
michael@0 744 case SCTP_ERROR_CAUSE_IND:
michael@0 745 /* not valid in an ASCONF chunk */
michael@0 746 break;
michael@0 747 case SCTP_SET_PRIM_ADDR:
michael@0 748 asoc->peer_supports_asconf = 1;
michael@0 749 m_result = sctp_process_asconf_set_primary(src, aph,
michael@0 750 stcb, error);
michael@0 751 break;
michael@0 752 case SCTP_NAT_VTAGS:
michael@0 753 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: sees a NAT VTAG state parameter\n");
michael@0 754 break;
michael@0 755 case SCTP_SUCCESS_REPORT:
michael@0 756 /* not valid in an ASCONF chunk */
michael@0 757 break;
michael@0 758 case SCTP_ULP_ADAPTATION:
michael@0 759 /* FIX */
michael@0 760 break;
michael@0 761 default:
michael@0 762 if ((param_type & 0x8000) == 0) {
michael@0 763 /* Been told to STOP at this param */
michael@0 764 asconf_limit = offset;
michael@0 765 /*
michael@0 766 * FIX FIX - We need to call
michael@0 767 * sctp_arethere_unrecognized_parameters()
michael@0 768 * to get a operr and send it for any
michael@0 769 * param's with the 0x4000 bit set OR do it
michael@0 770 * here ourselves... note we still must STOP
michael@0 771 * if the 0x8000 bit is clear.
michael@0 772 */
michael@0 773 }
michael@0 774 /* unknown/invalid param type */
michael@0 775 break;
michael@0 776 } /* switch */
michael@0 777
michael@0 778 /* add any (error) result to the reply mbuf chain */
michael@0 779 if (m_result != NULL) {
michael@0 780 SCTP_BUF_NEXT(m_tail) = m_result;
michael@0 781 m_tail = m_result;
michael@0 782 /* update lengths, make sure it's aligned too */
michael@0 783 SCTP_BUF_LEN(m_result) = SCTP_SIZE32(SCTP_BUF_LEN(m_result));
michael@0 784 ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result);
michael@0 785 /* set flag to force success reports */
michael@0 786 error = 1;
michael@0 787 }
michael@0 788 offset += SCTP_SIZE32(param_length);
michael@0 789 /* update remaining ASCONF message length to process */
michael@0 790 if (offset >= asconf_limit) {
michael@0 791 /* no more data in the mbuf chain */
michael@0 792 break;
michael@0 793 }
michael@0 794 /* get pointer to next asconf param */
michael@0 795 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
michael@0 796 sizeof(struct sctp_asconf_paramhdr),
michael@0 797 (uint8_t *)&aparam_buf);
michael@0 798 if (aph == NULL) {
michael@0 799 /* can't get an asconf paramhdr */
michael@0 800 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: can't get asconf param hdr!\n");
michael@0 801 /* FIX ME - add error here... */
michael@0 802 }
michael@0 803 }
michael@0 804
michael@0 805 send_reply:
michael@0 806 ack_cp->ch.chunk_length = htons(ack_cp->ch.chunk_length);
michael@0 807 /* save the ASCONF-ACK reply */
michael@0 808 ack = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asconf_ack),
michael@0 809 struct sctp_asconf_ack);
michael@0 810 if (ack == NULL) {
michael@0 811 sctp_m_freem(m_ack);
michael@0 812 return;
michael@0 813 }
michael@0 814 ack->serial_number = serial_num;
michael@0 815 ack->last_sent_to = NULL;
michael@0 816 ack->data = m_ack;
michael@0 817 ack->len = 0;
michael@0 818 for (n = m_ack; n != NULL; n = SCTP_BUF_NEXT(n)) {
michael@0 819 ack->len += SCTP_BUF_LEN(n);
michael@0 820 }
michael@0 821 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_ack_sent, ack, next);
michael@0 822
michael@0 823 /* see if last_control_chunk_from is set properly (use IP src addr) */
michael@0 824 if (stcb->asoc.last_control_chunk_from == NULL) {
michael@0 825 /*
michael@0 826 * this could happen if the source address was just newly
michael@0 827 * added
michael@0 828 */
michael@0 829 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: looking up net for IP source address\n");
michael@0 830 SCTPDBG(SCTP_DEBUG_ASCONF1, "Looking for IP source: ");
michael@0 831 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
michael@0 832 /* look up the from address */
michael@0 833 stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, src);
michael@0 834 #ifdef SCTP_DEBUG
michael@0 835 if (stcb->asoc.last_control_chunk_from == NULL) {
michael@0 836 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: IP source address not found?!\n");
michael@0 837 }
michael@0 838 #endif
michael@0 839 }
michael@0 840 }
michael@0 841
michael@0 842 /*
michael@0 843 * does the address match? returns 0 if not, 1 if so
michael@0 844 */
michael@0 845 static uint32_t
michael@0 846 sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa)
michael@0 847 {
michael@0 848 switch (sa->sa_family) {
michael@0 849 #ifdef INET6
michael@0 850 case AF_INET6:
michael@0 851 {
michael@0 852 /* XXX scopeid */
michael@0 853 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
michael@0 854
michael@0 855 if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) &&
michael@0 856 (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr,
michael@0 857 sizeof(struct in6_addr)) == 0)) {
michael@0 858 return (1);
michael@0 859 }
michael@0 860 break;
michael@0 861 }
michael@0 862 #endif
michael@0 863 #ifdef INET
michael@0 864 case AF_INET:
michael@0 865 {
michael@0 866 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
michael@0 867
michael@0 868 if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) &&
michael@0 869 (memcmp(&aa->ap.addrp.addr, &sin->sin_addr,
michael@0 870 sizeof(struct in_addr)) == 0)) {
michael@0 871 return (1);
michael@0 872 }
michael@0 873 break;
michael@0 874 }
michael@0 875 #endif
michael@0 876 default:
michael@0 877 break;
michael@0 878 }
michael@0 879 return (0);
michael@0 880 }
michael@0 881
michael@0 882 /*
michael@0 883 * does the address match? returns 0 if not, 1 if so
michael@0 884 */
michael@0 885 static uint32_t
michael@0 886 sctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa)
michael@0 887 {
michael@0 888 #if defined(INET) || defined(INET6)
michael@0 889 uint16_t param_type, param_length;
michael@0 890
michael@0 891 param_type = ntohs(ph->param_type);
michael@0 892 param_length = ntohs(ph->param_length);
michael@0 893 #endif
michael@0 894 switch (sa->sa_family) {
michael@0 895 #ifdef INET6
michael@0 896 case AF_INET6:
michael@0 897 {
michael@0 898 /* XXX scopeid */
michael@0 899 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
michael@0 900 struct sctp_ipv6addr_param *v6addr;
michael@0 901
michael@0 902 v6addr = (struct sctp_ipv6addr_param *)ph;
michael@0 903 if ((param_type == SCTP_IPV6_ADDRESS) &&
michael@0 904 (param_length == sizeof(struct sctp_ipv6addr_param)) &&
michael@0 905 (memcmp(&v6addr->addr, &sin6->sin6_addr,
michael@0 906 sizeof(struct in6_addr)) == 0)) {
michael@0 907 return (1);
michael@0 908 }
michael@0 909 break;
michael@0 910 }
michael@0 911 #endif
michael@0 912 #ifdef INET
michael@0 913 case AF_INET:
michael@0 914 {
michael@0 915 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
michael@0 916 struct sctp_ipv4addr_param *v4addr;
michael@0 917
michael@0 918 v4addr = (struct sctp_ipv4addr_param *)ph;
michael@0 919 if ((param_type == SCTP_IPV4_ADDRESS) &&
michael@0 920 (param_length == sizeof(struct sctp_ipv4addr_param)) &&
michael@0 921 (memcmp(&v4addr->addr, &sin->sin_addr,
michael@0 922 sizeof(struct in_addr)) == 0)) {
michael@0 923 return (1);
michael@0 924 }
michael@0 925 break;
michael@0 926 }
michael@0 927 #endif
michael@0 928 default:
michael@0 929 break;
michael@0 930 }
michael@0 931 return (0);
michael@0 932 }
michael@0 933 /*
michael@0 934 * Cleanup for non-responded/OP ERR'd ASCONF
michael@0 935 */
michael@0 936 void
michael@0 937 sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
michael@0 938 {
michael@0 939 /* mark peer as ASCONF incapable */
michael@0 940 stcb->asoc.peer_supports_asconf = 0;
michael@0 941 /*
michael@0 942 * clear out any existing asconfs going out
michael@0 943 */
michael@0 944 sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
michael@0 945 SCTP_FROM_SCTP_ASCONF+SCTP_LOC_2);
michael@0 946 stcb->asoc.asconf_seq_out_acked = stcb->asoc.asconf_seq_out;
michael@0 947 /* remove the old ASCONF on our outbound queue */
michael@0 948 sctp_toss_old_asconf(stcb);
michael@0 949 }
michael@0 950
michael@0 951 /*
michael@0 952 * cleanup any cached source addresses that may be topologically
michael@0 953 * incorrect after a new address has been added to this interface.
michael@0 954 */
michael@0 955 static void
michael@0 956 sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
michael@0 957 {
michael@0 958 struct sctp_nets *net;
michael@0 959
michael@0 960 /*
michael@0 961 * Ideally, we want to only clear cached routes and source addresses
michael@0 962 * that are topologically incorrect. But since there is no easy way
michael@0 963 * to know whether the newly added address on the ifn would cause a
michael@0 964 * routing change (i.e. a new egress interface would be chosen)
michael@0 965 * without doing a new routing lookup and source address selection,
michael@0 966 * we will (for now) just flush any cached route using a different
michael@0 967 * ifn (and cached source addrs) and let output re-choose them during
michael@0 968 * the next send on that net.
michael@0 969 */
michael@0 970 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
michael@0 971 /*
michael@0 972 * clear any cached route (and cached source address) if the
michael@0 973 * route's interface is NOT the same as the address change.
michael@0 974 * If it's the same interface, just clear the cached source
michael@0 975 * address.
michael@0 976 */
michael@0 977 if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) &&
michael@0 978 ((ifn == NULL) ||
michael@0 979 (SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index))) {
michael@0 980 /* clear any cached route */
michael@0 981 RTFREE(net->ro.ro_rt);
michael@0 982 net->ro.ro_rt = NULL;
michael@0 983 }
michael@0 984 /* clear any cached source address */
michael@0 985 if (net->src_addr_selected) {
michael@0 986 sctp_free_ifa(net->ro._s_addr);
michael@0 987 net->ro._s_addr = NULL;
michael@0 988 net->src_addr_selected = 0;
michael@0 989 }
michael@0 990 }
michael@0 991 }
michael@0 992
michael@0 993
michael@0 994 void
michael@0 995 sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
michael@0 996 {
michael@0 997 int error;
michael@0 998
michael@0 999 if (dstnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
michael@0 1000 return;
michael@0 1001 }
michael@0 1002 if (stcb->asoc.deleted_primary == NULL) {
michael@0 1003 return;
michael@0 1004 }
michael@0 1005
michael@0 1006 if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
michael@0 1007 SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: Deleted primary is ");
michael@0 1008 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa);
michael@0 1009 SCTPDBG(SCTP_DEBUG_ASCONF1, "Current Primary is ");
michael@0 1010 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa);
michael@0 1011 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb,
michael@0 1012 stcb->asoc.deleted_primary,
michael@0 1013 SCTP_FROM_SCTP_TIMER+SCTP_LOC_8);
michael@0 1014 stcb->asoc.num_send_timers_up--;
michael@0 1015 if (stcb->asoc.num_send_timers_up < 0) {
michael@0 1016 stcb->asoc.num_send_timers_up = 0;
michael@0 1017 }
michael@0 1018 SCTP_TCB_LOCK_ASSERT(stcb);
michael@0 1019 error = sctp_t3rxt_timer(stcb->sctp_ep, stcb,
michael@0 1020 stcb->asoc.deleted_primary);
michael@0 1021 if (error) {
michael@0 1022 SCTP_INP_DECR_REF(stcb->sctp_ep);
michael@0 1023 return;
michael@0 1024 }
michael@0 1025 SCTP_TCB_LOCK_ASSERT(stcb);
michael@0 1026 #ifdef SCTP_AUDITING_ENABLED
michael@0 1027 sctp_auditing(4, stcb->sctp_ep, stcb, stcb->asoc.deleted_primary);
michael@0 1028 #endif
michael@0 1029 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
michael@0 1030 if ((stcb->asoc.num_send_timers_up == 0) &&
michael@0 1031 (stcb->asoc.sent_queue_cnt > 0)) {
michael@0 1032 struct sctp_tmit_chunk *chk;
michael@0 1033
michael@0 1034 chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
michael@0 1035 sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
michael@0 1036 stcb, chk->whoTo);
michael@0 1037 }
michael@0 1038 }
michael@0 1039 return;
michael@0 1040 }
michael@0 1041
michael@0 1042 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)
michael@0 1043 static int
michael@0 1044 sctp_asconf_queue_mgmt(struct sctp_tcb *, struct sctp_ifa *, uint16_t);
michael@0 1045
michael@0 1046 void
michael@0 1047 sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net)
michael@0 1048 {
michael@0 1049 struct sctp_tmit_chunk *chk;
michael@0 1050
michael@0 1051 SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans: RTO is %d\n", net->RTO);
michael@0 1052 sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net,
michael@0 1053 SCTP_FROM_SCTP_TIMER+SCTP_LOC_5);
michael@0 1054 stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
michael@0 1055 net->error_count = 0;
michael@0 1056 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
michael@0 1057 if (chk->whoTo == net) {
michael@0 1058 if (chk->sent < SCTP_DATAGRAM_RESEND) {
michael@0 1059 chk->sent = SCTP_DATAGRAM_RESEND;
michael@0 1060 sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
michael@0 1061 sctp_flight_size_decrease(chk);
michael@0 1062 sctp_total_flight_decrease(stcb, chk);
michael@0 1063 net->marked_retrans++;
michael@0 1064 stcb->asoc.marked_retrans++;
michael@0 1065 }
michael@0 1066 }
michael@0 1067 }
michael@0 1068 if (net->marked_retrans) {
michael@0 1069 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
michael@0 1070 }
michael@0 1071 }
michael@0 1072
michael@0 1073 static void
michael@0 1074 sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa)
michael@0 1075 {
michael@0 1076 struct sctp_nets *net;
michael@0 1077 int addrnum, changed;
michael@0 1078
michael@0 1079 /* If number of local valid addresses is 1, the valid address is
michael@0 1080 probably newly added address.
michael@0 1081 Several valid addresses in this association. A source address
michael@0 1082 may not be changed. Additionally, they can be configured on a
michael@0 1083 same interface as "alias" addresses. (by micchie)
michael@0 1084 */
michael@0 1085 addrnum = sctp_local_addr_count(stcb);
michael@0 1086 SCTPDBG(SCTP_DEBUG_ASCONF1, "p_check_react(): %d local addresses\n",
michael@0 1087 addrnum);
michael@0 1088 if (addrnum == 1) {
michael@0 1089 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
michael@0 1090 /* clear any cached route and source address */
michael@0 1091 if (net->ro.ro_rt) {
michael@0 1092 RTFREE(net->ro.ro_rt);
michael@0 1093 net->ro.ro_rt = NULL;
michael@0 1094 }
michael@0 1095 if (net->src_addr_selected) {
michael@0 1096 sctp_free_ifa(net->ro._s_addr);
michael@0 1097 net->ro._s_addr = NULL;
michael@0 1098 net->src_addr_selected = 0;
michael@0 1099 }
michael@0 1100 /* Retransmit unacknowledged DATA chunks immediately */
michael@0 1101 if (sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 1102 SCTP_MOBILITY_FASTHANDOFF)) {
michael@0 1103 sctp_net_immediate_retrans(stcb, net);
michael@0 1104 }
michael@0 1105 /* also, SET PRIMARY is maybe already sent */
michael@0 1106 }
michael@0 1107 return;
michael@0 1108 }
michael@0 1109
michael@0 1110 /* Multiple local addresses exsist in the association. */
michael@0 1111 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
michael@0 1112 /* clear any cached route and source address */
michael@0 1113 if (net->ro.ro_rt) {
michael@0 1114 RTFREE(net->ro.ro_rt);
michael@0 1115 net->ro.ro_rt = NULL;
michael@0 1116 }
michael@0 1117 if (net->src_addr_selected) {
michael@0 1118 sctp_free_ifa(net->ro._s_addr);
michael@0 1119 net->ro._s_addr = NULL;
michael@0 1120 net->src_addr_selected = 0;
michael@0 1121 }
michael@0 1122 /* Check if the nexthop is corresponding to the new address.
michael@0 1123 If the new address is corresponding to the current nexthop,
michael@0 1124 the path will be changed.
michael@0 1125 If the new address is NOT corresponding to the current
michael@0 1126 nexthop, the path will not be changed.
michael@0 1127 */
michael@0 1128 SCTP_RTALLOC((sctp_route_t *)&net->ro,
michael@0 1129 stcb->sctp_ep->def_vrf_id);
michael@0 1130 if (net->ro.ro_rt == NULL)
michael@0 1131 continue;
michael@0 1132
michael@0 1133 changed = 0;
michael@0 1134 switch (net->ro._l_addr.sa.sa_family) {
michael@0 1135 #ifdef INET
michael@0 1136 case AF_INET:
michael@0 1137 if (sctp_v4src_match_nexthop(newifa, (sctp_route_t *)&net->ro)) {
michael@0 1138 changed = 1;
michael@0 1139 }
michael@0 1140 break;
michael@0 1141 #endif
michael@0 1142 #ifdef INET6
michael@0 1143 case AF_INET6:
michael@0 1144 if (sctp_v6src_match_nexthop(
michael@0 1145 &newifa->address.sin6, (sctp_route_t *)&net->ro)) {
michael@0 1146 changed = 1;
michael@0 1147 }
michael@0 1148 break;
michael@0 1149 #endif
michael@0 1150 default:
michael@0 1151 break;
michael@0 1152 }
michael@0 1153 /* if the newly added address does not relate routing
michael@0 1154 information, we skip.
michael@0 1155 */
michael@0 1156 if (changed == 0)
michael@0 1157 continue;
michael@0 1158 /* Retransmit unacknowledged DATA chunks immediately */
michael@0 1159 if (sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 1160 SCTP_MOBILITY_FASTHANDOFF)) {
michael@0 1161 sctp_net_immediate_retrans(stcb, net);
michael@0 1162 }
michael@0 1163 /* Send SET PRIMARY for this new address */
michael@0 1164 if (net == stcb->asoc.primary_destination) {
michael@0 1165 (void)sctp_asconf_queue_mgmt(stcb, newifa,
michael@0 1166 SCTP_SET_PRIM_ADDR);
michael@0 1167 }
michael@0 1168 }
michael@0 1169 }
michael@0 1170 #endif /* __FreeBSD__ __APPLE__ __Userspace__ */
michael@0 1171
michael@0 1172 /*
michael@0 1173 * process an ADD/DELETE IP ack from peer.
michael@0 1174 * addr: corresponding sctp_ifa to the address being added/deleted.
michael@0 1175 * type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS.
michael@0 1176 * flag: 1=success, 0=failure.
michael@0 1177 */
michael@0 1178 static void
michael@0 1179 sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, uint32_t flag)
michael@0 1180 {
michael@0 1181 /*
michael@0 1182 * do the necessary asoc list work- if we get a failure indication,
michael@0 1183 * leave the address on the assoc's restricted list. If we get a
michael@0 1184 * success indication, remove the address from the restricted list.
michael@0 1185 */
michael@0 1186 /*
michael@0 1187 * Note: this will only occur for ADD_IP_ADDRESS, since
michael@0 1188 * DEL_IP_ADDRESS is never actually added to the list...
michael@0 1189 */
michael@0 1190 if (flag) {
michael@0 1191 /* success case, so remove from the restricted list */
michael@0 1192 sctp_del_local_addr_restricted(stcb, addr);
michael@0 1193
michael@0 1194 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)
michael@0 1195 if (sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 1196 SCTP_MOBILITY_BASE) ||
michael@0 1197 sctp_is_mobility_feature_on(stcb->sctp_ep,
michael@0 1198 SCTP_MOBILITY_FASTHANDOFF)) {
michael@0 1199 sctp_path_check_and_react(stcb, addr);
michael@0 1200 return;
michael@0 1201 }
michael@0 1202 #endif /* __FreeBSD__ __APPLE__ __Userspace__ */
michael@0 1203 /* clear any cached/topologically incorrect source addresses */
michael@0 1204 sctp_asconf_nets_cleanup(stcb, addr->ifn_p);
michael@0 1205 }
michael@0 1206 /* else, leave it on the list */
michael@0 1207 }
michael@0 1208
michael@0 1209 /*
michael@0 1210 * add an asconf add/delete/set primary IP address parameter to the queue.
michael@0 1211 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
michael@0 1212 * returns 0 if queued, -1 if not queued/removed.
michael@0 1213 * NOTE: if adding, but a delete for the same address is already scheduled
michael@0 1214 * (and not yet sent out), simply remove it from queue. Same for deleting
michael@0 1215 * an address already scheduled for add. If a duplicate operation is found,
michael@0 1216 * ignore the new one.
michael@0 1217 */
michael@0 1218 static int
michael@0 1219 sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
michael@0 1220 uint16_t type)
michael@0 1221 {
michael@0 1222 struct sctp_asconf_addr *aa, *aa_next;
michael@0 1223
michael@0 1224 /* make sure the request isn't already in the queue */
michael@0 1225 TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
michael@0 1226 /* address match? */
michael@0 1227 if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0)
michael@0 1228 continue;
michael@0 1229 /* is the request already in queue but not sent?
michael@0 1230 * pass the request already sent in order to resolve the following case:
michael@0 1231 * 1. arrival of ADD, then sent
michael@0 1232 * 2. arrival of DEL. we can't remove the ADD request already sent
michael@0 1233 * 3. arrival of ADD
michael@0 1234 */
michael@0 1235 if (aa->ap.aph.ph.param_type == type && aa->sent == 0) {
michael@0 1236 return (-1);
michael@0 1237 }
michael@0 1238 /* is the negative request already in queue, and not sent */
michael@0 1239 if ((aa->sent == 0) && (type == SCTP_ADD_IP_ADDRESS) &&
michael@0 1240 (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS)) {
michael@0 1241 /* add requested, delete already queued */
michael@0 1242 TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
michael@0 1243 /* remove the ifa from the restricted list */
michael@0 1244 sctp_del_local_addr_restricted(stcb, ifa);
michael@0 1245 /* free the asconf param */
michael@0 1246 SCTP_FREE(aa, SCTP_M_ASC_ADDR);
michael@0 1247 SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: add removes queued entry\n");
michael@0 1248 return (-1);
michael@0 1249 }
michael@0 1250 if ((aa->sent == 0) && (type == SCTP_DEL_IP_ADDRESS) &&
michael@0 1251 (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS)) {
michael@0 1252 /* delete requested, add already queued */
michael@0 1253 TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
michael@0 1254 /* remove the aa->ifa from the restricted list */
michael@0 1255 sctp_del_local_addr_restricted(stcb, aa->ifa);
michael@0 1256 /* free the asconf param */
michael@0 1257 SCTP_FREE(aa, SCTP_M_ASC_ADDR);
michael@0 1258 SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: delete removes queued entry\n");
michael@0 1259 return (-1);
michael@0 1260 }
michael@0 1261 } /* for each aa */
michael@0 1262
michael@0 1263 /* adding new request to the queue */
michael@0 1264 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
michael@0 1265 SCTP_M_ASC_ADDR);
michael@0 1266 if (aa == NULL) {
michael@0 1267 /* didn't get memory */
michael@0 1268 SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n");
michael@0 1269 return (-1);
michael@0 1270 }
michael@0 1271 aa->special_del = 0;
michael@0 1272 /* fill in asconf address parameter fields */
michael@0 1273 /* top level elements are "networked" during send */
michael@0 1274 aa->ap.aph.ph.param_type = type;
michael@0 1275 aa->ifa = ifa;
michael@0 1276 atomic_add_int(&ifa->refcount, 1);
michael@0 1277 /* correlation_id filled in during send routine later... */
michael@0 1278 switch (ifa->address.sa.sa_family) {
michael@0 1279 #ifdef INET6
michael@0 1280 case AF_INET6:
michael@0 1281 {
michael@0 1282 struct sockaddr_in6 *sin6;
michael@0 1283
michael@0 1284 sin6 = (struct sockaddr_in6 *)&ifa->address.sa;
michael@0 1285 aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
michael@0 1286 aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
michael@0 1287 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
michael@0 1288 sizeof(struct sctp_ipv6addr_param);
michael@0 1289 memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
michael@0 1290 sizeof(struct in6_addr));
michael@0 1291 break;
michael@0 1292 }
michael@0 1293 #endif
michael@0 1294 #ifdef INET
michael@0 1295 case AF_INET:
michael@0 1296 {
michael@0 1297 struct sockaddr_in *sin;
michael@0 1298
michael@0 1299 sin= (struct sockaddr_in *)&ifa->address.sa;
michael@0 1300 aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
michael@0 1301 aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
michael@0 1302 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
michael@0 1303 sizeof(struct sctp_ipv4addr_param);
michael@0 1304 memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
michael@0 1305 sizeof(struct in_addr));
michael@0 1306 break;
michael@0 1307 }
michael@0 1308 #endif
michael@0 1309 default:
michael@0 1310 /* invalid family! */
michael@0 1311 SCTP_FREE(aa, SCTP_M_ASC_ADDR);
michael@0 1312 sctp_free_ifa(ifa);
michael@0 1313 return (-1);
michael@0 1314 }
michael@0 1315 aa->sent = 0; /* clear sent flag */
michael@0 1316
michael@0 1317 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
michael@0 1318 #ifdef SCTP_DEBUG
michael@0 1319 if (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_ASCONF2) {
michael@0 1320 if (type == SCTP_ADD_IP_ADDRESS) {
michael@0 1321 SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: ");
michael@0 1322 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
michael@0 1323 } else if (type == SCTP_DEL_IP_ADDRESS) {
michael@0 1324 SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: ");
michael@0 1325 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
michael@0 1326 } else {
michael@0 1327 SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: ");
michael@0 1328 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
michael@0 1329 }
michael@0 1330 }
michael@0 1331 #endif
michael@0 1332
michael@0 1333 return (0);
michael@0 1334 }
michael@0 1335
michael@0 1336
michael@0 1337 /*
michael@0 1338 * add an asconf operation for the given ifa and type.
michael@0 1339 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
michael@0 1340 * returns 0 if completed, -1 if not completed, 1 if immediate send is
michael@0 1341 * advisable.
michael@0 1342 */
michael@0 1343 static int
michael@0 1344 sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
michael@0 1345 uint16_t type)
michael@0 1346 {
michael@0 1347 uint32_t status;
michael@0 1348 int pending_delete_queued = 0;
michael@0 1349
michael@0 1350 /* see if peer supports ASCONF */
michael@0 1351 if (stcb->asoc.peer_supports_asconf == 0) {
michael@0 1352 return (-1);
michael@0 1353 }
michael@0 1354
michael@0 1355 /*
michael@0 1356 * if this is deleting the last address from the assoc, mark it as
michael@0 1357 * pending.
michael@0 1358 */
michael@0 1359 if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending &&
michael@0 1360 (sctp_local_addr_count(stcb) < 2)) {
michael@0 1361 /* set the pending delete info only */
michael@0 1362 stcb->asoc.asconf_del_pending = 1;
michael@0 1363 stcb->asoc.asconf_addr_del_pending = ifa;
michael@0 1364 atomic_add_int(&ifa->refcount, 1);
michael@0 1365 SCTPDBG(SCTP_DEBUG_ASCONF2,
michael@0 1366 "asconf_queue_add: mark delete last address pending\n");
michael@0 1367 return (-1);
michael@0 1368 }
michael@0 1369
michael@0 1370 /* queue an asconf parameter */
michael@0 1371 status = sctp_asconf_queue_mgmt(stcb, ifa, type);
michael@0 1372
michael@0 1373 /*
michael@0 1374 * if this is an add, and there is a delete also pending (i.e. the
michael@0 1375 * last local address is being changed), queue the pending delete too.
michael@0 1376 */
michael@0 1377 if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending && (status == 0)) {
michael@0 1378 /* queue in the pending delete */
michael@0 1379 if (sctp_asconf_queue_mgmt(stcb,
michael@0 1380 stcb->asoc.asconf_addr_del_pending,
michael@0 1381 SCTP_DEL_IP_ADDRESS) == 0) {
michael@0 1382 SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queing pending delete\n");
michael@0 1383 pending_delete_queued = 1;
michael@0 1384 /* clear out the pending delete info */
michael@0 1385 stcb->asoc.asconf_del_pending = 0;
michael@0 1386 sctp_free_ifa(stcb->asoc.asconf_addr_del_pending);
michael@0 1387 stcb->asoc.asconf_addr_del_pending = NULL;
michael@0 1388 }
michael@0 1389 }
michael@0 1390
michael@0 1391 if (pending_delete_queued) {
michael@0 1392 struct sctp_nets *net;
michael@0 1393 /*
michael@0 1394 * since we know that the only/last address is now being
michael@0 1395 * changed in this case, reset the cwnd/rto on all nets to
michael@0 1396 * start as a new address and path. Also clear the error
michael@0 1397 * counts to give the assoc the best chance to complete the
michael@0 1398 * address change.
michael@0 1399 */
michael@0 1400 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
michael@0 1401 stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb,
michael@0 1402 net);
michael@0 1403 net->RTO = 0;
michael@0 1404 net->error_count = 0;
michael@0 1405 }
michael@0 1406 stcb->asoc.overall_error_count = 0;
michael@0 1407 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
michael@0 1408 sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
michael@0 1409 stcb->asoc.overall_error_count,
michael@0 1410 0,
michael@0 1411 SCTP_FROM_SCTP_ASCONF,
michael@0 1412 __LINE__);
michael@0 1413 }
michael@0 1414
michael@0 1415 /* queue in an advisory set primary too */
michael@0 1416 (void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR);
michael@0 1417 /* let caller know we should send this out immediately */
michael@0 1418 status = 1;
michael@0 1419 }
michael@0 1420 return (status);
michael@0 1421 }
michael@0 1422
michael@0 1423 /*-
michael@0 1424 * add an asconf delete IP address parameter to the queue by sockaddr and
michael@0 1425 * possibly with no sctp_ifa available. This is only called by the routine
michael@0 1426 * that checks the addresses in an INIT-ACK against the current address list.
michael@0 1427 * returns 0 if completed, non-zero if not completed.
michael@0 1428 * NOTE: if an add is already scheduled (and not yet sent out), simply
michael@0 1429 * remove it from queue. If a duplicate operation is found, ignore the
michael@0 1430 * new one.
michael@0 1431 */
michael@0 1432 static int
michael@0 1433 sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa)
michael@0 1434 {
michael@0 1435 struct sctp_ifa *ifa;
michael@0 1436 struct sctp_asconf_addr *aa, *aa_next;
michael@0 1437 uint32_t vrf_id;
michael@0 1438
michael@0 1439 if (stcb == NULL) {
michael@0 1440 return (-1);
michael@0 1441 }
michael@0 1442 /* see if peer supports ASCONF */
michael@0 1443 if (stcb->asoc.peer_supports_asconf == 0) {
michael@0 1444 return (-1);
michael@0 1445 }
michael@0 1446 /* make sure the request isn't already in the queue */
michael@0 1447 TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
michael@0 1448 /* address match? */
michael@0 1449 if (sctp_asconf_addr_match(aa, sa) == 0)
michael@0 1450 continue;
michael@0 1451 /* is the request already in queue (sent or not) */
michael@0 1452 if (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
michael@0 1453 return (-1);
michael@0 1454 }
michael@0 1455 /* is the negative request already in queue, and not sent */
michael@0 1456 if (aa->sent == 1)
michael@0 1457 continue;
michael@0 1458 if (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) {
michael@0 1459 /* add already queued, so remove existing entry */
michael@0 1460 TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
michael@0 1461 sctp_del_local_addr_restricted(stcb, aa->ifa);
michael@0 1462 /* free the entry */
michael@0 1463 SCTP_FREE(aa, SCTP_M_ASC_ADDR);
michael@0 1464 return (-1);
michael@0 1465 }
michael@0 1466 } /* for each aa */
michael@0 1467
michael@0 1468 /* find any existing ifa-- NOTE ifa CAN be allowed to be NULL */
michael@0 1469 if (stcb) {
michael@0 1470 vrf_id = stcb->asoc.vrf_id;
michael@0 1471 } else {
michael@0 1472 vrf_id = SCTP_DEFAULT_VRFID;
michael@0 1473 }
michael@0 1474 ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
michael@0 1475
michael@0 1476 /* adding new request to the queue */
michael@0 1477 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
michael@0 1478 SCTP_M_ASC_ADDR);
michael@0 1479 if (aa == NULL) {
michael@0 1480 /* didn't get memory */
michael@0 1481 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 1482 "sctp_asconf_queue_sa_delete: failed to get memory!\n");
michael@0 1483 return (-1);
michael@0 1484 }
michael@0 1485 aa->special_del = 0;
michael@0 1486 /* fill in asconf address parameter fields */
michael@0 1487 /* top level elements are "networked" during send */
michael@0 1488 aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
michael@0 1489 aa->ifa = ifa;
michael@0 1490 if (ifa)
michael@0 1491 atomic_add_int(&ifa->refcount, 1);
michael@0 1492 /* correlation_id filled in during send routine later... */
michael@0 1493 switch (sa->sa_family) {
michael@0 1494 #ifdef INET6
michael@0 1495 case AF_INET6:
michael@0 1496 {
michael@0 1497 /* IPv6 address */
michael@0 1498 struct sockaddr_in6 *sin6;
michael@0 1499
michael@0 1500 sin6 = (struct sockaddr_in6 *)sa;
michael@0 1501 aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
michael@0 1502 aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
michael@0 1503 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param);
michael@0 1504 memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
michael@0 1505 sizeof(struct in6_addr));
michael@0 1506 break;
michael@0 1507 }
michael@0 1508 #endif
michael@0 1509 #ifdef INET
michael@0 1510 case AF_INET:
michael@0 1511 {
michael@0 1512 /* IPv4 address */
michael@0 1513 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
michael@0 1514
michael@0 1515 aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
michael@0 1516 aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
michael@0 1517 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param);
michael@0 1518 memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
michael@0 1519 sizeof(struct in_addr));
michael@0 1520 break;
michael@0 1521 }
michael@0 1522 #endif
michael@0 1523 default:
michael@0 1524 /* invalid family! */
michael@0 1525 SCTP_FREE(aa, SCTP_M_ASC_ADDR);
michael@0 1526 if (ifa)
michael@0 1527 sctp_free_ifa(ifa);
michael@0 1528 return (-1);
michael@0 1529 }
michael@0 1530 aa->sent = 0; /* clear sent flag */
michael@0 1531
michael@0 1532 /* delete goes to the back of the queue */
michael@0 1533 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
michael@0 1534
michael@0 1535 /* sa_ignore MEMLEAK {memory is put on the tailq} */
michael@0 1536 return (0);
michael@0 1537 }
michael@0 1538
michael@0 1539 /*
michael@0 1540 * find a specific asconf param on our "sent" queue
michael@0 1541 */
michael@0 1542 static struct sctp_asconf_addr *
michael@0 1543 sctp_asconf_find_param(struct sctp_tcb *stcb, uint32_t correlation_id)
michael@0 1544 {
michael@0 1545 struct sctp_asconf_addr *aa;
michael@0 1546
michael@0 1547 TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
michael@0 1548 if (aa->ap.aph.correlation_id == correlation_id &&
michael@0 1549 aa->sent == 1) {
michael@0 1550 /* found it */
michael@0 1551 return (aa);
michael@0 1552 }
michael@0 1553 }
michael@0 1554 /* didn't find it */
michael@0 1555 return (NULL);
michael@0 1556 }
michael@0 1557
michael@0 1558 /*
michael@0 1559 * process an SCTP_ERROR_CAUSE_IND for a ASCONF-ACK parameter and do
michael@0 1560 * notifications based on the error response
michael@0 1561 */
michael@0 1562 static void
michael@0 1563 sctp_asconf_process_error(struct sctp_tcb *stcb,
michael@0 1564 struct sctp_asconf_paramhdr *aph)
michael@0 1565 {
michael@0 1566 struct sctp_error_cause *eh;
michael@0 1567 struct sctp_paramhdr *ph;
michael@0 1568 uint16_t param_type;
michael@0 1569 uint16_t error_code;
michael@0 1570
michael@0 1571 eh = (struct sctp_error_cause *)(aph + 1);
michael@0 1572 ph = (struct sctp_paramhdr *)(eh + 1);
michael@0 1573 /* validate lengths */
michael@0 1574 if (htons(eh->length) + sizeof(struct sctp_error_cause) >
michael@0 1575 htons(aph->ph.param_length)) {
michael@0 1576 /* invalid error cause length */
michael@0 1577 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 1578 "asconf_process_error: cause element too long\n");
michael@0 1579 return;
michael@0 1580 }
michael@0 1581 if (htons(ph->param_length) + sizeof(struct sctp_paramhdr) >
michael@0 1582 htons(eh->length)) {
michael@0 1583 /* invalid included TLV length */
michael@0 1584 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 1585 "asconf_process_error: included TLV too long\n");
michael@0 1586 return;
michael@0 1587 }
michael@0 1588 /* which error code ? */
michael@0 1589 error_code = ntohs(eh->code);
michael@0 1590 param_type = ntohs(aph->ph.param_type);
michael@0 1591 /* FIX: this should go back up the REMOTE_ERROR ULP notify */
michael@0 1592 switch (error_code) {
michael@0 1593 case SCTP_CAUSE_RESOURCE_SHORTAGE:
michael@0 1594 /* we allow ourselves to "try again" for this error */
michael@0 1595 break;
michael@0 1596 default:
michael@0 1597 /* peer can't handle it... */
michael@0 1598 switch (param_type) {
michael@0 1599 case SCTP_ADD_IP_ADDRESS:
michael@0 1600 case SCTP_DEL_IP_ADDRESS:
michael@0 1601 stcb->asoc.peer_supports_asconf = 0;
michael@0 1602 break;
michael@0 1603 case SCTP_SET_PRIM_ADDR:
michael@0 1604 stcb->asoc.peer_supports_asconf = 0;
michael@0 1605 break;
michael@0 1606 default:
michael@0 1607 break;
michael@0 1608 }
michael@0 1609 }
michael@0 1610 }
michael@0 1611
michael@0 1612 /*
michael@0 1613 * process an asconf queue param.
michael@0 1614 * aparam: parameter to process, will be removed from the queue.
michael@0 1615 * flag: 1=success case, 0=failure case
michael@0 1616 */
michael@0 1617 static void
michael@0 1618 sctp_asconf_process_param_ack(struct sctp_tcb *stcb,
michael@0 1619 struct sctp_asconf_addr *aparam, uint32_t flag)
michael@0 1620 {
michael@0 1621 uint16_t param_type;
michael@0 1622
michael@0 1623 /* process this param */
michael@0 1624 param_type = aparam->ap.aph.ph.param_type;
michael@0 1625 switch (param_type) {
michael@0 1626 case SCTP_ADD_IP_ADDRESS:
michael@0 1627 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 1628 "process_param_ack: added IP address\n");
michael@0 1629 sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, flag);
michael@0 1630 break;
michael@0 1631 case SCTP_DEL_IP_ADDRESS:
michael@0 1632 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 1633 "process_param_ack: deleted IP address\n");
michael@0 1634 /* nothing really to do... lists already updated */
michael@0 1635 break;
michael@0 1636 case SCTP_SET_PRIM_ADDR:
michael@0 1637 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 1638 "process_param_ack: set primary IP address\n");
michael@0 1639 /* nothing to do... peer may start using this addr */
michael@0 1640 if (flag == 0)
michael@0 1641 stcb->asoc.peer_supports_asconf = 0;
michael@0 1642 break;
michael@0 1643 default:
michael@0 1644 /* should NEVER happen */
michael@0 1645 break;
michael@0 1646 }
michael@0 1647
michael@0 1648 /* remove the param and free it */
michael@0 1649 TAILQ_REMOVE(&stcb->asoc.asconf_queue, aparam, next);
michael@0 1650 if (aparam->ifa)
michael@0 1651 sctp_free_ifa(aparam->ifa);
michael@0 1652 SCTP_FREE(aparam, SCTP_M_ASC_ADDR);
michael@0 1653 }
michael@0 1654
michael@0 1655 /*
michael@0 1656 * cleanup from a bad asconf ack parameter
michael@0 1657 */
michael@0 1658 static void
michael@0 1659 sctp_asconf_ack_clear(struct sctp_tcb *stcb)
michael@0 1660 {
michael@0 1661 /* assume peer doesn't really know how to do asconfs */
michael@0 1662 stcb->asoc.peer_supports_asconf = 0;
michael@0 1663 /* XXX we could free the pending queue here */
michael@0 1664 }
michael@0 1665
michael@0 1666 void
michael@0 1667 sctp_handle_asconf_ack(struct mbuf *m, int offset,
michael@0 1668 struct sctp_asconf_ack_chunk *cp, struct sctp_tcb *stcb,
michael@0 1669 struct sctp_nets *net, int *abort_no_unlock)
michael@0 1670 {
michael@0 1671 struct sctp_association *asoc;
michael@0 1672 uint32_t serial_num;
michael@0 1673 uint16_t ack_length;
michael@0 1674 struct sctp_asconf_paramhdr *aph;
michael@0 1675 struct sctp_asconf_addr *aa, *aa_next;
michael@0 1676 uint32_t last_error_id = 0; /* last error correlation id */
michael@0 1677 uint32_t id;
michael@0 1678 struct sctp_asconf_addr *ap;
michael@0 1679
michael@0 1680 /* asconf param buffer */
michael@0 1681 uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
michael@0 1682
michael@0 1683 /* verify minimum length */
michael@0 1684 if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_ack_chunk)) {
michael@0 1685 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 1686 "handle_asconf_ack: chunk too small = %xh\n",
michael@0 1687 ntohs(cp->ch.chunk_length));
michael@0 1688 return;
michael@0 1689 }
michael@0 1690 asoc = &stcb->asoc;
michael@0 1691 serial_num = ntohl(cp->serial_number);
michael@0 1692
michael@0 1693 /*
michael@0 1694 * NOTE: we may want to handle this differently- currently, we will
michael@0 1695 * abort when we get an ack for the expected serial number + 1 (eg.
michael@0 1696 * we didn't send it), process an ack normally if it is the expected
michael@0 1697 * serial number, and re-send the previous ack for *ALL* other
michael@0 1698 * serial numbers
michael@0 1699 */
michael@0 1700
michael@0 1701 /*
michael@0 1702 * if the serial number is the next expected, but I didn't send it,
michael@0 1703 * abort the asoc, since someone probably just hijacked us...
michael@0 1704 */
michael@0 1705 if (serial_num == (asoc->asconf_seq_out + 1)) {
michael@0 1706 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
michael@0 1707 sctp_abort_an_association(stcb->sctp_ep, stcb, NULL, SCTP_SO_NOT_LOCKED);
michael@0 1708 *abort_no_unlock = 1;
michael@0 1709 return;
michael@0 1710 }
michael@0 1711 if (serial_num != asoc->asconf_seq_out_acked + 1) {
michael@0 1712 /* got a duplicate/unexpected ASCONF-ACK */
michael@0 1713 SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n",
michael@0 1714 serial_num, asoc->asconf_seq_out_acked + 1);
michael@0 1715 return;
michael@0 1716 }
michael@0 1717
michael@0 1718 if (serial_num == asoc->asconf_seq_out - 1) {
michael@0 1719 /* stop our timer */
michael@0 1720 sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
michael@0 1721 SCTP_FROM_SCTP_ASCONF+SCTP_LOC_3);
michael@0 1722 }
michael@0 1723
michael@0 1724 /* process the ASCONF-ACK contents */
michael@0 1725 ack_length = ntohs(cp->ch.chunk_length) -
michael@0 1726 sizeof(struct sctp_asconf_ack_chunk);
michael@0 1727 offset += sizeof(struct sctp_asconf_ack_chunk);
michael@0 1728 /* process through all parameters */
michael@0 1729 while (ack_length >= sizeof(struct sctp_asconf_paramhdr)) {
michael@0 1730 unsigned int param_length, param_type;
michael@0 1731
michael@0 1732 /* get pointer to next asconf parameter */
michael@0 1733 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
michael@0 1734 sizeof(struct sctp_asconf_paramhdr), aparam_buf);
michael@0 1735 if (aph == NULL) {
michael@0 1736 /* can't get an asconf paramhdr */
michael@0 1737 sctp_asconf_ack_clear(stcb);
michael@0 1738 return;
michael@0 1739 }
michael@0 1740 param_type = ntohs(aph->ph.param_type);
michael@0 1741 param_length = ntohs(aph->ph.param_length);
michael@0 1742 if (param_length > ack_length) {
michael@0 1743 sctp_asconf_ack_clear(stcb);
michael@0 1744 return;
michael@0 1745 }
michael@0 1746 if (param_length < sizeof(struct sctp_paramhdr)) {
michael@0 1747 sctp_asconf_ack_clear(stcb);
michael@0 1748 return;
michael@0 1749 }
michael@0 1750 /* get the complete parameter... */
michael@0 1751 if (param_length > sizeof(aparam_buf)) {
michael@0 1752 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 1753 "param length (%u) larger than buffer size!\n", param_length);
michael@0 1754 sctp_asconf_ack_clear(stcb);
michael@0 1755 return;
michael@0 1756 }
michael@0 1757 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
michael@0 1758 if (aph == NULL) {
michael@0 1759 sctp_asconf_ack_clear(stcb);
michael@0 1760 return;
michael@0 1761 }
michael@0 1762 /* correlation_id is transparent to peer, no ntohl needed */
michael@0 1763 id = aph->correlation_id;
michael@0 1764
michael@0 1765 switch (param_type) {
michael@0 1766 case SCTP_ERROR_CAUSE_IND:
michael@0 1767 last_error_id = id;
michael@0 1768 /* find the corresponding asconf param in our queue */
michael@0 1769 ap = sctp_asconf_find_param(stcb, id);
michael@0 1770 if (ap == NULL) {
michael@0 1771 /* hmm... can't find this in our queue! */
michael@0 1772 break;
michael@0 1773 }
michael@0 1774 /* process the parameter, failed flag */
michael@0 1775 sctp_asconf_process_param_ack(stcb, ap, 0);
michael@0 1776 /* process the error response */
michael@0 1777 sctp_asconf_process_error(stcb, aph);
michael@0 1778 break;
michael@0 1779 case SCTP_SUCCESS_REPORT:
michael@0 1780 /* find the corresponding asconf param in our queue */
michael@0 1781 ap = sctp_asconf_find_param(stcb, id);
michael@0 1782 if (ap == NULL) {
michael@0 1783 /* hmm... can't find this in our queue! */
michael@0 1784 break;
michael@0 1785 }
michael@0 1786 /* process the parameter, success flag */
michael@0 1787 sctp_asconf_process_param_ack(stcb, ap, 1);
michael@0 1788 break;
michael@0 1789 default:
michael@0 1790 break;
michael@0 1791 } /* switch */
michael@0 1792
michael@0 1793 /* update remaining ASCONF-ACK message length to process */
michael@0 1794 ack_length -= SCTP_SIZE32(param_length);
michael@0 1795 if (ack_length <= 0) {
michael@0 1796 /* no more data in the mbuf chain */
michael@0 1797 break;
michael@0 1798 }
michael@0 1799 offset += SCTP_SIZE32(param_length);
michael@0 1800 } /* while */
michael@0 1801
michael@0 1802 /*
michael@0 1803 * if there are any "sent" params still on the queue, these are
michael@0 1804 * implicitly "success", or "failed" (if we got an error back) ...
michael@0 1805 * so process these appropriately
michael@0 1806 *
michael@0 1807 * we assume that the correlation_id's are monotonically increasing
michael@0 1808 * beginning from 1 and that we don't have *that* many outstanding
michael@0 1809 * at any given time
michael@0 1810 */
michael@0 1811 if (last_error_id == 0)
michael@0 1812 last_error_id--; /* set to "max" value */
michael@0 1813 TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
michael@0 1814 if (aa->sent == 1) {
michael@0 1815 /*
michael@0 1816 * implicitly successful or failed if correlation_id
michael@0 1817 * < last_error_id, then success else, failure
michael@0 1818 */
michael@0 1819 if (aa->ap.aph.correlation_id < last_error_id)
michael@0 1820 sctp_asconf_process_param_ack(stcb, aa, 1);
michael@0 1821 else
michael@0 1822 sctp_asconf_process_param_ack(stcb, aa, 0);
michael@0 1823 } else {
michael@0 1824 /*
michael@0 1825 * since we always process in order (FIFO queue) if
michael@0 1826 * we reach one that hasn't been sent, the rest
michael@0 1827 * should not have been sent either. so, we're
michael@0 1828 * done...
michael@0 1829 */
michael@0 1830 break;
michael@0 1831 }
michael@0 1832 }
michael@0 1833
michael@0 1834 /* update the next sequence number to use */
michael@0 1835 asoc->asconf_seq_out_acked++;
michael@0 1836 /* remove the old ASCONF on our outbound queue */
michael@0 1837 sctp_toss_old_asconf(stcb);
michael@0 1838 if (!TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
michael@0 1839 #ifdef SCTP_TIMER_BASED_ASCONF
michael@0 1840 /* we have more params, so restart our timer */
michael@0 1841 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep,
michael@0 1842 stcb, net);
michael@0 1843 #else
michael@0 1844 /* we have more params, so send out more */
michael@0 1845 sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
michael@0 1846 #endif
michael@0 1847 }
michael@0 1848 }
michael@0 1849
michael@0 1850 #ifdef INET6
michael@0 1851 static uint32_t
michael@0 1852 sctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa)
michael@0 1853 {
michael@0 1854 struct sockaddr_in6 *sin6, *net6;
michael@0 1855 struct sctp_nets *net;
michael@0 1856
michael@0 1857 if (sa->sa_family != AF_INET6) {
michael@0 1858 /* wrong family */
michael@0 1859 return (0);
michael@0 1860 }
michael@0 1861 sin6 = (struct sockaddr_in6 *)sa;
michael@0 1862 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) == 0) {
michael@0 1863 /* not link local address */
michael@0 1864 return (0);
michael@0 1865 }
michael@0 1866 /* hunt through our destination nets list for this scope_id */
michael@0 1867 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
michael@0 1868 if (((struct sockaddr *)(&net->ro._l_addr))->sa_family !=
michael@0 1869 AF_INET6)
michael@0 1870 continue;
michael@0 1871 net6 = (struct sockaddr_in6 *)&net->ro._l_addr;
michael@0 1872 if (IN6_IS_ADDR_LINKLOCAL(&net6->sin6_addr) == 0)
michael@0 1873 continue;
michael@0 1874 if (sctp_is_same_scope(sin6, net6)) {
michael@0 1875 /* found one */
michael@0 1876 return (1);
michael@0 1877 }
michael@0 1878 }
michael@0 1879 /* didn't find one */
michael@0 1880 return (0);
michael@0 1881 }
michael@0 1882 #endif
michael@0 1883
michael@0 1884 /*
michael@0 1885 * address management functions
michael@0 1886 */
michael@0 1887 static void
michael@0 1888 sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
michael@0 1889 struct sctp_ifa *ifa, uint16_t type, int addr_locked)
michael@0 1890 {
michael@0 1891 int status;
michael@0 1892
michael@0 1893 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 ||
michael@0 1894 sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
michael@0 1895 /* subset bound, no ASCONF allowed case, so ignore */
michael@0 1896 return;
michael@0 1897 }
michael@0 1898 /*
michael@0 1899 * note: we know this is not the subset bound, no ASCONF case eg.
michael@0 1900 * this is boundall or subset bound w/ASCONF allowed
michael@0 1901 */
michael@0 1902
michael@0 1903 /* first, make sure it's a good address family */
michael@0 1904 switch (ifa->address.sa.sa_family) {
michael@0 1905 #ifdef INET6
michael@0 1906 case AF_INET6:
michael@0 1907 break;
michael@0 1908 #endif
michael@0 1909 #ifdef INET
michael@0 1910 case AF_INET:
michael@0 1911 break;
michael@0 1912 #endif
michael@0 1913 default:
michael@0 1914 return;
michael@0 1915 }
michael@0 1916 #ifdef INET6
michael@0 1917 /* make sure we're "allowed" to add this type of addr */
michael@0 1918 if (ifa->address.sa.sa_family == AF_INET6) {
michael@0 1919 /* invalid if we're not a v6 endpoint */
michael@0 1920 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)
michael@0 1921 return;
michael@0 1922 /* is the v6 addr really valid ? */
michael@0 1923 if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
michael@0 1924 return;
michael@0 1925 }
michael@0 1926 }
michael@0 1927 #endif
michael@0 1928 /* put this address on the "pending/do not use yet" list */
michael@0 1929 sctp_add_local_addr_restricted(stcb, ifa);
michael@0 1930 /*
michael@0 1931 * check address scope if address is out of scope, don't queue
michael@0 1932 * anything... note: this would leave the address on both inp and
michael@0 1933 * asoc lists
michael@0 1934 */
michael@0 1935 switch (ifa->address.sa.sa_family) {
michael@0 1936 #ifdef INET6
michael@0 1937 case AF_INET6:
michael@0 1938 {
michael@0 1939 struct sockaddr_in6 *sin6;
michael@0 1940
michael@0 1941 sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
michael@0 1942 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
michael@0 1943 /* we skip unspecifed addresses */
michael@0 1944 return;
michael@0 1945 }
michael@0 1946 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
michael@0 1947 if (stcb->asoc.scope.local_scope == 0) {
michael@0 1948 return;
michael@0 1949 }
michael@0 1950 /* is it the right link local scope? */
michael@0 1951 if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
michael@0 1952 return;
michael@0 1953 }
michael@0 1954 }
michael@0 1955 if (stcb->asoc.scope.site_scope == 0 &&
michael@0 1956 IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
michael@0 1957 return;
michael@0 1958 }
michael@0 1959 break;
michael@0 1960 }
michael@0 1961 #endif
michael@0 1962 #ifdef INET
michael@0 1963 case AF_INET:
michael@0 1964 {
michael@0 1965 struct sockaddr_in *sin;
michael@0 1966 struct in6pcb *inp6;
michael@0 1967
michael@0 1968 inp6 = (struct in6pcb *)&inp->ip_inp.inp;
michael@0 1969 /* invalid if we are a v6 only endpoint */
michael@0 1970 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
michael@0 1971 SCTP_IPV6_V6ONLY(inp6))
michael@0 1972 return;
michael@0 1973
michael@0 1974 sin = (struct sockaddr_in *)&ifa->address.sa;
michael@0 1975 if (sin->sin_addr.s_addr == 0) {
michael@0 1976 /* we skip unspecifed addresses */
michael@0 1977 return;
michael@0 1978 }
michael@0 1979 if (stcb->asoc.scope.ipv4_local_scope == 0 &&
michael@0 1980 IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
michael@0 1981 return;
michael@0 1982 }
michael@0 1983 break;
michael@0 1984 }
michael@0 1985 #endif
michael@0 1986 default:
michael@0 1987 /* else, not AF_INET or AF_INET6, so skip */
michael@0 1988 return;
michael@0 1989 }
michael@0 1990
michael@0 1991 /* queue an asconf for this address add/delete */
michael@0 1992 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
michael@0 1993 /* does the peer do asconf? */
michael@0 1994 if (stcb->asoc.peer_supports_asconf) {
michael@0 1995 /* queue an asconf for this addr */
michael@0 1996 status = sctp_asconf_queue_add(stcb, ifa, type);
michael@0 1997
michael@0 1998 /*
michael@0 1999 * if queued ok, and in the open state, send out the
michael@0 2000 * ASCONF. If in the non-open state, these will be
michael@0 2001 * sent when the state goes open.
michael@0 2002 */
michael@0 2003 if (status == 0 &&
michael@0 2004 SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
michael@0 2005 #ifdef SCTP_TIMER_BASED_ASCONF
michael@0 2006 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
michael@0 2007 stcb, stcb->asoc.primary_destination);
michael@0 2008 #else
michael@0 2009 sctp_send_asconf(stcb, NULL, addr_locked);
michael@0 2010 #endif
michael@0 2011 }
michael@0 2012 }
michael@0 2013 }
michael@0 2014 }
michael@0 2015
michael@0 2016
michael@0 2017 int
michael@0 2018 sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
michael@0 2019 {
michael@0 2020 struct sctp_asconf_iterator *asc;
michael@0 2021 struct sctp_ifa *ifa;
michael@0 2022 struct sctp_laddr *l;
michael@0 2023 int cnt_invalid = 0;
michael@0 2024
michael@0 2025 asc = (struct sctp_asconf_iterator *)ptr;
michael@0 2026 LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
michael@0 2027 ifa = l->ifa;
michael@0 2028 switch (ifa->address.sa.sa_family) {
michael@0 2029 #ifdef INET6
michael@0 2030 case AF_INET6:
michael@0 2031 /* invalid if we're not a v6 endpoint */
michael@0 2032 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
michael@0 2033 cnt_invalid++;
michael@0 2034 if (asc->cnt == cnt_invalid)
michael@0 2035 return (1);
michael@0 2036 }
michael@0 2037 break;
michael@0 2038 #endif
michael@0 2039 #ifdef INET
michael@0 2040 case AF_INET:
michael@0 2041 {
michael@0 2042 /* invalid if we are a v6 only endpoint */
michael@0 2043 struct in6pcb *inp6;
michael@0 2044 inp6 = (struct in6pcb *)&inp->ip_inp.inp;
michael@0 2045 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
michael@0 2046 SCTP_IPV6_V6ONLY(inp6)) {
michael@0 2047 cnt_invalid++;
michael@0 2048 if (asc->cnt == cnt_invalid)
michael@0 2049 return (1);
michael@0 2050 }
michael@0 2051 break;
michael@0 2052 }
michael@0 2053 #endif
michael@0 2054 default:
michael@0 2055 /* invalid address family */
michael@0 2056 cnt_invalid++;
michael@0 2057 if (asc->cnt == cnt_invalid)
michael@0 2058 return (1);
michael@0 2059 }
michael@0 2060 }
michael@0 2061 return (0);
michael@0 2062 }
michael@0 2063
michael@0 2064 static int
michael@0 2065 sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
michael@0 2066 {
michael@0 2067 struct sctp_ifa *ifa;
michael@0 2068 struct sctp_asconf_iterator *asc;
michael@0 2069 struct sctp_laddr *laddr, *nladdr, *l;
michael@0 2070
michael@0 2071 /* Only for specific case not bound all */
michael@0 2072 asc = (struct sctp_asconf_iterator *)ptr;
michael@0 2073 LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
michael@0 2074 ifa = l->ifa;
michael@0 2075 if (l->action == SCTP_ADD_IP_ADDRESS) {
michael@0 2076 LIST_FOREACH(laddr, &inp->sctp_addr_list,
michael@0 2077 sctp_nxt_addr) {
michael@0 2078 if (laddr->ifa == ifa) {
michael@0 2079 laddr->action = 0;
michael@0 2080 break;
michael@0 2081 }
michael@0 2082
michael@0 2083 }
michael@0 2084 } else if (l->action == SCTP_DEL_IP_ADDRESS) {
michael@0 2085 LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
michael@0 2086 /* remove only after all guys are done */
michael@0 2087 if (laddr->ifa == ifa) {
michael@0 2088 sctp_del_local_addr_ep(inp, ifa);
michael@0 2089 }
michael@0 2090 }
michael@0 2091 }
michael@0 2092 }
michael@0 2093 return (0);
michael@0 2094 }
michael@0 2095
michael@0 2096 void
michael@0 2097 sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
michael@0 2098 void *ptr, uint32_t val SCTP_UNUSED)
michael@0 2099 {
michael@0 2100 struct sctp_asconf_iterator *asc;
michael@0 2101 struct sctp_ifa *ifa;
michael@0 2102 struct sctp_laddr *l;
michael@0 2103 int cnt_invalid = 0;
michael@0 2104 int type, status;
michael@0 2105 int num_queued = 0;
michael@0 2106
michael@0 2107 asc = (struct sctp_asconf_iterator *)ptr;
michael@0 2108 LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
michael@0 2109 ifa = l->ifa;
michael@0 2110 type = l->action;
michael@0 2111
michael@0 2112 /* address's vrf_id must be the vrf_id of the assoc */
michael@0 2113 if (ifa->vrf_id != stcb->asoc.vrf_id) {
michael@0 2114 continue;
michael@0 2115 }
michael@0 2116
michael@0 2117 /* Same checks again for assoc */
michael@0 2118 switch (ifa->address.sa.sa_family) {
michael@0 2119 #ifdef INET6
michael@0 2120 case AF_INET6:
michael@0 2121 {
michael@0 2122 /* invalid if we're not a v6 endpoint */
michael@0 2123 struct sockaddr_in6 *sin6;
michael@0 2124
michael@0 2125 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
michael@0 2126 cnt_invalid++;
michael@0 2127 if (asc->cnt == cnt_invalid)
michael@0 2128 return;
michael@0 2129 else
michael@0 2130 continue;
michael@0 2131 }
michael@0 2132 sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
michael@0 2133 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
michael@0 2134 /* we skip unspecifed addresses */
michael@0 2135 continue;
michael@0 2136 }
michael@0 2137 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
michael@0 2138 if (stcb->asoc.scope.local_scope == 0) {
michael@0 2139 continue;
michael@0 2140 }
michael@0 2141 /* is it the right link local scope? */
michael@0 2142 if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
michael@0 2143 continue;
michael@0 2144 }
michael@0 2145 }
michael@0 2146 break;
michael@0 2147 }
michael@0 2148 #endif
michael@0 2149 #ifdef INET
michael@0 2150 case AF_INET:
michael@0 2151 {
michael@0 2152 /* invalid if we are a v6 only endpoint */
michael@0 2153 struct in6pcb *inp6;
michael@0 2154 struct sockaddr_in *sin;
michael@0 2155
michael@0 2156 inp6 = (struct in6pcb *)&inp->ip_inp.inp;
michael@0 2157 /* invalid if we are a v6 only endpoint */
michael@0 2158 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
michael@0 2159 SCTP_IPV6_V6ONLY(inp6))
michael@0 2160 continue;
michael@0 2161
michael@0 2162 sin = (struct sockaddr_in *)&ifa->address.sa;
michael@0 2163 if (sin->sin_addr.s_addr == 0) {
michael@0 2164 /* we skip unspecifed addresses */
michael@0 2165 continue;
michael@0 2166 }
michael@0 2167 if (stcb->asoc.scope.ipv4_local_scope == 0 &&
michael@0 2168 IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
michael@0 2169 continue;
michael@0 2170 }
michael@0 2171 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
michael@0 2172 SCTP_IPV6_V6ONLY(inp6)) {
michael@0 2173 cnt_invalid++;
michael@0 2174 if (asc->cnt == cnt_invalid)
michael@0 2175 return;
michael@0 2176 else
michael@0 2177 continue;
michael@0 2178 }
michael@0 2179 break;
michael@0 2180 }
michael@0 2181 #endif
michael@0 2182 default:
michael@0 2183 /* invalid address family */
michael@0 2184 cnt_invalid++;
michael@0 2185 if (asc->cnt == cnt_invalid)
michael@0 2186 return;
michael@0 2187 else
michael@0 2188 continue;
michael@0 2189 break;
michael@0 2190 }
michael@0 2191
michael@0 2192 if (type == SCTP_ADD_IP_ADDRESS) {
michael@0 2193 /* prevent this address from being used as a source */
michael@0 2194 sctp_add_local_addr_restricted(stcb, ifa);
michael@0 2195 } else if (type == SCTP_DEL_IP_ADDRESS) {
michael@0 2196 struct sctp_nets *net;
michael@0 2197 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
michael@0 2198 sctp_rtentry_t *rt;
michael@0 2199
michael@0 2200 /* delete this address if cached */
michael@0 2201 if (net->ro._s_addr == ifa) {
michael@0 2202 sctp_free_ifa(net->ro._s_addr);
michael@0 2203 net->ro._s_addr = NULL;
michael@0 2204 net->src_addr_selected = 0;
michael@0 2205 rt = net->ro.ro_rt;
michael@0 2206 if (rt) {
michael@0 2207 RTFREE(rt);
michael@0 2208 net->ro.ro_rt = NULL;
michael@0 2209 }
michael@0 2210 /*
michael@0 2211 * Now we deleted our src address,
michael@0 2212 * should we not also now reset the
michael@0 2213 * cwnd/rto to start as if its a new
michael@0 2214 * address?
michael@0 2215 */
michael@0 2216 stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
michael@0 2217 net->RTO = 0;
michael@0 2218
michael@0 2219 }
michael@0 2220 }
michael@0 2221 } else if (type == SCTP_SET_PRIM_ADDR) {
michael@0 2222 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
michael@0 2223 /* must validate the ifa is in the ep */
michael@0 2224 if (sctp_is_addr_in_ep(stcb->sctp_ep,ifa) == 0) {
michael@0 2225 continue;
michael@0 2226 }
michael@0 2227 } else {
michael@0 2228 /* Need to check scopes for this guy */
michael@0 2229 if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) {
michael@0 2230 continue;
michael@0 2231 }
michael@0 2232 }
michael@0 2233 }
michael@0 2234 /* queue an asconf for this address add/delete */
michael@0 2235 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF) &&
michael@0 2236 stcb->asoc.peer_supports_asconf) {
michael@0 2237 /* queue an asconf for this addr */
michael@0 2238 status = sctp_asconf_queue_add(stcb, ifa, type);
michael@0 2239 /*
michael@0 2240 * if queued ok, and in the open state, update the
michael@0 2241 * count of queued params. If in the non-open state,
michael@0 2242 * these get sent when the assoc goes open.
michael@0 2243 */
michael@0 2244 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
michael@0 2245 if (status >= 0) {
michael@0 2246 num_queued++;
michael@0 2247 }
michael@0 2248 }
michael@0 2249 }
michael@0 2250 }
michael@0 2251 /*
michael@0 2252 * If we have queued params in the open state, send out an ASCONF.
michael@0 2253 */
michael@0 2254 if (num_queued > 0) {
michael@0 2255 sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
michael@0 2256 }
michael@0 2257 }
michael@0 2258
michael@0 2259 void
michael@0 2260 sctp_asconf_iterator_end(void *ptr, uint32_t val SCTP_UNUSED)
michael@0 2261 {
michael@0 2262 struct sctp_asconf_iterator *asc;
michael@0 2263 struct sctp_ifa *ifa;
michael@0 2264 struct sctp_laddr *l, *nl;
michael@0 2265
michael@0 2266 asc = (struct sctp_asconf_iterator *)ptr;
michael@0 2267 LIST_FOREACH_SAFE(l, &asc->list_of_work, sctp_nxt_addr, nl) {
michael@0 2268 ifa = l->ifa;
michael@0 2269 if (l->action == SCTP_ADD_IP_ADDRESS) {
michael@0 2270 /* Clear the defer use flag */
michael@0 2271 ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
michael@0 2272 }
michael@0 2273 sctp_free_ifa(ifa);
michael@0 2274 SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), l);
michael@0 2275 SCTP_DECR_LADDR_COUNT();
michael@0 2276 }
michael@0 2277 SCTP_FREE(asc, SCTP_M_ASC_IT);
michael@0 2278 }
michael@0 2279
michael@0 2280 /*
michael@0 2281 * sa is the sockaddr to ask the peer to set primary to.
michael@0 2282 * returns: 0 = completed, -1 = error
michael@0 2283 */
michael@0 2284 int32_t
michael@0 2285 sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
michael@0 2286 {
michael@0 2287 uint32_t vrf_id;
michael@0 2288 struct sctp_ifa *ifa;
michael@0 2289
michael@0 2290 /* find the ifa for the desired set primary */
michael@0 2291 vrf_id = stcb->asoc.vrf_id;
michael@0 2292 ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
michael@0 2293 if (ifa == NULL) {
michael@0 2294 /* Invalid address */
michael@0 2295 return (-1);
michael@0 2296 }
michael@0 2297
michael@0 2298 /* queue an ASCONF:SET_PRIM_ADDR to be sent */
michael@0 2299 if (!sctp_asconf_queue_add(stcb, ifa, SCTP_SET_PRIM_ADDR)) {
michael@0 2300 /* set primary queuing succeeded */
michael@0 2301 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 2302 "set_primary_ip_address_sa: queued on tcb=%p, ",
michael@0 2303 (void *)stcb);
michael@0 2304 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
michael@0 2305 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
michael@0 2306 #ifdef SCTP_TIMER_BASED_ASCONF
michael@0 2307 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
michael@0 2308 stcb->sctp_ep, stcb,
michael@0 2309 stcb->asoc.primary_destination);
michael@0 2310 #else
michael@0 2311 sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
michael@0 2312 #endif
michael@0 2313 }
michael@0 2314 } else {
michael@0 2315 SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: failed to add to queue on tcb=%p, ",
michael@0 2316 (void *)stcb);
michael@0 2317 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
michael@0 2318 return (-1);
michael@0 2319 }
michael@0 2320 return (0);
michael@0 2321 }
michael@0 2322
michael@0 2323 void
michael@0 2324 sctp_set_primary_ip_address(struct sctp_ifa *ifa)
michael@0 2325 {
michael@0 2326 struct sctp_inpcb *inp;
michael@0 2327
michael@0 2328 /* go through all our PCB's */
michael@0 2329 LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) {
michael@0 2330 struct sctp_tcb *stcb;
michael@0 2331
michael@0 2332 /* process for all associations for this endpoint */
michael@0 2333 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
michael@0 2334 /* queue an ASCONF:SET_PRIM_ADDR to be sent */
michael@0 2335 if (!sctp_asconf_queue_add(stcb, ifa,
michael@0 2336 SCTP_SET_PRIM_ADDR)) {
michael@0 2337 /* set primary queuing succeeded */
michael@0 2338 SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ",
michael@0 2339 (void *)stcb);
michael@0 2340 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa);
michael@0 2341 if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
michael@0 2342 #ifdef SCTP_TIMER_BASED_ASCONF
michael@0 2343 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
michael@0 2344 stcb->sctp_ep, stcb,
michael@0 2345 stcb->asoc.primary_destination);
michael@0 2346 #else
michael@0 2347 sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
michael@0 2348 #endif
michael@0 2349 }
michael@0 2350 }
michael@0 2351 } /* for each stcb */
michael@0 2352 } /* for each inp */
michael@0 2353 }
michael@0 2354
michael@0 2355 int
michael@0 2356 sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa)
michael@0 2357 {
michael@0 2358 struct sctp_tmit_chunk *chk, *nchk;
michael@0 2359 unsigned int offset, asconf_limit;
michael@0 2360 struct sctp_asconf_chunk *acp;
michael@0 2361 struct sctp_asconf_paramhdr *aph;
michael@0 2362 uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
michael@0 2363 struct sctp_paramhdr *ph;
michael@0 2364 int add_cnt, del_cnt;
michael@0 2365 uint16_t last_param_type;
michael@0 2366
michael@0 2367 add_cnt = del_cnt = 0;
michael@0 2368 last_param_type = 0;
michael@0 2369 TAILQ_FOREACH_SAFE(chk, &stcb->asoc.asconf_send_queue, sctp_next, nchk) {
michael@0 2370 if (chk->data == NULL) {
michael@0 2371 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: No mbuf data?\n");
michael@0 2372 continue;
michael@0 2373 }
michael@0 2374 offset = 0;
michael@0 2375 acp = mtod(chk->data, struct sctp_asconf_chunk *);
michael@0 2376 offset += sizeof(struct sctp_asconf_chunk);
michael@0 2377 asconf_limit = ntohs(acp->ch.chunk_length);
michael@0 2378 ph = (struct sctp_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf);
michael@0 2379 if (ph == NULL) {
michael@0 2380 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get lookup addr!\n");
michael@0 2381 continue;
michael@0 2382 }
michael@0 2383 offset += ntohs(ph->param_length);
michael@0 2384
michael@0 2385 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
michael@0 2386 if (aph == NULL) {
michael@0 2387 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: Empty ASCONF will be sent?\n");
michael@0 2388 continue;
michael@0 2389 }
michael@0 2390 while (aph != NULL) {
michael@0 2391 unsigned int param_length, param_type;
michael@0 2392
michael@0 2393 param_type = ntohs(aph->ph.param_type);
michael@0 2394 param_length = ntohs(aph->ph.param_length);
michael@0 2395 if (offset + param_length > asconf_limit) {
michael@0 2396 /* parameter goes beyond end of chunk! */
michael@0 2397 break;
michael@0 2398 }
michael@0 2399 if (param_length > sizeof(aparam_buf)) {
michael@0 2400 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length (%u) larger than buffer size!\n", param_length);
michael@0 2401 break;
michael@0 2402 }
michael@0 2403 if (param_length <= sizeof(struct sctp_paramhdr)) {
michael@0 2404 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length(%u) too short\n", param_length);
michael@0 2405 break;
michael@0 2406 }
michael@0 2407
michael@0 2408 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, param_length, aparam_buf);
michael@0 2409 if (aph == NULL) {
michael@0 2410 SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get entire param\n");
michael@0 2411 break;
michael@0 2412 }
michael@0 2413
michael@0 2414 ph = (struct sctp_paramhdr *)(aph + 1);
michael@0 2415 if (sctp_addr_match(ph, &sctp_ifa->address.sa) != 0) {
michael@0 2416 switch (param_type) {
michael@0 2417 case SCTP_ADD_IP_ADDRESS:
michael@0 2418 add_cnt++;
michael@0 2419 break;
michael@0 2420 case SCTP_DEL_IP_ADDRESS:
michael@0 2421 del_cnt++;
michael@0 2422 break;
michael@0 2423 default:
michael@0 2424 break;
michael@0 2425 }
michael@0 2426 last_param_type = param_type;
michael@0 2427 }
michael@0 2428
michael@0 2429 offset += SCTP_SIZE32(param_length);
michael@0 2430 if (offset >= asconf_limit) {
michael@0 2431 /* no more data in the mbuf chain */
michael@0 2432 break;
michael@0 2433 }
michael@0 2434 /* get pointer to next asconf param */
michael@0 2435 aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
michael@0 2436 }
michael@0 2437 }
michael@0 2438
michael@0 2439 /* we want to find the sequences which consist of ADD -> DEL -> ADD or DEL -> ADD */
michael@0 2440 if (add_cnt > del_cnt ||
michael@0 2441 (add_cnt == del_cnt && last_param_type == SCTP_ADD_IP_ADDRESS)) {
michael@0 2442 return (1);
michael@0 2443 }
michael@0 2444 return (0);
michael@0 2445 }
michael@0 2446
michael@0 2447 static struct sockaddr *
michael@0 2448 sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
michael@0 2449 {
michael@0 2450 struct sctp_vrf *vrf = NULL;
michael@0 2451 struct sctp_ifn *sctp_ifn;
michael@0 2452 struct sctp_ifa *sctp_ifa;
michael@0 2453
michael@0 2454 if (addr_locked == SCTP_ADDR_NOT_LOCKED)
michael@0 2455 SCTP_IPI_ADDR_RLOCK();
michael@0 2456 vrf = sctp_find_vrf(stcb->asoc.vrf_id);
michael@0 2457 if (vrf == NULL) {
michael@0 2458 if (addr_locked == SCTP_ADDR_NOT_LOCKED)
michael@0 2459 SCTP_IPI_ADDR_RUNLOCK();
michael@0 2460 return (NULL);
michael@0 2461 }
michael@0 2462 LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
michael@0 2463 if (stcb->asoc.scope.loopback_scope == 0 &&
michael@0 2464 SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
michael@0 2465 /* Skip if loopback_scope not set */
michael@0 2466 continue;
michael@0 2467 }
michael@0 2468 LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
michael@0 2469 switch (sctp_ifa->address.sa.sa_family) {
michael@0 2470 #ifdef INET
michael@0 2471 case AF_INET:
michael@0 2472 if (stcb->asoc.scope.ipv4_addr_legal) {
michael@0 2473 struct sockaddr_in *sin;
michael@0 2474
michael@0 2475 sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
michael@0 2476 if (sin->sin_addr.s_addr == 0) {
michael@0 2477 /* skip unspecifed addresses */
michael@0 2478 continue;
michael@0 2479 }
michael@0 2480 if (stcb->asoc.scope.ipv4_local_scope == 0 &&
michael@0 2481 IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))
michael@0 2482 continue;
michael@0 2483
michael@0 2484 if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
michael@0 2485 (!sctp_is_addr_pending(stcb, sctp_ifa)))
michael@0 2486 continue;
michael@0 2487 /* found a valid local v4 address to use */
michael@0 2488 if (addr_locked == SCTP_ADDR_NOT_LOCKED)
michael@0 2489 SCTP_IPI_ADDR_RUNLOCK();
michael@0 2490 return (&sctp_ifa->address.sa);
michael@0 2491 }
michael@0 2492 break;
michael@0 2493 #endif
michael@0 2494 #ifdef INET6
michael@0 2495 case AF_INET6:
michael@0 2496 if (stcb->asoc.scope.ipv6_addr_legal) {
michael@0 2497 struct sockaddr_in6 *sin6;
michael@0 2498
michael@0 2499 if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
michael@0 2500 continue;
michael@0 2501 }
michael@0 2502
michael@0 2503 sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
michael@0 2504 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
michael@0 2505 /* we skip unspecifed addresses */
michael@0 2506 continue;
michael@0 2507 }
michael@0 2508 if (stcb->asoc.scope.local_scope == 0 &&
michael@0 2509 IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
michael@0 2510 continue;
michael@0 2511 if (stcb->asoc.scope.site_scope == 0 &&
michael@0 2512 IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
michael@0 2513 continue;
michael@0 2514
michael@0 2515 if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
michael@0 2516 (!sctp_is_addr_pending(stcb, sctp_ifa)))
michael@0 2517 continue;
michael@0 2518 /* found a valid local v6 address to use */
michael@0 2519 if (addr_locked == SCTP_ADDR_NOT_LOCKED)
michael@0 2520 SCTP_IPI_ADDR_RUNLOCK();
michael@0 2521 return (&sctp_ifa->address.sa);
michael@0 2522 }
michael@0 2523 break;
michael@0 2524 #endif
michael@0 2525 default:
michael@0 2526 break;
michael@0 2527 }
michael@0 2528 }
michael@0 2529 }
michael@0 2530 /* no valid addresses found */
michael@0 2531 if (addr_locked == SCTP_ADDR_NOT_LOCKED)
michael@0 2532 SCTP_IPI_ADDR_RUNLOCK();
michael@0 2533 return (NULL);
michael@0 2534 }
michael@0 2535
michael@0 2536 static struct sockaddr *
michael@0 2537 sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb)
michael@0 2538 {
michael@0 2539 struct sctp_laddr *laddr;
michael@0 2540
michael@0 2541 LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
michael@0 2542 if (laddr->ifa == NULL) {
michael@0 2543 continue;
michael@0 2544 }
michael@0 2545 /* is the address restricted ? */
michael@0 2546 if (sctp_is_addr_restricted(stcb, laddr->ifa) &&
michael@0 2547 (!sctp_is_addr_pending(stcb, laddr->ifa)))
michael@0 2548 continue;
michael@0 2549
michael@0 2550 /* found a valid local address to use */
michael@0 2551 return (&laddr->ifa->address.sa);
michael@0 2552 }
michael@0 2553 /* no valid addresses found */
michael@0 2554 return (NULL);
michael@0 2555 }
michael@0 2556
michael@0 2557 /*
michael@0 2558 * builds an ASCONF chunk from queued ASCONF params.
michael@0 2559 * returns NULL on error (no mbuf, no ASCONF params queued, etc).
michael@0 2560 */
michael@0 2561 struct mbuf *
michael@0 2562 sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
michael@0 2563 {
michael@0 2564 struct mbuf *m_asconf, *m_asconf_chk;
michael@0 2565 struct sctp_asconf_addr *aa;
michael@0 2566 struct sctp_asconf_chunk *acp;
michael@0 2567 struct sctp_asconf_paramhdr *aph;
michael@0 2568 struct sctp_asconf_addr_param *aap;
michael@0 2569 uint32_t p_length;
michael@0 2570 uint32_t correlation_id = 1; /* 0 is reserved... */
michael@0 2571 caddr_t ptr, lookup_ptr;
michael@0 2572 uint8_t lookup_used = 0;
michael@0 2573
michael@0 2574 /* are there any asconf params to send? */
michael@0 2575 TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
michael@0 2576 if (aa->sent == 0)
michael@0 2577 break;
michael@0 2578 }
michael@0 2579 if (aa == NULL)
michael@0 2580 return (NULL);
michael@0 2581
michael@0 2582 /*
michael@0 2583 * get a chunk header mbuf and a cluster for the asconf params since
michael@0 2584 * it's simpler to fill in the asconf chunk header lookup address on
michael@0 2585 * the fly
michael@0 2586 */
michael@0 2587 m_asconf_chk = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_chunk), 0, M_NOWAIT, 1, MT_DATA);
michael@0 2588 if (m_asconf_chk == NULL) {
michael@0 2589 /* no mbuf's */
michael@0 2590 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 2591 "compose_asconf: couldn't get chunk mbuf!\n");
michael@0 2592 return (NULL);
michael@0 2593 }
michael@0 2594 m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
michael@0 2595 if (m_asconf == NULL) {
michael@0 2596 /* no mbuf's */
michael@0 2597 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 2598 "compose_asconf: couldn't get mbuf!\n");
michael@0 2599 sctp_m_freem(m_asconf_chk);
michael@0 2600 return (NULL);
michael@0 2601 }
michael@0 2602 SCTP_BUF_LEN(m_asconf_chk) = sizeof(struct sctp_asconf_chunk);
michael@0 2603 SCTP_BUF_LEN(m_asconf) = 0;
michael@0 2604 acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *);
michael@0 2605 bzero(acp, sizeof(struct sctp_asconf_chunk));
michael@0 2606 /* save pointers to lookup address and asconf params */
michael@0 2607 lookup_ptr = (caddr_t)(acp + 1); /* after the header */
michael@0 2608 ptr = mtod(m_asconf, caddr_t); /* beginning of cluster */
michael@0 2609
michael@0 2610 /* fill in chunk header info */
michael@0 2611 acp->ch.chunk_type = SCTP_ASCONF;
michael@0 2612 acp->ch.chunk_flags = 0;
michael@0 2613 acp->serial_number = htonl(stcb->asoc.asconf_seq_out);
michael@0 2614 stcb->asoc.asconf_seq_out++;
michael@0 2615
michael@0 2616 /* add parameters... up to smallest MTU allowed */
michael@0 2617 TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
michael@0 2618 if (aa->sent)
michael@0 2619 continue;
michael@0 2620 /* get the parameter length */
michael@0 2621 p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length);
michael@0 2622 /* will it fit in current chunk? */
michael@0 2623 if ((SCTP_BUF_LEN(m_asconf) + p_length > stcb->asoc.smallest_mtu) ||
michael@0 2624 (SCTP_BUF_LEN(m_asconf) + p_length > MCLBYTES)) {
michael@0 2625 /* won't fit, so we're done with this chunk */
michael@0 2626 break;
michael@0 2627 }
michael@0 2628 /* assign (and store) a correlation id */
michael@0 2629 aa->ap.aph.correlation_id = correlation_id++;
michael@0 2630
michael@0 2631 /*
michael@0 2632 * fill in address if we're doing a delete this is a simple
michael@0 2633 * way for us to fill in the correlation address, which
michael@0 2634 * should only be used by the peer if we're deleting our
michael@0 2635 * source address and adding a new address (e.g. renumbering
michael@0 2636 * case)
michael@0 2637 */
michael@0 2638 if (lookup_used == 0 &&
michael@0 2639 (aa->special_del == 0) &&
michael@0 2640 aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
michael@0 2641 struct sctp_ipv6addr_param *lookup;
michael@0 2642 uint16_t p_size, addr_size;
michael@0 2643
michael@0 2644 lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
michael@0 2645 lookup->ph.param_type =
michael@0 2646 htons(aa->ap.addrp.ph.param_type);
michael@0 2647 if (aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) {
michael@0 2648 /* copy IPv6 address */
michael@0 2649 p_size = sizeof(struct sctp_ipv6addr_param);
michael@0 2650 addr_size = sizeof(struct in6_addr);
michael@0 2651 } else {
michael@0 2652 /* copy IPv4 address */
michael@0 2653 p_size = sizeof(struct sctp_ipv4addr_param);
michael@0 2654 addr_size = sizeof(struct in_addr);
michael@0 2655 }
michael@0 2656 lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
michael@0 2657 memcpy(lookup->addr, &aa->ap.addrp.addr, addr_size);
michael@0 2658 SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size);
michael@0 2659 lookup_used = 1;
michael@0 2660 }
michael@0 2661 /* copy into current space */
michael@0 2662 memcpy(ptr, &aa->ap, p_length);
michael@0 2663
michael@0 2664 /* network elements and update lengths */
michael@0 2665 aph = (struct sctp_asconf_paramhdr *)ptr;
michael@0 2666 aap = (struct sctp_asconf_addr_param *)ptr;
michael@0 2667 /* correlation_id is transparent to peer, no htonl needed */
michael@0 2668 aph->ph.param_type = htons(aph->ph.param_type);
michael@0 2669 aph->ph.param_length = htons(aph->ph.param_length);
michael@0 2670 aap->addrp.ph.param_type = htons(aap->addrp.ph.param_type);
michael@0 2671 aap->addrp.ph.param_length = htons(aap->addrp.ph.param_length);
michael@0 2672
michael@0 2673 SCTP_BUF_LEN(m_asconf) += SCTP_SIZE32(p_length);
michael@0 2674 ptr += SCTP_SIZE32(p_length);
michael@0 2675
michael@0 2676 /*
michael@0 2677 * these params are removed off the pending list upon
michael@0 2678 * getting an ASCONF-ACK back from the peer, just set flag
michael@0 2679 */
michael@0 2680 aa->sent = 1;
michael@0 2681 }
michael@0 2682 /* check to see if the lookup addr has been populated yet */
michael@0 2683 if (lookup_used == 0) {
michael@0 2684 /* NOTE: if the address param is optional, can skip this... */
michael@0 2685 /* add any valid (existing) address... */
michael@0 2686 struct sctp_ipv6addr_param *lookup;
michael@0 2687 uint16_t p_size, addr_size;
michael@0 2688 struct sockaddr *found_addr;
michael@0 2689 caddr_t addr_ptr;
michael@0 2690
michael@0 2691 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)
michael@0 2692 found_addr = sctp_find_valid_localaddr(stcb,
michael@0 2693 addr_locked);
michael@0 2694 else
michael@0 2695 found_addr = sctp_find_valid_localaddr_ep(stcb);
michael@0 2696
michael@0 2697 lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
michael@0 2698 if (found_addr != NULL) {
michael@0 2699 switch (found_addr->sa_family) {
michael@0 2700 #ifdef INET6
michael@0 2701 case AF_INET6:
michael@0 2702 /* copy IPv6 address */
michael@0 2703 lookup->ph.param_type =
michael@0 2704 htons(SCTP_IPV6_ADDRESS);
michael@0 2705 p_size = sizeof(struct sctp_ipv6addr_param);
michael@0 2706 addr_size = sizeof(struct in6_addr);
michael@0 2707 addr_ptr = (caddr_t)&((struct sockaddr_in6 *)
michael@0 2708 found_addr)->sin6_addr;
michael@0 2709 break;
michael@0 2710 #endif
michael@0 2711 #ifdef INET
michael@0 2712 case AF_INET:
michael@0 2713 /* copy IPv4 address */
michael@0 2714 lookup->ph.param_type =
michael@0 2715 htons(SCTP_IPV4_ADDRESS);
michael@0 2716 p_size = sizeof(struct sctp_ipv4addr_param);
michael@0 2717 addr_size = sizeof(struct in_addr);
michael@0 2718 addr_ptr = (caddr_t)&((struct sockaddr_in *)
michael@0 2719 found_addr)->sin_addr;
michael@0 2720 break;
michael@0 2721 #endif
michael@0 2722 default:
michael@0 2723 p_size = 0;
michael@0 2724 addr_size = 0;
michael@0 2725 addr_ptr = NULL;
michael@0 2726 break;
michael@0 2727 }
michael@0 2728 lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
michael@0 2729 memcpy(lookup->addr, addr_ptr, addr_size);
michael@0 2730 SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size);
michael@0 2731 } else {
michael@0 2732 /* uh oh... don't have any address?? */
michael@0 2733 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 2734 "compose_asconf: no lookup addr!\n");
michael@0 2735 /* XXX for now, we send a IPv4 address of 0.0.0.0 */
michael@0 2736 lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS);
michael@0 2737 lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)));
michael@0 2738 bzero(lookup->addr, sizeof(struct in_addr));
michael@0 2739 SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param));
michael@0 2740 }
michael@0 2741 }
michael@0 2742 /* chain it all together */
michael@0 2743 SCTP_BUF_NEXT(m_asconf_chk) = m_asconf;
michael@0 2744 *retlen = SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf);
michael@0 2745 acp->ch.chunk_length = htons(*retlen);
michael@0 2746
michael@0 2747 return (m_asconf_chk);
michael@0 2748 }
michael@0 2749
michael@0 2750 /*
michael@0 2751 * section to handle address changes before an association is up eg. changes
michael@0 2752 * during INIT/INIT-ACK/COOKIE-ECHO handshake
michael@0 2753 */
michael@0 2754
michael@0 2755 /*
michael@0 2756 * processes the (local) addresses in the INIT-ACK chunk
michael@0 2757 */
michael@0 2758 static void
michael@0 2759 sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
michael@0 2760 unsigned int offset, unsigned int length)
michael@0 2761 {
michael@0 2762 struct sctp_paramhdr tmp_param, *ph;
michael@0 2763 uint16_t plen, ptype;
michael@0 2764 struct sctp_ifa *sctp_ifa;
michael@0 2765 #ifdef INET6
michael@0 2766 struct sctp_ipv6addr_param addr6_store;
michael@0 2767 struct sockaddr_in6 sin6;
michael@0 2768 #endif
michael@0 2769 #ifdef INET
michael@0 2770 struct sctp_ipv4addr_param addr4_store;
michael@0 2771 struct sockaddr_in sin;
michael@0 2772 #endif
michael@0 2773 struct sockaddr *sa;
michael@0 2774 uint32_t vrf_id;
michael@0 2775
michael@0 2776 SCTPDBG(SCTP_DEBUG_ASCONF2, "processing init-ack addresses\n");
michael@0 2777 if (stcb == NULL) /* Un-needed check for SA */
michael@0 2778 return;
michael@0 2779
michael@0 2780 /* convert to upper bound */
michael@0 2781 length += offset;
michael@0 2782
michael@0 2783 if ((offset + sizeof(struct sctp_paramhdr)) > length) {
michael@0 2784 return;
michael@0 2785 }
michael@0 2786 /* init the addresses */
michael@0 2787 #ifdef INET6
michael@0 2788 bzero(&sin6, sizeof(sin6));
michael@0 2789 sin6.sin6_family = AF_INET6;
michael@0 2790 #ifdef HAVE_SIN6_LEN
michael@0 2791 sin6.sin6_len = sizeof(sin6);
michael@0 2792 #endif
michael@0 2793 sin6.sin6_port = stcb->rport;
michael@0 2794 #endif
michael@0 2795
michael@0 2796 #ifdef INET
michael@0 2797 bzero(&sin, sizeof(sin));
michael@0 2798 sin.sin_family = AF_INET;
michael@0 2799 #ifdef HAVE_SIN_LEN
michael@0 2800 sin.sin_len = sizeof(sin);
michael@0 2801 #endif
michael@0 2802 sin.sin_port = stcb->rport;
michael@0 2803 #endif
michael@0 2804
michael@0 2805 /* go through the addresses in the init-ack */
michael@0 2806 ph = (struct sctp_paramhdr *)
michael@0 2807 sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
michael@0 2808 (uint8_t *)&tmp_param);
michael@0 2809 while (ph != NULL) {
michael@0 2810 ptype = ntohs(ph->param_type);
michael@0 2811 plen = ntohs(ph->param_length);
michael@0 2812 switch (ptype) {
michael@0 2813 #ifdef INET6
michael@0 2814 case SCTP_IPV6_ADDRESS:
michael@0 2815 {
michael@0 2816 struct sctp_ipv6addr_param *a6p;
michael@0 2817
michael@0 2818 /* get the entire IPv6 address param */
michael@0 2819 a6p = (struct sctp_ipv6addr_param *)
michael@0 2820 sctp_m_getptr(m, offset,
michael@0 2821 sizeof(struct sctp_ipv6addr_param),
michael@0 2822 (uint8_t *)&addr6_store);
michael@0 2823 if (plen != sizeof(struct sctp_ipv6addr_param) ||
michael@0 2824 a6p == NULL) {
michael@0 2825 return;
michael@0 2826 }
michael@0 2827 memcpy(&sin6.sin6_addr, a6p->addr,
michael@0 2828 sizeof(struct in6_addr));
michael@0 2829 sa = (struct sockaddr *)&sin6;
michael@0 2830 break;
michael@0 2831 }
michael@0 2832 #endif
michael@0 2833 #ifdef INET
michael@0 2834 case SCTP_IPV4_ADDRESS:
michael@0 2835 {
michael@0 2836 struct sctp_ipv4addr_param *a4p;
michael@0 2837
michael@0 2838 /* get the entire IPv4 address param */
michael@0 2839 a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset,
michael@0 2840 sizeof(struct sctp_ipv4addr_param),
michael@0 2841 (uint8_t *)&addr4_store);
michael@0 2842 if (plen != sizeof(struct sctp_ipv4addr_param) ||
michael@0 2843 a4p == NULL) {
michael@0 2844 return;
michael@0 2845 }
michael@0 2846 sin.sin_addr.s_addr = a4p->addr;
michael@0 2847 sa = (struct sockaddr *)&sin;
michael@0 2848 break;
michael@0 2849 }
michael@0 2850 #endif
michael@0 2851 default:
michael@0 2852 goto next_addr;
michael@0 2853 }
michael@0 2854
michael@0 2855 /* see if this address really (still) exists */
michael@0 2856 if (stcb) {
michael@0 2857 vrf_id = stcb->asoc.vrf_id;
michael@0 2858 } else {
michael@0 2859 vrf_id = SCTP_DEFAULT_VRFID;
michael@0 2860 }
michael@0 2861 sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id,
michael@0 2862 SCTP_ADDR_NOT_LOCKED);
michael@0 2863 if (sctp_ifa == NULL) {
michael@0 2864 /* address doesn't exist anymore */
michael@0 2865 int status;
michael@0 2866
michael@0 2867 /* are ASCONFs allowed ? */
michael@0 2868 if ((sctp_is_feature_on(stcb->sctp_ep,
michael@0 2869 SCTP_PCB_FLAGS_DO_ASCONF)) &&
michael@0 2870 stcb->asoc.peer_supports_asconf) {
michael@0 2871 /* queue an ASCONF DEL_IP_ADDRESS */
michael@0 2872 status = sctp_asconf_queue_sa_delete(stcb, sa);
michael@0 2873 /*
michael@0 2874 * if queued ok, and in correct state, send
michael@0 2875 * out the ASCONF.
michael@0 2876 */
michael@0 2877 if (status == 0 &&
michael@0 2878 SCTP_GET_STATE(&stcb->asoc) ==
michael@0 2879 SCTP_STATE_OPEN) {
michael@0 2880 #ifdef SCTP_TIMER_BASED_ASCONF
michael@0 2881 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
michael@0 2882 stcb->sctp_ep, stcb,
michael@0 2883 stcb->asoc.primary_destination);
michael@0 2884 #else
michael@0 2885 sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
michael@0 2886 #endif
michael@0 2887 }
michael@0 2888 }
michael@0 2889 }
michael@0 2890
michael@0 2891 next_addr:
michael@0 2892 /*
michael@0 2893 * Sanity check: Make sure the length isn't 0, otherwise
michael@0 2894 * we'll be stuck in this loop for a long time...
michael@0 2895 */
michael@0 2896 if (SCTP_SIZE32(plen) == 0) {
michael@0 2897 SCTP_PRINTF("process_initack_addrs: bad len (%d) type=%xh\n",
michael@0 2898 plen, ptype);
michael@0 2899 return;
michael@0 2900 }
michael@0 2901 /* get next parameter */
michael@0 2902 offset += SCTP_SIZE32(plen);
michael@0 2903 if ((offset + sizeof(struct sctp_paramhdr)) > length)
michael@0 2904 return;
michael@0 2905 ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
michael@0 2906 sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
michael@0 2907 } /* while */
michael@0 2908 }
michael@0 2909
michael@0 2910 /* FIX ME: need to verify return result for v6 address type if v6 disabled */
michael@0 2911 /*
michael@0 2912 * checks to see if a specific address is in the initack address list returns
michael@0 2913 * 1 if found, 0 if not
michael@0 2914 */
michael@0 2915 static uint32_t
michael@0 2916 sctp_addr_in_initack(struct mbuf *m, uint32_t offset, uint32_t length, struct sockaddr *sa)
michael@0 2917 {
michael@0 2918 struct sctp_paramhdr tmp_param, *ph;
michael@0 2919 uint16_t plen, ptype;
michael@0 2920 #ifdef INET
michael@0 2921 struct sockaddr_in *sin;
michael@0 2922 struct sctp_ipv4addr_param *a4p;
michael@0 2923 struct sctp_ipv6addr_param addr4_store;
michael@0 2924 #endif
michael@0 2925 #ifdef INET6
michael@0 2926 struct sockaddr_in6 *sin6;
michael@0 2927 struct sctp_ipv6addr_param *a6p;
michael@0 2928 struct sctp_ipv6addr_param addr6_store;
michael@0 2929 #ifdef SCTP_EMBEDDED_V6_SCOPE
michael@0 2930 struct sockaddr_in6 sin6_tmp;
michael@0 2931 #endif
michael@0 2932 #endif
michael@0 2933
michael@0 2934 switch (sa->sa_family) {
michael@0 2935 #ifdef INET
michael@0 2936 case AF_INET:
michael@0 2937 break;
michael@0 2938 #endif
michael@0 2939 #ifdef INET6
michael@0 2940 case AF_INET6:
michael@0 2941 break;
michael@0 2942 #endif
michael@0 2943 default:
michael@0 2944 return (0);
michael@0 2945 }
michael@0 2946
michael@0 2947 SCTPDBG(SCTP_DEBUG_ASCONF2, "find_initack_addr: starting search for ");
michael@0 2948 SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
michael@0 2949 /* convert to upper bound */
michael@0 2950 length += offset;
michael@0 2951
michael@0 2952 if ((offset + sizeof(struct sctp_paramhdr)) > length) {
michael@0 2953 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 2954 "find_initack_addr: invalid offset?\n");
michael@0 2955 return (0);
michael@0 2956 }
michael@0 2957 /* go through the addresses in the init-ack */
michael@0 2958 ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
michael@0 2959 sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
michael@0 2960 while (ph != NULL) {
michael@0 2961 ptype = ntohs(ph->param_type);
michael@0 2962 plen = ntohs(ph->param_length);
michael@0 2963 switch (ptype) {
michael@0 2964 #ifdef INET6
michael@0 2965 case SCTP_IPV6_ADDRESS:
michael@0 2966 if (sa->sa_family == AF_INET6) {
michael@0 2967 /* get the entire IPv6 address param */
michael@0 2968 if (plen != sizeof(struct sctp_ipv6addr_param)) {
michael@0 2969 break;
michael@0 2970 }
michael@0 2971 /* get the entire IPv6 address param */
michael@0 2972 a6p = (struct sctp_ipv6addr_param *)
michael@0 2973 sctp_m_getptr(m, offset,
michael@0 2974 sizeof(struct sctp_ipv6addr_param),
michael@0 2975 (uint8_t *)&addr6_store);
michael@0 2976 if (a6p == NULL) {
michael@0 2977 return (0);
michael@0 2978 }
michael@0 2979 sin6 = (struct sockaddr_in6 *)sa;
michael@0 2980 #ifdef SCTP_EMBEDDED_V6_SCOPE
michael@0 2981 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
michael@0 2982 /* create a copy and clear scope */
michael@0 2983 memcpy(&sin6_tmp, sin6,
michael@0 2984 sizeof(struct sockaddr_in6));
michael@0 2985 sin6 = &sin6_tmp;
michael@0 2986 in6_clearscope(&sin6->sin6_addr);
michael@0 2987 }
michael@0 2988 #endif /* SCTP_EMBEDDED_V6_SCOPE */
michael@0 2989 if (memcmp(&sin6->sin6_addr, a6p->addr,
michael@0 2990 sizeof(struct in6_addr)) == 0) {
michael@0 2991 /* found it */
michael@0 2992 return (1);
michael@0 2993 }
michael@0 2994 }
michael@0 2995 break;
michael@0 2996 #endif /* INET6 */
michael@0 2997 #ifdef INET
michael@0 2998 case SCTP_IPV4_ADDRESS:
michael@0 2999 if (sa->sa_family == AF_INET) {
michael@0 3000 if (plen != sizeof(struct sctp_ipv4addr_param)) {
michael@0 3001 break;
michael@0 3002 }
michael@0 3003 /* get the entire IPv4 address param */
michael@0 3004 a4p = (struct sctp_ipv4addr_param *)
michael@0 3005 sctp_m_getptr(m, offset,
michael@0 3006 sizeof(struct sctp_ipv4addr_param),
michael@0 3007 (uint8_t *)&addr4_store);
michael@0 3008 if (a4p == NULL) {
michael@0 3009 return (0);
michael@0 3010 }
michael@0 3011 sin = (struct sockaddr_in *)sa;
michael@0 3012 if (sin->sin_addr.s_addr == a4p->addr) {
michael@0 3013 /* found it */
michael@0 3014 return (1);
michael@0 3015 }
michael@0 3016 }
michael@0 3017 break;
michael@0 3018 #endif
michael@0 3019 default:
michael@0 3020 break;
michael@0 3021 }
michael@0 3022 /* get next parameter */
michael@0 3023 offset += SCTP_SIZE32(plen);
michael@0 3024 if (offset + sizeof(struct sctp_paramhdr) > length) {
michael@0 3025 return (0);
michael@0 3026 }
michael@0 3027 ph = (struct sctp_paramhdr *)
michael@0 3028 sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
michael@0 3029 (uint8_t *) & tmp_param);
michael@0 3030 } /* while */
michael@0 3031 /* not found! */
michael@0 3032 return (0);
michael@0 3033 }
michael@0 3034
michael@0 3035 /*
michael@0 3036 * makes sure that the current endpoint local addr list is consistent with
michael@0 3037 * the new association (eg. subset bound, asconf allowed) adds addresses as
michael@0 3038 * necessary
michael@0 3039 */
michael@0 3040 static void
michael@0 3041 sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
michael@0 3042 int length, struct sockaddr *init_addr)
michael@0 3043 {
michael@0 3044 struct sctp_laddr *laddr;
michael@0 3045
michael@0 3046 /* go through the endpoint list */
michael@0 3047 LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
michael@0 3048 /* be paranoid and validate the laddr */
michael@0 3049 if (laddr->ifa == NULL) {
michael@0 3050 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 3051 "check_addr_list_ep: laddr->ifa is NULL");
michael@0 3052 continue;
michael@0 3053 }
michael@0 3054 if (laddr->ifa == NULL) {
michael@0 3055 SCTPDBG(SCTP_DEBUG_ASCONF1, "check_addr_list_ep: laddr->ifa->ifa_addr is NULL");
michael@0 3056 continue;
michael@0 3057 }
michael@0 3058 /* do i have it implicitly? */
michael@0 3059 if (sctp_cmpaddr(&laddr->ifa->address.sa, init_addr)) {
michael@0 3060 continue;
michael@0 3061 }
michael@0 3062 /* check to see if in the init-ack */
michael@0 3063 if (!sctp_addr_in_initack(m, offset, length, &laddr->ifa->address.sa)) {
michael@0 3064 /* try to add it */
michael@0 3065 sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa,
michael@0 3066 SCTP_ADD_IP_ADDRESS, SCTP_ADDR_NOT_LOCKED);
michael@0 3067 }
michael@0 3068 }
michael@0 3069 }
michael@0 3070
michael@0 3071 /*
michael@0 3072 * makes sure that the current kernel address list is consistent with the new
michael@0 3073 * association (with all addrs bound) adds addresses as necessary
michael@0 3074 */
michael@0 3075 static void
michael@0 3076 sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
michael@0 3077 int length, struct sockaddr *init_addr,
michael@0 3078 uint16_t local_scope, uint16_t site_scope,
michael@0 3079 uint16_t ipv4_scope, uint16_t loopback_scope)
michael@0 3080 {
michael@0 3081 struct sctp_vrf *vrf = NULL;
michael@0 3082 struct sctp_ifn *sctp_ifn;
michael@0 3083 struct sctp_ifa *sctp_ifa;
michael@0 3084 uint32_t vrf_id;
michael@0 3085 #ifdef INET
michael@0 3086 struct sockaddr_in *sin;
michael@0 3087 #endif
michael@0 3088 #ifdef INET6
michael@0 3089 struct sockaddr_in6 *sin6;
michael@0 3090 #endif
michael@0 3091
michael@0 3092 if (stcb) {
michael@0 3093 vrf_id = stcb->asoc.vrf_id;
michael@0 3094 } else {
michael@0 3095 return;
michael@0 3096 }
michael@0 3097 SCTP_IPI_ADDR_RLOCK();
michael@0 3098 vrf = sctp_find_vrf(vrf_id);
michael@0 3099 if (vrf == NULL) {
michael@0 3100 SCTP_IPI_ADDR_RUNLOCK();
michael@0 3101 return;
michael@0 3102 }
michael@0 3103 /* go through all our known interfaces */
michael@0 3104 LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
michael@0 3105 if (loopback_scope == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
michael@0 3106 /* skip loopback interface */
michael@0 3107 continue;
michael@0 3108 }
michael@0 3109 /* go through each interface address */
michael@0 3110 LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
michael@0 3111 /* do i have it implicitly? */
michael@0 3112 if (sctp_cmpaddr(&sctp_ifa->address.sa, init_addr)) {
michael@0 3113 continue;
michael@0 3114 }
michael@0 3115 switch (sctp_ifa->address.sa.sa_family) {
michael@0 3116 #ifdef INET
michael@0 3117 case AF_INET:
michael@0 3118 sin = (struct sockaddr_in *)&sctp_ifa->address.sin;
michael@0 3119 if ((ipv4_scope == 0) &&
michael@0 3120 (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
michael@0 3121 /* private address not in scope */
michael@0 3122 continue;
michael@0 3123 }
michael@0 3124 break;
michael@0 3125 #endif
michael@0 3126 #ifdef INET6
michael@0 3127 case AF_INET6:
michael@0 3128 sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sin6;
michael@0 3129 if ((local_scope == 0) &&
michael@0 3130 (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
michael@0 3131 continue;
michael@0 3132 }
michael@0 3133 if ((site_scope == 0) &&
michael@0 3134 (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
michael@0 3135 continue;
michael@0 3136 }
michael@0 3137 break;
michael@0 3138 #endif
michael@0 3139 default:
michael@0 3140 break;
michael@0 3141 }
michael@0 3142 /* check to see if in the init-ack */
michael@0 3143 if (!sctp_addr_in_initack(m, offset, length, &sctp_ifa->address.sa)) {
michael@0 3144 /* try to add it */
michael@0 3145 sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb,
michael@0 3146 sctp_ifa, SCTP_ADD_IP_ADDRESS,
michael@0 3147 SCTP_ADDR_LOCKED);
michael@0 3148 }
michael@0 3149 } /* end foreach ifa */
michael@0 3150 } /* end foreach ifn */
michael@0 3151 SCTP_IPI_ADDR_RUNLOCK();
michael@0 3152 }
michael@0 3153
michael@0 3154 /*
michael@0 3155 * validates an init-ack chunk (from a cookie-echo) with current addresses
michael@0 3156 * adds addresses from the init-ack into our local address list, if needed
michael@0 3157 * queues asconf adds/deletes addresses as needed and makes appropriate list
michael@0 3158 * changes for source address selection m, offset: points to the start of the
michael@0 3159 * address list in an init-ack chunk length: total length of the address
michael@0 3160 * params only init_addr: address where my INIT-ACK was sent from
michael@0 3161 */
michael@0 3162 void
michael@0 3163 sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset,
michael@0 3164 int length, struct sockaddr *init_addr,
michael@0 3165 uint16_t local_scope, uint16_t site_scope,
michael@0 3166 uint16_t ipv4_scope, uint16_t loopback_scope)
michael@0 3167 {
michael@0 3168 /* process the local addresses in the initack */
michael@0 3169 sctp_process_initack_addresses(stcb, m, offset, length);
michael@0 3170
michael@0 3171 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
michael@0 3172 /* bound all case */
michael@0 3173 sctp_check_address_list_all(stcb, m, offset, length, init_addr,
michael@0 3174 local_scope, site_scope, ipv4_scope, loopback_scope);
michael@0 3175 } else {
michael@0 3176 /* subset bound case */
michael@0 3177 if (sctp_is_feature_on(stcb->sctp_ep,
michael@0 3178 SCTP_PCB_FLAGS_DO_ASCONF)) {
michael@0 3179 /* asconf's allowed */
michael@0 3180 sctp_check_address_list_ep(stcb, m, offset, length,
michael@0 3181 init_addr);
michael@0 3182 }
michael@0 3183 /* else, no asconfs allowed, so what we sent is what we get */
michael@0 3184 }
michael@0 3185 }
michael@0 3186
michael@0 3187 /*
michael@0 3188 * sctp_bindx() support
michael@0 3189 */
michael@0 3190 uint32_t
michael@0 3191 sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
michael@0 3192 uint32_t type, uint32_t vrf_id, struct sctp_ifa *sctp_ifap)
michael@0 3193 {
michael@0 3194 struct sctp_ifa *ifa;
michael@0 3195 struct sctp_laddr *laddr, *nladdr;
michael@0 3196
michael@0 3197 #ifdef HAVE_SA_LEN
michael@0 3198 if (sa->sa_len == 0) {
michael@0 3199 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
michael@0 3200 return (EINVAL);
michael@0 3201 }
michael@0 3202 #endif
michael@0 3203 if (sctp_ifap) {
michael@0 3204 ifa = sctp_ifap;
michael@0 3205 } else if (type == SCTP_ADD_IP_ADDRESS) {
michael@0 3206 /* For an add the address MUST be on the system */
michael@0 3207 ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
michael@0 3208 } else if (type == SCTP_DEL_IP_ADDRESS) {
michael@0 3209 /* For a delete we need to find it in the inp */
michael@0 3210 ifa = sctp_find_ifa_in_ep(inp, sa, SCTP_ADDR_NOT_LOCKED);
michael@0 3211 } else {
michael@0 3212 ifa = NULL;
michael@0 3213 }
michael@0 3214 if (ifa != NULL) {
michael@0 3215 if (type == SCTP_ADD_IP_ADDRESS) {
michael@0 3216 sctp_add_local_addr_ep(inp, ifa, type);
michael@0 3217 } else if (type == SCTP_DEL_IP_ADDRESS) {
michael@0 3218 if (inp->laddr_count < 2) {
michael@0 3219 /* can't delete the last local address */
michael@0 3220 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
michael@0 3221 return (EINVAL);
michael@0 3222 }
michael@0 3223 LIST_FOREACH(laddr, &inp->sctp_addr_list,
michael@0 3224 sctp_nxt_addr) {
michael@0 3225 if (ifa == laddr->ifa) {
michael@0 3226 /* Mark in the delete */
michael@0 3227 laddr->action = type;
michael@0 3228 }
michael@0 3229 }
michael@0 3230 }
michael@0 3231 if (LIST_EMPTY(&inp->sctp_asoc_list)) {
michael@0 3232 /*
michael@0 3233 * There is no need to start the iterator if
michael@0 3234 * the inp has no associations.
michael@0 3235 */
michael@0 3236 if (type == SCTP_DEL_IP_ADDRESS) {
michael@0 3237 LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
michael@0 3238 if (laddr->ifa == ifa) {
michael@0 3239 sctp_del_local_addr_ep(inp, ifa);
michael@0 3240 }
michael@0 3241 }
michael@0 3242 }
michael@0 3243 } else {
michael@0 3244 struct sctp_asconf_iterator *asc;
michael@0 3245 struct sctp_laddr *wi;
michael@0 3246
michael@0 3247 SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
michael@0 3248 sizeof(struct sctp_asconf_iterator),
michael@0 3249 SCTP_M_ASC_IT);
michael@0 3250 if (asc == NULL) {
michael@0 3251 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
michael@0 3252 return (ENOMEM);
michael@0 3253 }
michael@0 3254 wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
michael@0 3255 if (wi == NULL) {
michael@0 3256 SCTP_FREE(asc, SCTP_M_ASC_IT);
michael@0 3257 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
michael@0 3258 return (ENOMEM);
michael@0 3259 }
michael@0 3260 LIST_INIT(&asc->list_of_work);
michael@0 3261 asc->cnt = 1;
michael@0 3262 SCTP_INCR_LADDR_COUNT();
michael@0 3263 wi->ifa = ifa;
michael@0 3264 wi->action = type;
michael@0 3265 atomic_add_int(&ifa->refcount, 1);
michael@0 3266 LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
michael@0 3267 (void)sctp_initiate_iterator(sctp_asconf_iterator_ep,
michael@0 3268 sctp_asconf_iterator_stcb,
michael@0 3269 sctp_asconf_iterator_ep_end,
michael@0 3270 SCTP_PCB_ANY_FLAGS,
michael@0 3271 SCTP_PCB_ANY_FEATURES,
michael@0 3272 SCTP_ASOC_ANY_STATE,
michael@0 3273 (void *)asc, 0,
michael@0 3274 sctp_asconf_iterator_end, inp, 0);
michael@0 3275 }
michael@0 3276 return (0);
michael@0 3277 } else {
michael@0 3278 /* invalid address! */
michael@0 3279 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EADDRNOTAVAIL);
michael@0 3280 return (EADDRNOTAVAIL);
michael@0 3281 }
michael@0 3282 }
michael@0 3283
michael@0 3284 void
michael@0 3285 sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
michael@0 3286 struct sctp_nets *net)
michael@0 3287 {
michael@0 3288 struct sctp_asconf_addr *aa;
michael@0 3289 struct sctp_ifa *sctp_ifap;
michael@0 3290 struct sctp_asconf_tag_param *vtag;
michael@0 3291 #ifdef INET
michael@0 3292 struct sockaddr_in *to;
michael@0 3293 #endif
michael@0 3294 #ifdef INET6
michael@0 3295 struct sockaddr_in6 *to6;
michael@0 3296 #endif
michael@0 3297 if (net == NULL) {
michael@0 3298 SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n");
michael@0 3299 return;
michael@0 3300 }
michael@0 3301 if (stcb == NULL) {
michael@0 3302 SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing stcb\n");
michael@0 3303 return;
michael@0 3304 }
michael@0 3305 /* Need to have in the asconf:
michael@0 3306 * - vtagparam(my_vtag/peer_vtag)
michael@0 3307 * - add(0.0.0.0)
michael@0 3308 * - del(0.0.0.0)
michael@0 3309 * - Any global addresses add(addr)
michael@0 3310 */
michael@0 3311 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
michael@0 3312 SCTP_M_ASC_ADDR);
michael@0 3313 if (aa == NULL) {
michael@0 3314 /* didn't get memory */
michael@0 3315 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 3316 "sctp_asconf_send_nat_state_update: failed to get memory!\n");
michael@0 3317 return;
michael@0 3318 }
michael@0 3319 aa->special_del = 0;
michael@0 3320 /* fill in asconf address parameter fields */
michael@0 3321 /* top level elements are "networked" during send */
michael@0 3322 aa->ifa = NULL;
michael@0 3323 aa->sent = 0; /* clear sent flag */
michael@0 3324 vtag = (struct sctp_asconf_tag_param *)&aa->ap.aph;
michael@0 3325 vtag->aph.ph.param_type = SCTP_NAT_VTAGS;
michael@0 3326 vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param);
michael@0 3327 vtag->local_vtag = htonl(stcb->asoc.my_vtag);
michael@0 3328 vtag->remote_vtag = htonl(stcb->asoc.peer_vtag);
michael@0 3329 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
michael@0 3330
michael@0 3331 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
michael@0 3332 SCTP_M_ASC_ADDR);
michael@0 3333 if (aa == NULL) {
michael@0 3334 /* didn't get memory */
michael@0 3335 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 3336 "sctp_asconf_send_nat_state_update: failed to get memory!\n");
michael@0 3337 return;
michael@0 3338 }
michael@0 3339 memset(aa, 0, sizeof(struct sctp_asconf_addr));
michael@0 3340 /* fill in asconf address parameter fields */
michael@0 3341 /* ADD(0.0.0.0) */
michael@0 3342 switch (net->ro._l_addr.sa.sa_family) {
michael@0 3343 #ifdef INET
michael@0 3344 case AF_INET:
michael@0 3345 aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
michael@0 3346 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
michael@0 3347 aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
michael@0 3348 aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
michael@0 3349 /* No need to add an address, we are using 0.0.0.0 */
michael@0 3350 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
michael@0 3351 break;
michael@0 3352 #endif
michael@0 3353 #ifdef INET6
michael@0 3354 case AF_INET6:
michael@0 3355 aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
michael@0 3356 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
michael@0 3357 aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
michael@0 3358 aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
michael@0 3359 /* No need to add an address, we are using 0.0.0.0 */
michael@0 3360 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
michael@0 3361 break;
michael@0 3362 #endif
michael@0 3363 }
michael@0 3364 SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
michael@0 3365 SCTP_M_ASC_ADDR);
michael@0 3366 if (aa == NULL) {
michael@0 3367 /* didn't get memory */
michael@0 3368 SCTPDBG(SCTP_DEBUG_ASCONF1,
michael@0 3369 "sctp_asconf_send_nat_state_update: failed to get memory!\n");
michael@0 3370 return;
michael@0 3371 }
michael@0 3372 memset(aa, 0, sizeof(struct sctp_asconf_addr));
michael@0 3373 /* fill in asconf address parameter fields */
michael@0 3374 /* ADD(0.0.0.0) */
michael@0 3375 switch (net->ro._l_addr.sa.sa_family) {
michael@0 3376 #ifdef INET
michael@0 3377 case AF_INET:
michael@0 3378 aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
michael@0 3379 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
michael@0 3380 aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
michael@0 3381 aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
michael@0 3382 /* No need to add an address, we are using 0.0.0.0 */
michael@0 3383 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
michael@0 3384 break;
michael@0 3385 #endif
michael@0 3386 #ifdef INET6
michael@0 3387 case AF_INET6:
michael@0 3388 aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
michael@0 3389 aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
michael@0 3390 aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
michael@0 3391 aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
michael@0 3392 /* No need to add an address, we are using 0.0.0.0 */
michael@0 3393 TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
michael@0 3394 break;
michael@0 3395 #endif
michael@0 3396 }
michael@0 3397 /* Now we must hunt the addresses and add all global addresses */
michael@0 3398 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
michael@0 3399 struct sctp_vrf *vrf = NULL;
michael@0 3400 struct sctp_ifn *sctp_ifnp;
michael@0 3401 uint32_t vrf_id;
michael@0 3402
michael@0 3403 vrf_id = stcb->sctp_ep->def_vrf_id;
michael@0 3404 vrf = sctp_find_vrf(vrf_id);
michael@0 3405 if (vrf == NULL) {
michael@0 3406 goto skip_rest;
michael@0 3407 }
michael@0 3408
michael@0 3409 SCTP_IPI_ADDR_RLOCK();
michael@0 3410 LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
michael@0 3411 LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
michael@0 3412 switch (sctp_ifap->address.sa.sa_family) {
michael@0 3413 #ifdef INET
michael@0 3414 case AF_INET:
michael@0 3415 to = &sctp_ifap->address.sin;
michael@0 3416 if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
michael@0 3417 continue;
michael@0 3418 }
michael@0 3419 if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
michael@0 3420 continue;
michael@0 3421 }
michael@0 3422 break;
michael@0 3423 #endif
michael@0 3424 #ifdef INET6
michael@0 3425 case AF_INET6:
michael@0 3426 to6 = &sctp_ifap->address.sin6;
michael@0 3427 if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
michael@0 3428 continue;
michael@0 3429 }
michael@0 3430 if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
michael@0 3431 continue;
michael@0 3432 }
michael@0 3433 break;
michael@0 3434 #endif
michael@0 3435 default:
michael@0 3436 continue;
michael@0 3437 }
michael@0 3438 sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
michael@0 3439 }
michael@0 3440 }
michael@0 3441 SCTP_IPI_ADDR_RUNLOCK();
michael@0 3442 } else {
michael@0 3443 struct sctp_laddr *laddr;
michael@0 3444
michael@0 3445 LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
michael@0 3446 if (laddr->ifa == NULL) {
michael@0 3447 continue;
michael@0 3448 }
michael@0 3449 if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
michael@0 3450 /* Address being deleted by the system, dont
michael@0 3451 * list.
michael@0 3452 */
michael@0 3453 continue;
michael@0 3454 if (laddr->action == SCTP_DEL_IP_ADDRESS) {
michael@0 3455 /* Address being deleted on this ep
michael@0 3456 * don't list.
michael@0 3457 */
michael@0 3458 continue;
michael@0 3459 }
michael@0 3460 sctp_ifap = laddr->ifa;
michael@0 3461 switch (sctp_ifap->address.sa.sa_family) {
michael@0 3462 #ifdef INET
michael@0 3463 case AF_INET:
michael@0 3464 to = &sctp_ifap->address.sin;
michael@0 3465 if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
michael@0 3466 continue;
michael@0 3467 }
michael@0 3468 if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
michael@0 3469 continue;
michael@0 3470 }
michael@0 3471 break;
michael@0 3472 #endif
michael@0 3473 #ifdef INET6
michael@0 3474 case AF_INET6:
michael@0 3475 to6 = &sctp_ifap->address.sin6;
michael@0 3476 if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
michael@0 3477 continue;
michael@0 3478 }
michael@0 3479 if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
michael@0 3480 continue;
michael@0 3481 }
michael@0 3482 break;
michael@0 3483 #endif
michael@0 3484 default:
michael@0 3485 continue;
michael@0 3486 }
michael@0 3487 sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
michael@0 3488 }
michael@0 3489 }
michael@0 3490 skip_rest:
michael@0 3491 /* Now we must send the asconf into the queue */
michael@0 3492 sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
michael@0 3493 }

mercurial