/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
* Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* a) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* b) Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
*
* c) Neither the name of Cisco Systems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <netinet/sctp_os.h>
#include <sys/proc.h>
#include <netinet/sctp_var.h>
#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_header.h>
#include <netinet/sctp_pcb.h>
#include <netinet/sctputil.h>
#include <netinet/sctp_output.h>
#include <netinet/sctp_uio.h>
#include <netinet/sctputil.h>
#include <netinet/sctp_auth.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_indata.h>
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_input.h>
#include <netinet/sctp_crc32.h>
#include <netinet/sctp_kdtrace.h>
#if defined(INET) || defined(INET6)
#include <netinet/udp.h>
#endif
#include <netinet/udp_var.h>
#include <machine/in_cksum.h>
#define SCTP_MAX_GAPS_INARRAY 4
struct sack_track {
uint8_t right_edge; /* mergable on the right edge */
uint8_t left_edge; /* mergable on the left edge */
uint8_t num_entries;
uint8_t spare;
struct sctp_gap_ack_block gaps[SCTP_MAX_GAPS_INARRAY];
};
const struct sack_track sack_array[256] = {
{0, 0, 0, 0, /* 0x00 */
{{0, 0},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 1, 0, /* 0x01 */
{{0, 0},
{0, 0},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x02 */
{{1, 1},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 1, 0, /* 0x03 */
{{0, 1},
{0, 0},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x04 */
{{2, 2},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x05 */
{{0, 0},
{2, 2},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x06 */
{{1, 2},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 1, 0, /* 0x07 */
{{0, 2},
{0, 0},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x08 */
{{3, 3},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x09 */
{{0, 0},
{3, 3},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x0a */
{{1, 1},
{3, 3},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x0b */
{{0, 1},
{3, 3},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x0c */
{{2, 3},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x0d */
{{0, 0},
{2, 3},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x0e */
{{1, 3},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 1, 0, /* 0x0f */
{{0, 3},
{0, 0},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x10 */
{{4, 4},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x11 */
{{0, 0},
{4, 4},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x12 */
{{1, 1},
{4, 4},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x13 */
{{0, 1},
{4, 4},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x14 */
{{2, 2},
{4, 4},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x15 */
{{0, 0},
{2, 2},
{4, 4},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x16 */
{{1, 2},
{4, 4},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x17 */
{{0, 2},
{4, 4},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x18 */
{{3, 4},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x19 */
{{0, 0},
{3, 4},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x1a */
{{1, 1},
{3, 4},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x1b */
{{0, 1},
{3, 4},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x1c */
{{2, 4},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x1d */
{{0, 0},
{2, 4},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x1e */
{{1, 4},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 1, 0, /* 0x1f */
{{0, 4},
{0, 0},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x20 */
{{5, 5},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x21 */
{{0, 0},
{5, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x22 */
{{1, 1},
{5, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x23 */
{{0, 1},
{5, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x24 */
{{2, 2},
{5, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x25 */
{{0, 0},
{2, 2},
{5, 5},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x26 */
{{1, 2},
{5, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x27 */
{{0, 2},
{5, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x28 */
{{3, 3},
{5, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x29 */
{{0, 0},
{3, 3},
{5, 5},
{0, 0}
}
},
{0, 0, 3, 0, /* 0x2a */
{{1, 1},
{3, 3},
{5, 5},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x2b */
{{0, 1},
{3, 3},
{5, 5},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x2c */
{{2, 3},
{5, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x2d */
{{0, 0},
{2, 3},
{5, 5},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x2e */
{{1, 3},
{5, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x2f */
{{0, 3},
{5, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x30 */
{{4, 5},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x31 */
{{0, 0},
{4, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x32 */
{{1, 1},
{4, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x33 */
{{0, 1},
{4, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x34 */
{{2, 2},
{4, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x35 */
{{0, 0},
{2, 2},
{4, 5},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x36 */
{{1, 2},
{4, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x37 */
{{0, 2},
{4, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x38 */
{{3, 5},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x39 */
{{0, 0},
{3, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x3a */
{{1, 1},
{3, 5},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x3b */
{{0, 1},
{3, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x3c */
{{2, 5},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x3d */
{{0, 0},
{2, 5},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x3e */
{{1, 5},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 1, 0, /* 0x3f */
{{0, 5},
{0, 0},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x40 */
{{6, 6},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x41 */
{{0, 0},
{6, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x42 */
{{1, 1},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x43 */
{{0, 1},
{6, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x44 */
{{2, 2},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x45 */
{{0, 0},
{2, 2},
{6, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x46 */
{{1, 2},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x47 */
{{0, 2},
{6, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x48 */
{{3, 3},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x49 */
{{0, 0},
{3, 3},
{6, 6},
{0, 0}
}
},
{0, 0, 3, 0, /* 0x4a */
{{1, 1},
{3, 3},
{6, 6},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x4b */
{{0, 1},
{3, 3},
{6, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x4c */
{{2, 3},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x4d */
{{0, 0},
{2, 3},
{6, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x4e */
{{1, 3},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x4f */
{{0, 3},
{6, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x50 */
{{4, 4},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x51 */
{{0, 0},
{4, 4},
{6, 6},
{0, 0}
}
},
{0, 0, 3, 0, /* 0x52 */
{{1, 1},
{4, 4},
{6, 6},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x53 */
{{0, 1},
{4, 4},
{6, 6},
{0, 0}
}
},
{0, 0, 3, 0, /* 0x54 */
{{2, 2},
{4, 4},
{6, 6},
{0, 0}
}
},
{1, 0, 4, 0, /* 0x55 */
{{0, 0},
{2, 2},
{4, 4},
{6, 6}
}
},
{0, 0, 3, 0, /* 0x56 */
{{1, 2},
{4, 4},
{6, 6},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x57 */
{{0, 2},
{4, 4},
{6, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x58 */
{{3, 4},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x59 */
{{0, 0},
{3, 4},
{6, 6},
{0, 0}
}
},
{0, 0, 3, 0, /* 0x5a */
{{1, 1},
{3, 4},
{6, 6},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x5b */
{{0, 1},
{3, 4},
{6, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x5c */
{{2, 4},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x5d */
{{0, 0},
{2, 4},
{6, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x5e */
{{1, 4},
{6, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x5f */
{{0, 4},
{6, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x60 */
{{5, 6},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x61 */
{{0, 0},
{5, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x62 */
{{1, 1},
{5, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x63 */
{{0, 1},
{5, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x64 */
{{2, 2},
{5, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x65 */
{{0, 0},
{2, 2},
{5, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x66 */
{{1, 2},
{5, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x67 */
{{0, 2},
{5, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x68 */
{{3, 3},
{5, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x69 */
{{0, 0},
{3, 3},
{5, 6},
{0, 0}
}
},
{0, 0, 3, 0, /* 0x6a */
{{1, 1},
{3, 3},
{5, 6},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x6b */
{{0, 1},
{3, 3},
{5, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x6c */
{{2, 3},
{5, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x6d */
{{0, 0},
{2, 3},
{5, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x6e */
{{1, 3},
{5, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x6f */
{{0, 3},
{5, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x70 */
{{4, 6},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x71 */
{{0, 0},
{4, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x72 */
{{1, 1},
{4, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x73 */
{{0, 1},
{4, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x74 */
{{2, 2},
{4, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 3, 0, /* 0x75 */
{{0, 0},
{2, 2},
{4, 6},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x76 */
{{1, 2},
{4, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x77 */
{{0, 2},
{4, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x78 */
{{3, 6},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x79 */
{{0, 0},
{3, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 2, 0, /* 0x7a */
{{1, 1},
{3, 6},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x7b */
{{0, 1},
{3, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x7c */
{{2, 6},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 2, 0, /* 0x7d */
{{0, 0},
{2, 6},
{0, 0},
{0, 0}
}
},
{0, 0, 1, 0, /* 0x7e */
{{1, 6},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 0, 1, 0, /* 0x7f */
{{0, 6},
{0, 0},
{0, 0},
{0, 0}
}
},
{0, 1, 1, 0, /* 0x80 */
{{7, 7},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0x81 */
{{0, 0},
{7, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x82 */
{{1, 1},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0x83 */
{{0, 1},
{7, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x84 */
{{2, 2},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x85 */
{{0, 0},
{2, 2},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x86 */
{{1, 2},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0x87 */
{{0, 2},
{7, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x88 */
{{3, 3},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x89 */
{{0, 0},
{3, 3},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0x8a */
{{1, 1},
{3, 3},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x8b */
{{0, 1},
{3, 3},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x8c */
{{2, 3},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x8d */
{{0, 0},
{2, 3},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x8e */
{{1, 3},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0x8f */
{{0, 3},
{7, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x90 */
{{4, 4},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x91 */
{{0, 0},
{4, 4},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0x92 */
{{1, 1},
{4, 4},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x93 */
{{0, 1},
{4, 4},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0x94 */
{{2, 2},
{4, 4},
{7, 7},
{0, 0}
}
},
{1, 1, 4, 0, /* 0x95 */
{{0, 0},
{2, 2},
{4, 4},
{7, 7}
}
},
{0, 1, 3, 0, /* 0x96 */
{{1, 2},
{4, 4},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x97 */
{{0, 2},
{4, 4},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x98 */
{{3, 4},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x99 */
{{0, 0},
{3, 4},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0x9a */
{{1, 1},
{3, 4},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x9b */
{{0, 1},
{3, 4},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x9c */
{{2, 4},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0x9d */
{{0, 0},
{2, 4},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0x9e */
{{1, 4},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0x9f */
{{0, 4},
{7, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xa0 */
{{5, 5},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xa1 */
{{0, 0},
{5, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xa2 */
{{1, 1},
{5, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xa3 */
{{0, 1},
{5, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xa4 */
{{2, 2},
{5, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 4, 0, /* 0xa5 */
{{0, 0},
{2, 2},
{5, 5},
{7, 7}
}
},
{0, 1, 3, 0, /* 0xa6 */
{{1, 2},
{5, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xa7 */
{{0, 2},
{5, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xa8 */
{{3, 3},
{5, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 4, 0, /* 0xa9 */
{{0, 0},
{3, 3},
{5, 5},
{7, 7}
}
},
{0, 1, 4, 0, /* 0xaa */
{{1, 1},
{3, 3},
{5, 5},
{7, 7}
}
},
{1, 1, 4, 0, /* 0xab */
{{0, 1},
{3, 3},
{5, 5},
{7, 7}
}
},
{0, 1, 3, 0, /* 0xac */
{{2, 3},
{5, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 4, 0, /* 0xad */
{{0, 0},
{2, 3},
{5, 5},
{7, 7}
}
},
{0, 1, 3, 0, /* 0xae */
{{1, 3},
{5, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xaf */
{{0, 3},
{5, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xb0 */
{{4, 5},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xb1 */
{{0, 0},
{4, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xb2 */
{{1, 1},
{4, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xb3 */
{{0, 1},
{4, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xb4 */
{{2, 2},
{4, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 4, 0, /* 0xb5 */
{{0, 0},
{2, 2},
{4, 5},
{7, 7}
}
},
{0, 1, 3, 0, /* 0xb6 */
{{1, 2},
{4, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xb7 */
{{0, 2},
{4, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xb8 */
{{3, 5},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xb9 */
{{0, 0},
{3, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xba */
{{1, 1},
{3, 5},
{7, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xbb */
{{0, 1},
{3, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xbc */
{{2, 5},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xbd */
{{0, 0},
{2, 5},
{7, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xbe */
{{1, 5},
{7, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xbf */
{{0, 5},
{7, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 1, 0, /* 0xc0 */
{{6, 7},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xc1 */
{{0, 0},
{6, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xc2 */
{{1, 1},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xc3 */
{{0, 1},
{6, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xc4 */
{{2, 2},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xc5 */
{{0, 0},
{2, 2},
{6, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xc6 */
{{1, 2},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xc7 */
{{0, 2},
{6, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xc8 */
{{3, 3},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xc9 */
{{0, 0},
{3, 3},
{6, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xca */
{{1, 1},
{3, 3},
{6, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xcb */
{{0, 1},
{3, 3},
{6, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xcc */
{{2, 3},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xcd */
{{0, 0},
{2, 3},
{6, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xce */
{{1, 3},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xcf */
{{0, 3},
{6, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xd0 */
{{4, 4},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xd1 */
{{0, 0},
{4, 4},
{6, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xd2 */
{{1, 1},
{4, 4},
{6, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xd3 */
{{0, 1},
{4, 4},
{6, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xd4 */
{{2, 2},
{4, 4},
{6, 7},
{0, 0}
}
},
{1, 1, 4, 0, /* 0xd5 */
{{0, 0},
{2, 2},
{4, 4},
{6, 7}
}
},
{0, 1, 3, 0, /* 0xd6 */
{{1, 2},
{4, 4},
{6, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xd7 */
{{0, 2},
{4, 4},
{6, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xd8 */
{{3, 4},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xd9 */
{{0, 0},
{3, 4},
{6, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xda */
{{1, 1},
{3, 4},
{6, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xdb */
{{0, 1},
{3, 4},
{6, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xdc */
{{2, 4},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xdd */
{{0, 0},
{2, 4},
{6, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xde */
{{1, 4},
{6, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xdf */
{{0, 4},
{6, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 1, 0, /* 0xe0 */
{{5, 7},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xe1 */
{{0, 0},
{5, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xe2 */
{{1, 1},
{5, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xe3 */
{{0, 1},
{5, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xe4 */
{{2, 2},
{5, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xe5 */
{{0, 0},
{2, 2},
{5, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xe6 */
{{1, 2},
{5, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xe7 */
{{0, 2},
{5, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xe8 */
{{3, 3},
{5, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xe9 */
{{0, 0},
{3, 3},
{5, 7},
{0, 0}
}
},
{0, 1, 3, 0, /* 0xea */
{{1, 1},
{3, 3},
{5, 7},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xeb */
{{0, 1},
{3, 3},
{5, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xec */
{{2, 3},
{5, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xed */
{{0, 0},
{2, 3},
{5, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xee */
{{1, 3},
{5, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xef */
{{0, 3},
{5, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 1, 0, /* 0xf0 */
{{4, 7},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xf1 */
{{0, 0},
{4, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xf2 */
{{1, 1},
{4, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xf3 */
{{0, 1},
{4, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xf4 */
{{2, 2},
{4, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 3, 0, /* 0xf5 */
{{0, 0},
{2, 2},
{4, 7},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xf6 */
{{1, 2},
{4, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xf7 */
{{0, 2},
{4, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 1, 0, /* 0xf8 */
{{3, 7},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xf9 */
{{0, 0},
{3, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 2, 0, /* 0xfa */
{{1, 1},
{3, 7},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xfb */
{{0, 1},
{3, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 1, 0, /* 0xfc */
{{2, 7},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 1, 2, 0, /* 0xfd */
{{0, 0},
{2, 7},
{0, 0},
{0, 0}
}
},
{0, 1, 1, 0, /* 0xfe */
{{1, 7},
{0, 0},
{0, 0},
{0, 0}
}
},
{1, 1, 1, 0, /* 0xff */
{{0, 7},
{0, 0},
{0, 0},
{0, 0}
}
}
};
int
sctp_is_address_in_scope(struct sctp_ifa *ifa,
struct sctp_scoping *scope,
int do_update)
{
if ((scope->loopback_scope == 0) &&
(ifa->ifn_p) && SCTP_IFN_IS_IFT_LOOP(ifa->ifn_p)) {
/*
* skip loopback if not in scope *
*/
return (0);
}
switch (ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
if (scope->ipv4_addr_legal) {
struct sockaddr_in *sin;
sin = &ifa->address.sin;
if (sin->sin_addr.s_addr == 0) {
/* not in scope , unspecified */
return (0);
}
if ((scope->ipv4_local_scope == 0) &&
(IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
/* private address not in scope */
return (0);
}
} else {
return (0);
}
break;
#endif
#ifdef INET6
case AF_INET6:
if (scope->ipv6_addr_legal) {
struct sockaddr_in6 *sin6;
/*
* Must update the flags, bummer, which means any
* IFA locks must now be applied HERE <->
*/
if (do_update) {
sctp_gather_internal_ifa_flags(ifa);
}
if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
return (0);
}
/* ok to use deprecated addresses? */
sin6 = &ifa->address.sin6;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
/* skip unspecifed addresses */
return (0);
}
if ( /* (local_scope == 0) && */
(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
return (0);
}
if ((scope->site_scope == 0) &&
(IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
return (0);
}
} else {
return (0);
}
break;
#endif
default:
return (0);
}
return (1);
}
static struct mbuf *
sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
{
#if defined(INET) || defined(INET6)
struct sctp_paramhdr *paramh;
struct mbuf *mret;
uint16_t plen;
#endif
switch (ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
plen = (uint16_t)sizeof(struct sctp_ipv4addr_param);
break;
#endif
#ifdef INET6
case AF_INET6:
plen = (uint16_t)sizeof(struct sctp_ipv6addr_param);
break;
#endif
default:
return (m);
}
#if defined(INET) || defined(INET6)
if (M_TRAILINGSPACE(m) >= plen) {
/* easy side we just drop it on the end */
paramh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m)));
mret = m;
} else {
/* Need more space */
mret = m;
while (SCTP_BUF_NEXT(mret) != NULL) {
mret = SCTP_BUF_NEXT(mret);
}
SCTP_BUF_NEXT(mret) = sctp_get_mbuf_for_msg(plen, 0, M_NOWAIT, 1, MT_DATA);
if (SCTP_BUF_NEXT(mret) == NULL) {
/* We are hosed, can't add more addresses */
return (m);
}
mret = SCTP_BUF_NEXT(mret);
paramh = mtod(mret, struct sctp_paramhdr *);
}
/* now add the parameter */
switch (ifa->address.sa.sa_family) {
#ifdef INET
case AF_INET:
{
struct sctp_ipv4addr_param *ipv4p;
struct sockaddr_in *sin;
sin = &ifa->address.sin;
ipv4p = (struct sctp_ipv4addr_param *)paramh;
paramh->param_type = htons(SCTP_IPV4_ADDRESS);
paramh->param_length = htons(plen);
ipv4p->addr = sin->sin_addr.s_addr;
SCTP_BUF_LEN(mret) += plen;
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
struct sctp_ipv6addr_param *ipv6p;
struct sockaddr_in6 *sin6;
sin6 = &ifa->address.sin6;
ipv6p = (struct sctp_ipv6addr_param *)paramh;
paramh->param_type = htons(SCTP_IPV6_ADDRESS);
paramh->param_length = htons(plen);
memcpy(ipv6p->addr, &sin6->sin6_addr,
sizeof(ipv6p->addr));
/* clear embedded scope in the address */
in6_clearscope((struct in6_addr *)ipv6p->addr);
SCTP_BUF_LEN(mret) += plen;
break;
}
#endif
default:
return (m);
}
if (len != NULL) {
*len += plen;
}
return (mret);
#endif
}
struct mbuf *
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_scoping *scope,
struct mbuf *m_at, int cnt_inits_to,
uint16_t *padding_len, uint16_t *chunk_len)
{
struct sctp_vrf *vrf = NULL;
int cnt, limit_out = 0, total_count;
uint32_t vrf_id;
vrf_id = inp->def_vrf_id;
SCTP_IPI_ADDR_RLOCK();
vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL) {
SCTP_IPI_ADDR_RUNLOCK();
return (m_at);
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
struct sctp_ifa *sctp_ifap;
struct sctp_ifn *sctp_ifnp;
cnt = cnt_inits_to;
if (vrf->total_ifa_count > SCTP_COUNT_LIMIT) {
limit_out = 1;
cnt = SCTP_ADDRESS_LIMIT;
goto skip_count;
}
LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
if ((scope->loopback_scope == 0) &&
SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) {
/*
* Skip loopback devices if loopback_scope
* not set
*/
continue;
}
LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
#ifdef INET
if ((sctp_ifap->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sctp_ifap->address.sin.sin_addr) != 0)) {
continue;
}
#endif
#ifdef INET6
if ((sctp_ifap->address.sa.sa_family == AF_INET6) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sctp_ifap->address.sin6.sin6_addr) != 0)) {
continue;
}
#endif
if (sctp_is_addr_restricted(stcb, sctp_ifap)) {
continue;
}
if (sctp_is_address_in_scope(sctp_ifap, scope, 1) == 0) {
continue;
}
cnt++;
if (cnt > SCTP_ADDRESS_LIMIT) {
break;
}
}
if (cnt > SCTP_ADDRESS_LIMIT) {
break;
}
}
skip_count:
if (cnt > 1) {
total_count = 0;
LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
cnt = 0;
if ((scope->loopback_scope == 0) &&
SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) {
/*
* Skip loopback devices if
* loopback_scope not set
*/
continue;
}
LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
#ifdef INET
if ((sctp_ifap->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sctp_ifap->address.sin.sin_addr) != 0)) {
continue;
}
#endif
#ifdef INET6
if ((sctp_ifap->address.sa.sa_family == AF_INET6) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sctp_ifap->address.sin6.sin6_addr) != 0)) {
continue;
}
#endif
if (sctp_is_addr_restricted(stcb, sctp_ifap)) {
continue;
}
if (sctp_is_address_in_scope(sctp_ifap,
scope, 0) == 0) {
continue;
}
if ((chunk_len != NULL) &&
(padding_len != NULL) &&
(*padding_len > 0)) {
memset(mtod(m_at, caddr_t)+*chunk_len, 0, *padding_len);
SCTP_BUF_LEN(m_at) += *padding_len;
*chunk_len += *padding_len;
*padding_len = 0;
}
m_at = sctp_add_addr_to_mbuf(m_at, sctp_ifap, chunk_len);
if (limit_out) {
cnt++;
total_count++;
if (cnt >= 2) {
/*
* two from each
* address
*/
break;
}
if (total_count > SCTP_ADDRESS_LIMIT) {
/* No more addresses */
break;
}
}
}
}
}
} else {
struct sctp_laddr *laddr;
cnt = cnt_inits_to;
/* First, how many ? */
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
continue;
}
if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
/*
* Address being deleted by the system, dont
* list.
*/
continue;
if (laddr->action == SCTP_DEL_IP_ADDRESS) {
/*
* Address being deleted on this ep don't
* list.
*/
continue;
}
if (sctp_is_address_in_scope(laddr->ifa,
scope, 1) == 0) {
continue;
}
cnt++;
}
/*
* To get through a NAT we only list addresses if we have
* more than one. That way if you just bind a single address
* we let the source of the init dictate our address.
*/
if (cnt > 1) {
cnt = cnt_inits_to;
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
continue;
}
if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) {
continue;
}
if (sctp_is_address_in_scope(laddr->ifa,
scope, 0) == 0) {
continue;
}
if ((chunk_len != NULL) &&
(padding_len != NULL) &&
(*padding_len > 0)) {
memset(mtod(m_at, caddr_t)+*chunk_len, 0, *padding_len);
SCTP_BUF_LEN(m_at) += *padding_len;
*chunk_len += *padding_len;
*padding_len = 0;
}
m_at = sctp_add_addr_to_mbuf(m_at, laddr->ifa, chunk_len);
cnt++;
if (cnt >= SCTP_ADDRESS_LIMIT) {
break;
}
}
}
}
SCTP_IPI_ADDR_RUNLOCK();
return (m_at);
}
static struct sctp_ifa *
sctp_is_ifa_addr_preferred(struct sctp_ifa *ifa,
uint8_t dest_is_loop,
uint8_t dest_is_priv,
sa_family_t fam)
{
uint8_t dest_is_global = 0;
/* dest_is_priv is true if destination is a private address */
/* dest_is_loop is true if destination is a loopback addresses */
/**
* Here we determine if its a preferred address. A preferred address
* means it is the same scope or higher scope then the destination.
* L = loopback, P = private, G = global
* -----------------------------------------
* src | dest | result
* ----------------------------------------
* L | L | yes
* -----------------------------------------
* P | L | yes-v4 no-v6
* -----------------------------------------
* G | L | yes-v4 no-v6
* -----------------------------------------
* L | P | no
* -----------------------------------------
* P | P | yes
* -----------------------------------------
* G | P | no
* -----------------------------------------
* L | G | no
* -----------------------------------------
* P | G | no
* -----------------------------------------
* G | G | yes
* -----------------------------------------
*/
if (ifa->address.sa.sa_family != fam) {
/* forget mis-matched family */
return (NULL);
}
if ((dest_is_priv == 0) && (dest_is_loop == 0)) {
dest_is_global = 1;
}
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Is destination preferred:");
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ifa->address.sa);
/* Ok the address may be ok */
#ifdef INET6
if (fam == AF_INET6) {
/* ok to use deprecated addresses? no lets not! */
if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:1\n");
return (NULL);
}
if (ifa->src_is_priv && !ifa->src_is_loop) {
if (dest_is_loop) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:2\n");
return (NULL);
}
}
if (ifa->src_is_glob) {
if (dest_is_loop) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:3\n");
return (NULL);
}
}
}
#endif
/*
* Now that we know what is what, implement or table this could in
* theory be done slicker (it used to be), but this is
* straightforward and easier to validate :-)
*/
SCTPDBG(SCTP_DEBUG_OUTPUT3, "src_loop:%d src_priv:%d src_glob:%d\n",
ifa->src_is_loop, ifa->src_is_priv, ifa->src_is_glob);
SCTPDBG(SCTP_DEBUG_OUTPUT3, "dest_loop:%d dest_priv:%d dest_glob:%d\n",
dest_is_loop, dest_is_priv, dest_is_global);
if ((ifa->src_is_loop) && (dest_is_priv)) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:4\n");
return (NULL);
}
if ((ifa->src_is_glob) && (dest_is_priv)) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:5\n");
return (NULL);
}
if ((ifa->src_is_loop) && (dest_is_global)) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:6\n");
return (NULL);
}
if ((ifa->src_is_priv) && (dest_is_global)) {
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:7\n");
return (NULL);
}
SCTPDBG(SCTP_DEBUG_OUTPUT3, "YES\n");
/* its a preferred address */
return (ifa);
}
static struct sctp_ifa *
sctp_is_ifa_addr_acceptable(struct sctp_ifa *ifa,
uint8_t dest_is_loop,
uint8_t dest_is_priv,
sa_family_t fam)
{
uint8_t dest_is_global = 0;
/**
* Here we determine if its a acceptable address. A acceptable
* address means it is the same scope or higher scope but we can
* allow for NAT which means its ok to have a global dest and a
* private src.
*
* L = loopback, P = private, G = global
* -----------------------------------------
* src | dest | result
* -----------------------------------------
* L | L | yes
* -----------------------------------------
* P | L | yes-v4 no-v6
* -----------------------------------------
* G | L | yes
* -----------------------------------------
* L | P | no
* -----------------------------------------
* P | P | yes
* -----------------------------------------
* G | P | yes - May not work
* -----------------------------------------
* L | G | no
* -----------------------------------------
* P | G | yes - May not work
* -----------------------------------------
* G | G | yes
* -----------------------------------------
*/
if (ifa->address.sa.sa_family != fam) {
/* forget non matching family */
SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa_fam:%d fam:%d\n",
ifa->address.sa.sa_family, fam);
return (NULL);
}
/* Ok the address may be ok */
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, &ifa->address.sa);
SCTPDBG(SCTP_DEBUG_OUTPUT3, "dst_is_loop:%d dest_is_priv:%d\n",
dest_is_loop, dest_is_priv);
if ((dest_is_loop == 0) && (dest_is_priv == 0)) {
dest_is_global = 1;
}
#ifdef INET6
if (fam == AF_INET6) {
/* ok to use deprecated addresses? */
if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
return (NULL);
}
if (ifa->src_is_priv) {
/* Special case, linklocal to loop */
if (dest_is_loop)
return (NULL);
}
}
#endif
/*
* Now that we know what is what, implement our table. This could in
* theory be done slicker (it used to be), but this is
* straightforward and easier to validate :-)
*/
SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_priv:%d\n",
ifa->src_is_loop,
dest_is_priv);
if ((ifa->src_is_loop == 1) && (dest_is_priv)) {
return (NULL);
}
SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_glob:%d\n",
ifa->src_is_loop,
dest_is_global);
if ((ifa->src_is_loop == 1) && (dest_is_global)) {
return (NULL);
}
SCTPDBG(SCTP_DEBUG_OUTPUT3, "address is acceptable\n");
/* its an acceptable address */
return (ifa);
}
int
sctp_is_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
{
struct sctp_laddr *laddr;
if (stcb == NULL) {
/* There are no restrictions, no TCB :-) */
return (0);
}
LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
__func__);
continue;
}
if (laddr->ifa == ifa) {
/* Yes it is on the list */
return (1);
}
}
return (0);
}
int
sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
{
struct sctp_laddr *laddr;
if (ifa == NULL)
return (0);
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
__func__);
continue;
}
if ((laddr->ifa == ifa) && laddr->action == 0)
/* same pointer */
return (1);
}
return (0);
}
static struct sctp_ifa *
sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
sctp_route_t *ro,
uint32_t vrf_id,
int non_asoc_addr_ok,
uint8_t dest_is_priv,
uint8_t dest_is_loop,
sa_family_t fam)
{
struct sctp_laddr *laddr, *starting_point;
void *ifn;
int resettotop = 0;
struct sctp_ifn *sctp_ifn;
struct sctp_ifa *sctp_ifa, *sifa;
struct sctp_vrf *vrf;
uint32_t ifn_index;
vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL)
return (NULL);
ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
sctp_ifn = sctp_find_ifn(ifn, ifn_index);
/*
* first question, is the ifn we will emit on in our list, if so, we
* want such an address. Note that we first looked for a preferred
* address.
*/
if (sctp_ifn) {
/* is a preferred one on the interface we route out? */
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin.sin_addr) != 0)) {
continue;
}
#endif
#ifdef INET6
if ((sctp_ifa->address.sa.sa_family == AF_INET6) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin6.sin6_addr) != 0)) {
continue;
}
#endif
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
(non_asoc_addr_ok == 0))
continue;
sifa = sctp_is_ifa_addr_preferred(sctp_ifa,
dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
continue;
if (sctp_is_addr_in_ep(inp, sifa)) {
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
}
}
/*
* ok, now we now need to find one on the list of the addresses. We
* can't get one on the emitting interface so let's find first a
* preferred one. If not that an acceptable one otherwise... we
* return NULL.
*/
starting_point = inp->next_addr_touse;
once_again:
if (inp->next_addr_touse == NULL) {
inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list);
resettotop = 1;
}
for (laddr = inp->next_addr_touse; laddr;
laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
if (laddr->ifa == NULL) {
/* address has been removed */
continue;
}
if (laddr->action == SCTP_DEL_IP_ADDRESS) {
/* address is being deleted */
continue;
}
sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
continue;
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
if (resettotop == 0) {
inp->next_addr_touse = NULL;
goto once_again;
}
inp->next_addr_touse = starting_point;
resettotop = 0;
once_again_too:
if (inp->next_addr_touse == NULL) {
inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list);
resettotop = 1;
}
/* ok, what about an acceptable address in the inp */
for (laddr = inp->next_addr_touse; laddr;
laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
if (laddr->ifa == NULL) {
/* address has been removed */
continue;
}
if (laddr->action == SCTP_DEL_IP_ADDRESS) {
/* address is being deleted */
continue;
}
sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
continue;
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
if (resettotop == 0) {
inp->next_addr_touse = NULL;
goto once_again_too;
}
/*
* no address bound can be a source for the destination we are in
* trouble
*/
return (NULL);
}
static struct sctp_ifa *
sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
sctp_route_t *ro,
uint32_t vrf_id,
uint8_t dest_is_priv,
uint8_t dest_is_loop,
int non_asoc_addr_ok,
sa_family_t fam)
{
struct sctp_laddr *laddr, *starting_point;
void *ifn;
struct sctp_ifn *sctp_ifn;
struct sctp_ifa *sctp_ifa, *sifa;
uint8_t start_at_beginning = 0;
struct sctp_vrf *vrf;
uint32_t ifn_index;
/*
* first question, is the ifn we will emit on in our list, if so, we
* want that one.
*/
vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL)
return (NULL);
ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
sctp_ifn = sctp_find_ifn(ifn, ifn_index);
/*
* first question, is the ifn we will emit on in our list? If so,
* we want that one. First we look for a preferred. Second, we go
* for an acceptable.
*/
if (sctp_ifn) {
/* first try for a preferred address on the ep */
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin.sin_addr) != 0)) {
continue;
}
#endif
#ifdef INET6
if ((sctp_ifa->address.sa.sa_family == AF_INET6) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin6.sin6_addr) != 0)) {
continue;
}
#endif
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
continue;
if (sctp_is_addr_in_ep(inp, sctp_ifa)) {
sifa = sctp_is_ifa_addr_preferred(sctp_ifa, dest_is_loop, dest_is_priv, fam);
if (sifa == NULL)
continue;
if (((non_asoc_addr_ok == 0) &&
(sctp_is_addr_restricted(stcb, sifa))) ||
(non_asoc_addr_ok &&
(sctp_is_addr_restricted(stcb, sifa)) &&
(!sctp_is_addr_pending(stcb, sifa)))) {
/* on the no-no list */
continue;
}
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
}
/* next try for an acceptable address on the ep */
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin.sin_addr) != 0)) {
continue;
}
#endif
#ifdef INET6
if ((sctp_ifa->address.sa.sa_family == AF_INET6) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin6.sin6_addr) != 0)) {
continue;
}
#endif
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
continue;
if (sctp_is_addr_in_ep(inp, sctp_ifa)) {
sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv, fam);
if (sifa == NULL)
continue;
if (((non_asoc_addr_ok == 0) &&
(sctp_is_addr_restricted(stcb, sifa))) ||
(non_asoc_addr_ok &&
(sctp_is_addr_restricted(stcb, sifa)) &&
(!sctp_is_addr_pending(stcb, sifa)))) {
/* on the no-no list */
continue;
}
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
}
}
/*
* if we can't find one like that then we must look at all addresses
* bound to pick one at first preferable then secondly acceptable.
*/
starting_point = stcb->asoc.last_used_address;
sctp_from_the_top:
if (stcb->asoc.last_used_address == NULL) {
start_at_beginning = 1;
stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list);
}
/* search beginning with the last used address */
for (laddr = stcb->asoc.last_used_address; laddr;
laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
if (laddr->ifa == NULL) {
/* address has been removed */
continue;
}
if (laddr->action == SCTP_DEL_IP_ADDRESS) {
/* address is being deleted */
continue;
}
sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam);
if (sifa == NULL)
continue;
if (((non_asoc_addr_ok == 0) &&
(sctp_is_addr_restricted(stcb, sifa))) ||
(non_asoc_addr_ok &&
(sctp_is_addr_restricted(stcb, sifa)) &&
(!sctp_is_addr_pending(stcb, sifa)))) {
/* on the no-no list */
continue;
}
stcb->asoc.last_used_address = laddr;
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
if (start_at_beginning == 0) {
stcb->asoc.last_used_address = NULL;
goto sctp_from_the_top;
}
/* now try for any higher scope than the destination */
stcb->asoc.last_used_address = starting_point;
start_at_beginning = 0;
sctp_from_the_top2:
if (stcb->asoc.last_used_address == NULL) {
start_at_beginning = 1;
stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list);
}
/* search beginning with the last used address */
for (laddr = stcb->asoc.last_used_address; laddr;
laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
if (laddr->ifa == NULL) {
/* address has been removed */
continue;
}
if (laddr->action == SCTP_DEL_IP_ADDRESS) {
/* address is being deleted */
continue;
}
sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
continue;
if (((non_asoc_addr_ok == 0) &&
(sctp_is_addr_restricted(stcb, sifa))) ||
(non_asoc_addr_ok &&
(sctp_is_addr_restricted(stcb, sifa)) &&
(!sctp_is_addr_pending(stcb, sifa)))) {
/* on the no-no list */
continue;
}
stcb->asoc.last_used_address = laddr;
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
if (start_at_beginning == 0) {
stcb->asoc.last_used_address = NULL;
goto sctp_from_the_top2;
}
return (NULL);
}
static struct sctp_ifa *
sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn,
struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
int non_asoc_addr_ok,
uint8_t dest_is_loop,
uint8_t dest_is_priv,
int addr_wanted,
sa_family_t fam,
sctp_route_t *ro)
{
struct sctp_ifa *ifa, *sifa;
int num_eligible_addr = 0;
#ifdef INET6
struct sockaddr_in6 sin6, lsa6;
if (fam == AF_INET6) {
memcpy(&sin6, &ro->ro_dst, sizeof(struct sockaddr_in6));
(void)sa6_recoverscope(&sin6);
}
#endif /* INET6 */
LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) {
#ifdef INET
if ((ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&ifa->address.sin.sin_addr) != 0)) {
continue;
}
#endif
#ifdef INET6
if ((ifa->address.sa.sa_family == AF_INET6) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&ifa->address.sin6.sin6_addr) != 0)) {
continue;
}
#endif
if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
(non_asoc_addr_ok == 0))
continue;
sifa = sctp_is_ifa_addr_preferred(ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
continue;
#ifdef INET6
if (fam == AF_INET6 &&
dest_is_loop &&
sifa->src_is_loop && sifa->src_is_priv) {
/*
* don't allow fe80::1 to be a src on loop ::1, we
* don't list it to the peer so we will get an
* abort.
*/
continue;
}
if (fam == AF_INET6 &&
IN6_IS_ADDR_LINKLOCAL(&sifa->address.sin6.sin6_addr) &&
IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
/*
* link-local <-> link-local must belong to the same
* scope.
*/
memcpy(&lsa6, &sifa->address.sin6, sizeof(struct sockaddr_in6));
(void)sa6_recoverscope(&lsa6);
if (sin6.sin6_scope_id != lsa6.sin6_scope_id) {
continue;
}
}
#endif /* INET6 */
/*
* Check if the IPv6 address matches to next-hop. In the
* mobile case, old IPv6 address may be not deleted from the
* interface. Then, the interface has previous and new
* addresses. We should use one corresponding to the
* next-hop. (by micchie)
*/
#ifdef INET6
if (stcb && fam == AF_INET6 &&
sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) {
if (sctp_v6src_match_nexthop(&sifa->address.sin6, ro)
== 0) {
continue;
}
}
#endif
#ifdef INET
/* Avoid topologically incorrect IPv4 address */
if (stcb && fam == AF_INET &&
sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) {
if (sctp_v4src_match_nexthop(sifa, ro) == 0) {
continue;
}
}
#endif
if (stcb) {
if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) {
continue;
}
if (((non_asoc_addr_ok == 0) &&
(sctp_is_addr_restricted(stcb, sifa))) ||
(non_asoc_addr_ok &&
(sctp_is_addr_restricted(stcb, sifa)) &&
(!sctp_is_addr_pending(stcb, sifa)))) {
/*
* It is restricted for some reason..
* probably not yet added.
*/
continue;
}
}
if (num_eligible_addr >= addr_wanted) {
return (sifa);
}
num_eligible_addr++;
}
return (NULL);
}
static int
sctp_count_num_preferred_boundall(struct sctp_ifn *ifn,
struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
int non_asoc_addr_ok,
uint8_t dest_is_loop,
uint8_t dest_is_priv,
sa_family_t fam)
{
struct sctp_ifa *ifa, *sifa;
int num_eligible_addr = 0;
LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) {
#ifdef INET
if ((ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&ifa->address.sin.sin_addr) != 0)) {
continue;
}
#endif
#ifdef INET6
if ((ifa->address.sa.sa_family == AF_INET6) &&
(stcb != NULL) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&ifa->address.sin6.sin6_addr) != 0)) {
continue;
}
#endif
if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
(non_asoc_addr_ok == 0)) {
continue;
}
sifa = sctp_is_ifa_addr_preferred(ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL) {
continue;
}
if (stcb) {
if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) {
continue;
}
if (((non_asoc_addr_ok == 0) &&
(sctp_is_addr_restricted(stcb, sifa))) ||
(non_asoc_addr_ok &&
(sctp_is_addr_restricted(stcb, sifa)) &&
(!sctp_is_addr_pending(stcb, sifa)))) {
/*
* It is restricted for some reason..
* probably not yet added.
*/
continue;
}
}
num_eligible_addr++;
}
return (num_eligible_addr);
}
static struct sctp_ifa *
sctp_choose_boundall(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_nets *net,
sctp_route_t *ro,
uint32_t vrf_id,
uint8_t dest_is_priv,
uint8_t dest_is_loop,
int non_asoc_addr_ok,
sa_family_t fam)
{
int cur_addr_num = 0, num_preferred = 0;
void *ifn;
struct sctp_ifn *sctp_ifn, *looked_at = NULL, *emit_ifn;
struct sctp_ifa *sctp_ifa, *sifa;
uint32_t ifn_index;
struct sctp_vrf *vrf;
#ifdef INET
int retried = 0;
#endif
/*-
* For boundall we can use any address in the association.
* If non_asoc_addr_ok is set we can use any address (at least in
* theory). So we look for preferred addresses first. If we find one,
* we use it. Otherwise we next try to get an address on the
* interface, which we should be able to do (unless non_asoc_addr_ok
* is false and we are routed out that way). In these cases where we
* can't use the address of the interface we go through all the
* ifn's looking for an address we can use and fill that in. Punting
* means we send back address 0, which will probably cause problems
* actually since then IP will fill in the address of the route ifn,
* which means we probably already rejected it.. i.e. here comes an
* abort :-<.
*/
vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL)
return (NULL);
ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro);
SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifn from route:%p ifn_index:%d\n", ifn, ifn_index);
emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(ifn, ifn_index);
if (sctp_ifn == NULL) {
/* ?? We don't have this guy ?? */
SCTPDBG(SCTP_DEBUG_OUTPUT2, "No ifn emit interface?\n");
goto bound_all_plan_b;
}
SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifn_index:%d name:%s is emit interface\n",
ifn_index, sctp_ifn->ifn_name);
if (net) {
cur_addr_num = net->indx_of_eligible_next_to_use;
}
num_preferred = sctp_count_num_preferred_boundall(sctp_ifn,
inp, stcb,
non_asoc_addr_ok,
dest_is_loop,
dest_is_priv, fam);
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Found %d preferred source addresses for intf:%s\n",
num_preferred, sctp_ifn->ifn_name);
if (num_preferred == 0) {
/*
* no eligible addresses, we must use some other interface
* address if we can find one.
*/
goto bound_all_plan_b;
}
/*
* Ok we have num_eligible_addr set with how many we can use, this
* may vary from call to call due to addresses being deprecated
* etc..
*/
if (cur_addr_num >= num_preferred) {
cur_addr_num = 0;
}
/*
* select the nth address from the list (where cur_addr_num is the
* nth) and 0 is the first one, 1 is the second one etc...
*/
SCTPDBG(SCTP_DEBUG_OUTPUT2, "cur_addr_num:%d\n", cur_addr_num);
sctp_ifa = sctp_select_nth_preferred_addr_from_ifn_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok, dest_is_loop,
dest_is_priv, cur_addr_num, fam, ro);
/* if sctp_ifa is NULL something changed??, fall to plan b. */
if (sctp_ifa) {
atomic_add_int(&sctp_ifa->refcount, 1);
if (net) {
/* save off where the next one we will want */
net->indx_of_eligible_next_to_use = cur_addr_num + 1;
}
return (sctp_ifa);
}
/*
* plan_b: Look at all interfaces and find a preferred address. If
* no preferred fall through to plan_c.
*/
bound_all_plan_b:
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan B\n");
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Examine interface %s\n",
sctp_ifn->ifn_name);
if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
/* wrong base scope */
SCTPDBG(SCTP_DEBUG_OUTPUT2, "skip\n");
continue;
}
if ((sctp_ifn == looked_at) && looked_at) {
/* already looked at this guy */
SCTPDBG(SCTP_DEBUG_OUTPUT2, "already seen\n");
continue;
}
num_preferred = sctp_count_num_preferred_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok,
dest_is_loop, dest_is_priv, fam);
SCTPDBG(SCTP_DEBUG_OUTPUT2,
"Found ifn:%p %d preferred source addresses\n",
ifn, num_preferred);
if (num_preferred == 0) {
/* None on this interface. */
SCTPDBG(SCTP_DEBUG_OUTPUT2, "No preferred -- skipping to next\n");
continue;
}
SCTPDBG(SCTP_DEBUG_OUTPUT2,
"num preferred:%d on interface:%p cur_addr_num:%d\n",
num_preferred, (void *)sctp_ifn, cur_addr_num);
/*
* Ok we have num_eligible_addr set with how many we can
* use, this may vary from call to call due to addresses
* being deprecated etc..
*/
if (cur_addr_num >= num_preferred) {
cur_addr_num = 0;
}
sifa = sctp_select_nth_preferred_addr_from_ifn_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok, dest_is_loop,
dest_is_priv, cur_addr_num, fam, ro);
if (sifa == NULL)
continue;
if (net) {
net->indx_of_eligible_next_to_use = cur_addr_num + 1;
SCTPDBG(SCTP_DEBUG_OUTPUT2, "we selected %d\n",
cur_addr_num);
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Source:");
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa);
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Dest:");
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &net->ro._l_addr.sa);
}
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
#ifdef INET
again_with_private_addresses_allowed:
#endif
/* plan_c: do we have an acceptable address on the emit interface */
sifa = NULL;
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan C: find acceptable on interface\n");
if (emit_ifn == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Jump to Plan D - no emit_ifn\n");
goto plan_d;
}
LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifa:%p\n", (void *)sctp_ifa);
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin.sin_addr) != 0)) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Jailed\n");
continue;
}
#endif
#ifdef INET6
if ((sctp_ifa->address.sa.sa_family == AF_INET6) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin6.sin6_addr) != 0)) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Jailed\n");
continue;
}
#endif
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
(non_asoc_addr_ok == 0)) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Defer\n");
continue;
}
sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "IFA not acceptable\n");
continue;
}
if (stcb) {
if (sctp_is_address_in_scope(sifa, &stcb->asoc.scope, 0) == 0) {
SCTPDBG(SCTP_DEBUG_OUTPUT2, "NOT in scope\n");
sifa = NULL;
continue;
}
if (((non_asoc_addr_ok == 0) &&
(sctp_is_addr_restricted(stcb, sifa))) ||
(non_asoc_addr_ok &&
(sctp_is_addr_restricted(stcb, sifa)) &&
(!sctp_is_addr_pending(stcb, sifa)))) {
/*
* It is restricted for some reason..
* probably not yet added.
*/
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its restricted\n");
sifa = NULL;
continue;
}
}
atomic_add_int(&sifa->refcount, 1);
goto out;
}
plan_d:
/*
* plan_d: We are in trouble. No preferred address on the emit
* interface. And not even a preferred address on all interfaces. Go
* out and see if we can find an acceptable address somewhere
* amongst all interfaces.
*/
SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan D looked_at is %p\n", (void *)looked_at);
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
/* wrong base scope */
continue;
}
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
#ifdef INET
if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
(prison_check_ip4(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin.sin_addr) != 0)) {
continue;
}
#endif
#ifdef INET6
if ((sctp_ifa->address.sa.sa_family == AF_INET6) &&
(prison_check_ip6(inp->ip_inp.inp.inp_cred,
&sctp_ifa->address.sin6.sin6_addr) != 0)) {
continue;
}
#endif
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
(non_asoc_addr_ok == 0))
continue;
sifa = sctp_is_ifa_addr_acceptable(sctp_ifa,
dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
continue;
if (stcb) {
if (sctp_is_address_in_scope(sifa, &stcb->asoc.scope, 0) == 0) {
sifa = NULL;
continue;
}
if (((non_asoc_addr_ok == 0) &&
(sctp_is_addr_restricted(stcb, sifa))) ||
(non_asoc_addr_ok &&
(sctp_is_addr_restricted(stcb, sifa)) &&
(!sctp_is_addr_pending(stcb, sifa)))) {
/*
* It is restricted for some
* reason.. probably not yet added.
*/
sifa = NULL;
continue;
}
}
goto out;
}
}
#ifdef INET
if (stcb) {
if ((retried == 0) && (stcb->asoc.scope.ipv4_local_scope == 0)) {
stcb->asoc.scope.ipv4_local_scope = 1;
retried = 1;
goto again_with_private_addresses_allowed;
} else if (retried == 1) {
stcb->asoc.scope.ipv4_local_scope = 0;
}
}
#endif
out:
#ifdef INET
if (sifa) {
if (retried == 1) {
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
/* wrong base scope */
continue;
}
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
struct sctp_ifa *tmp_sifa;
#ifdef INET
if ((sctp_ifa->addres
|