diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-01-04 14:17:57 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-01-05 10:05:06 +0000 |
commit | 39d357e3248f80abea0159765ff39554affb40db (patch) | |
tree | aba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/third_party/usrsctp | |
parent | 87778abf5a1f89266f37d1321b92a21851d8244d (diff) | |
download | qtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz |
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2
Change-Id: I20d43c737f82764d857ada9a55586901b18b9243
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/usrsctp')
60 files changed, 5264 insertions, 4274 deletions
diff --git a/chromium/third_party/usrsctp/BUILD.gn b/chromium/third_party/usrsctp/BUILD.gn index 46627963765..7e65a69cef4 100644 --- a/chromium/third_party/usrsctp/BUILD.gn +++ b/chromium/third_party/usrsctp/BUILD.gn @@ -123,16 +123,7 @@ static_library("usrsctp") { } if (is_win) { - defines += [ - "__Userspace_os_Windows", - - # Manually setting WINVER and _WIN32_WINNT is needed because Chrome - # sets WINVER to a newer version of windows. But compiling usrsctp - # this way would is incompatible with windows XP. - "WINVER=0x0502", - "_WIN32_WINNT=0x0502", - ] - configs -= [ "//build/config/win:winver" ] + defines += [ "__Userspace_os_Windows" ] } else { defines += [ "NON_WINDOWS_DEFINE" ] } diff --git a/chromium/third_party/usrsctp/OWNERS b/chromium/third_party/usrsctp/OWNERS index 614cb588ea0..5bce29c59a8 100644 --- a/chromium/third_party/usrsctp/OWNERS +++ b/chromium/third_party/usrsctp/OWNERS @@ -1,3 +1,4 @@ +pthatcher@chromium.org +deadbeef@chromium.org jiayl@chromium.org -lally@chromium.org ldixon@chromium.org diff --git a/chromium/third_party/usrsctp/usrsctp.gyp b/chromium/third_party/usrsctp/usrsctp.gyp deleted file mode 100644 index 9533fb8ed12..00000000000 --- a/chromium/third_party/usrsctp/usrsctp.gyp +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -{ - 'variables': { - 'libsctp_target_type%': 'static_library', - }, - 'target_defaults': { - 'defines': [ - 'SCTP_PROCESS_LEVEL_LOCKS', - 'SCTP_SIMPLE_ALLOCATOR', - 'SCTP_USE_OPENSSL_SHA1', - '__Userspace__', - # 'SCTP_DEBUG', # Uncomment for SCTP debugging. - ], - 'include_dirs': [ - 'usrsctplib/usrsctplib/', - 'usrsctplib/usrsctplib/netinet', - ], - 'dependencies': [ - '<(DEPTH)/third_party/boringssl/boringssl.gyp:boringssl', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - 'usrsctplib/usrsctplib/', - 'usrsctplib/usrsctplib/netinet', - ], - }, - }, - 'targets': [ - { - # GN version: //third_party/usrsctp - 'target_name': 'usrsctplib', - 'type': 'static_library', - 'sources': [ - # Note: sources list duplicated in GN build. - 'usrsctplib/usrsctplib/netinet/sctp.h', - 'usrsctplib/usrsctplib/netinet/sctp_asconf.c', - 'usrsctplib/usrsctplib/netinet/sctp_asconf.h', - 'usrsctplib/usrsctplib/netinet/sctp_auth.c', - 'usrsctplib/usrsctplib/netinet/sctp_auth.h', - 'usrsctplib/usrsctplib/netinet/sctp_bsd_addr.c', - 'usrsctplib/usrsctplib/netinet/sctp_bsd_addr.h', - 'usrsctplib/usrsctplib/netinet/sctp_callout.c', - 'usrsctplib/usrsctplib/netinet/sctp_callout.h', - 'usrsctplib/usrsctplib/netinet/sctp_cc_functions.c', - 'usrsctplib/usrsctplib/netinet/sctp_constants.h', - 'usrsctplib/usrsctplib/netinet/sctp_crc32.c', - 'usrsctplib/usrsctplib/netinet/sctp_crc32.h', - 'usrsctplib/usrsctplib/netinet/sctp_header.h', - 'usrsctplib/usrsctplib/netinet/sctp_indata.c', - 'usrsctplib/usrsctplib/netinet/sctp_indata.h', - 'usrsctplib/usrsctplib/netinet/sctp_input.c', - 'usrsctplib/usrsctplib/netinet/sctp_input.h', - 'usrsctplib/usrsctplib/netinet/sctp_lock_userspace.h', - 'usrsctplib/usrsctplib/netinet/sctp_os.h', - 'usrsctplib/usrsctplib/netinet/sctp_os_userspace.h', - 'usrsctplib/usrsctplib/netinet/sctp_output.c', - 'usrsctplib/usrsctplib/netinet/sctp_output.h', - 'usrsctplib/usrsctplib/netinet/sctp_pcb.c', - 'usrsctplib/usrsctplib/netinet/sctp_pcb.h', - 'usrsctplib/usrsctplib/netinet/sctp_peeloff.c', - 'usrsctplib/usrsctplib/netinet/sctp_peeloff.h', - 'usrsctplib/usrsctplib/netinet/sctp_process_lock.h', - 'usrsctplib/usrsctplib/netinet/sctp_sha1.c', - 'usrsctplib/usrsctplib/netinet/sctp_sha1.h', - 'usrsctplib/usrsctplib/netinet/sctp_ss_functions.c', - 'usrsctplib/usrsctplib/netinet/sctp_structs.h', - 'usrsctplib/usrsctplib/netinet/sctp_sysctl.c', - 'usrsctplib/usrsctplib/netinet/sctp_sysctl.h', - 'usrsctplib/usrsctplib/netinet/sctp_timer.c', - 'usrsctplib/usrsctplib/netinet/sctp_timer.h', - 'usrsctplib/usrsctplib/netinet/sctp_uio.h', - 'usrsctplib/usrsctplib/netinet/sctp_userspace.c', - 'usrsctplib/usrsctplib/netinet/sctp_usrreq.c', - 'usrsctplib/usrsctplib/netinet/sctp_var.h', - 'usrsctplib/usrsctplib/netinet/sctputil.c', - 'usrsctplib/usrsctplib/netinet/sctputil.h', - 'usrsctplib/usrsctplib/netinet6/sctp6_usrreq.c', - 'usrsctplib/usrsctplib/netinet6/sctp6_var.h', - 'usrsctplib/usrsctplib/user_atomic.h', - 'usrsctplib/usrsctplib/user_environment.c', - 'usrsctplib/usrsctplib/user_environment.h', - 'usrsctplib/usrsctplib/user_inpcb.h', - 'usrsctplib/usrsctplib/user_ip6_var.h', - 'usrsctplib/usrsctplib/user_ip_icmp.h', - 'usrsctplib/usrsctplib/user_malloc.h', - 'usrsctplib/usrsctplib/user_mbuf.c', - 'usrsctplib/usrsctplib/user_mbuf.h', - 'usrsctplib/usrsctplib/user_queue.h', - 'usrsctplib/usrsctplib/user_recv_thread.c', - 'usrsctplib/usrsctplib/user_recv_thread.h', - 'usrsctplib/usrsctplib/user_route.h', - 'usrsctplib/usrsctplib/user_socket.c', - 'usrsctplib/usrsctplib/user_socketvar.h', - 'usrsctplib/usrsctplib/user_uma.h', - 'usrsctplib/usrsctplib/usrsctp.h', - ], # sources - 'variables': { - 'clang_warning_flags': [ - # atomic_init in user_atomic.h is a static function in a header. - '-Wno-unused-function', - ], - }, - 'conditions': [ - ['OS=="linux" or OS=="android"', { - 'defines': [ - '__Userspace_os_Linux', - '_GNU_SOURCE' - ], - 'cflags!': [ '-Werror', '-Wall' ], - 'cflags': [ '-w' ], - }], - ['OS=="mac" or OS=="ios"', { - 'defines': [ - 'HAVE_SA_LEN', - 'HAVE_SCONN_LEN', - '__APPLE_USE_RFC_2292', - '__Userspace_os_Darwin', - ], - # usrsctp requires that __APPLE__ is undefined for compilation (for - # historical reasons). There is a plan to change this, and when it - # happens and we re-roll DEPS for usrsctp, we can remove the manual - # undefining of __APPLE__. - 'xcode_settings': { - 'OTHER_CFLAGS!': [ '-Werror', '-Wall' ], - 'OTHER_CFLAGS': [ '-U__APPLE__', '-w' ], - }, - }], - ['OS=="win"', { - 'defines': [ - '__Userspace_os_Windows', - # Manually setting WINVER and _WIN32_WINNT is needed because Chrome - # sets WINVER to a newer version of Windows. But compiling usrsctp - # this way would be incompatible with Windows XP. - 'WINVER=0x0502', - '_WIN32_WINNT=0x0502', - ], - 'defines!': [ - # Remove Chrome's WINVER defines to avoid redefinition warnings. - 'WINVER=0x0A00', - '_WIN32_WINNT=0x0A00', - ], - 'cflags!': [ '/W3', '/WX' ], - 'cflags': [ '/w' ], - # TODO(ldixon) : Remove this disabling of warnings by pushing a - # fix upstream to usrsctp - 'msvs_disabled_warnings': [ 4002, 4013, 4133, 4267, 4313, 4700 ], - }, { # OS != "win", - 'defines': [ - 'NON_WINDOWS_DEFINE', - ], - }], - ], # conditions - }, # target usrsctp - ], # targets -} diff --git a/chromium/third_party/usrsctp/usrsctp_nacl.gyp b/chromium/third_party/usrsctp/usrsctp_nacl.gyp deleted file mode 100644 index 7cce5e7b870..00000000000 --- a/chromium/third_party/usrsctp/usrsctp_nacl.gyp +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -{ - 'includes': [ - '../../native_client/build/untrusted.gypi', - ], - 'targets': [ - { - 'target_name': 'usrsctplib_nacl', - 'type': 'none', - 'variables': { - 'nlib_target': 'libusrsctplib_nacl.a', - 'build_glibc': 0, - 'build_newlib': 0, - 'build_pnacl_newlib': 1, - }, - 'dependencies': [ - '<(DEPTH)/native_client_sdk/native_client_sdk_untrusted.gyp:nacl_io_untrusted', - '<(DEPTH)/third_party/boringssl/boringssl_nacl.gyp:boringssl_nacl', - ], - 'sources': [ - # Note: sources list duplicated in GN build. - 'usrsctplib/netinet/sctp.h', - 'usrsctplib/netinet/sctp_asconf.c', - 'usrsctplib/netinet/sctp_asconf.h', - 'usrsctplib/netinet/sctp_auth.c', - 'usrsctplib/netinet/sctp_auth.h', - 'usrsctplib/netinet/sctp_bsd_addr.c', - 'usrsctplib/netinet/sctp_bsd_addr.h', - 'usrsctplib/netinet/sctp_callout.c', - 'usrsctplib/netinet/sctp_callout.h', - 'usrsctplib/netinet/sctp_cc_functions.c', - 'usrsctplib/netinet/sctp_constants.h', - 'usrsctplib/netinet/sctp_crc32.c', - 'usrsctplib/netinet/sctp_crc32.h', - 'usrsctplib/netinet/sctp_header.h', - 'usrsctplib/netinet/sctp_indata.c', - 'usrsctplib/netinet/sctp_indata.h', - 'usrsctplib/netinet/sctp_input.c', - 'usrsctplib/netinet/sctp_input.h', - 'usrsctplib/netinet/sctp_lock_userspace.h', - 'usrsctplib/netinet/sctp_os.h', - 'usrsctplib/netinet/sctp_os_userspace.h', - 'usrsctplib/netinet/sctp_output.c', - 'usrsctplib/netinet/sctp_output.h', - 'usrsctplib/netinet/sctp_pcb.c', - 'usrsctplib/netinet/sctp_pcb.h', - 'usrsctplib/netinet/sctp_peeloff.c', - 'usrsctplib/netinet/sctp_peeloff.h', - 'usrsctplib/netinet/sctp_process_lock.h', - 'usrsctplib/netinet/sctp_sha1.c', - 'usrsctplib/netinet/sctp_sha1.h', - 'usrsctplib/netinet/sctp_ss_functions.c', - 'usrsctplib/netinet/sctp_structs.h', - 'usrsctplib/netinet/sctp_sysctl.c', - 'usrsctplib/netinet/sctp_sysctl.h', - 'usrsctplib/netinet/sctp_timer.c', - 'usrsctplib/netinet/sctp_timer.h', - 'usrsctplib/netinet/sctp_uio.h', - 'usrsctplib/netinet/sctp_userspace.c', - 'usrsctplib/netinet/sctp_usrreq.c', - 'usrsctplib/netinet/sctp_var.h', - 'usrsctplib/netinet/sctputil.c', - 'usrsctplib/netinet/sctputil.h', - 'usrsctplib/netinet6/sctp6_usrreq.c', - 'usrsctplib/netinet6/sctp6_var.h', - 'usrsctplib/user_atomic.h', - 'usrsctplib/user_environment.c', - 'usrsctplib/user_environment.h', - 'usrsctplib/user_inpcb.h', - 'usrsctplib/user_ip6_var.h', - 'usrsctplib/user_ip_icmp.h', - 'usrsctplib/user_malloc.h', - 'usrsctplib/user_mbuf.c', - 'usrsctplib/user_mbuf.h', - 'usrsctplib/user_queue.h', - 'usrsctplib/user_recv_thread.c', - 'usrsctplib/user_recv_thread.h', - 'usrsctplib/user_route.h', - 'usrsctplib/user_socket.c', - 'usrsctplib/user_socketvar.h', - 'usrsctplib/user_uma.h', - 'usrsctplib/usrsctp.h' - ], # sources - 'defines': [ - 'SCTP_USE_OPENSSL_SHA1', - 'SCTP_PROCESS_LEVEL_LOCKS', - 'SCTP_SIMPLE_ALLOCATOR', - '__Userspace__', - '__Userspace_os_NaCl', - 'NON_WINDOWS_DEFINE', - # 'SCTP_DEBUG', # Uncomment for SCTP debugging. - ], - 'include_dirs': [ - 'usrsctplib/', - 'usrsctplib/netinet', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - 'usrsctplib/', - 'usrsctplib/netinet', - ], - }, - 'pnacl_cflags!': [ '-Werror', '-Wall' ], - 'pnacl_cflags': [ '-w' ], - }, # target usrsctp - ], # targets -} diff --git a/chromium/third_party/usrsctp/usrsctplib/CMakeLists.txt b/chromium/third_party/usrsctp/usrsctplib/CMakeLists.txt index 36d0ed3081c..3dc4e24b0f6 100644 --- a/chromium/third_party/usrsctp/usrsctplib/CMakeLists.txt +++ b/chromium/third_party/usrsctp/usrsctplib/CMakeLists.txt @@ -30,6 +30,18 @@ # cmake_minimum_required(VERSION 2.6) -message(">> WARNINING: CMAKE SUPPORT IS EXPERIMENTAL <<") + +# Debug build type as default +if (NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, using DEBUG") + set(CMAKE_BUILD_TYPE "DEBUG") +endif() + +# Enable verbose output in DEBUG mode +if (${CMAKE_BUILD_TYPE} MATCHES "DEBUG") + message(STATUS "enabling verbose outout") + set(CMAKE_VERBOSE_MAKEFILE on) +endif() + add_subdirectory(usrsctplib) add_subdirectory(programs) diff --git a/chromium/third_party/usrsctp/usrsctplib/Manual.md b/chromium/third_party/usrsctp/usrsctplib/Manual.md index 6a1f5493cad..eacae4217f2 100644 --- a/chromium/third_party/usrsctp/usrsctplib/Manual.md +++ b/chromium/third_party/usrsctp/usrsctplib/Manual.md @@ -5,10 +5,10 @@ SCTP is a message oriented, reliable transport protocol with direct support for Like TCP, SCTP provides reliable, connection oriented data delivery with congestion control. Unlike TCP, SCTP also provides message boundary preservation, ordered and unordered message delivery, multi-streaming and multi-homing. Detection of data corruption, loss of data and duplication of data is achieved by using checksums and sequence numbers. A selective retransmission mechanism is applied to correct loss or corruption of data. In this manual the socket API for the SCTP User-land implementation will be described. It is based on [RFC 6458](http://tools.ietf.org/html/rfc6458). The main focus of this document is on pointing out the differences to the SCTP Sockets API. For all aspects of the sockets API that are not mentioned in this document, please refer to [RFC 6458](http://tools.ietf.org/html/rfc6458). Questions about SCTP itself can hopefully be answered by [RFC 4960](http://tools.ietf.org/html/rfc4960). - + ## Getting Started The user-land stack has been tested on FreeBSD 10.0, Ubuntu 11.10, Windows 7, Mac OS X 10.6, and Mac OS X 10.7. The current version of the user-land stack is provided on [github](https://github.com/sctplab/usrsctp). Download the tarball and untar it in a folder of your choice. The tarball contains all the sources to build the libusrsctp, which has to be linked to the object file of an example program. In addition there are two applications in the folder `programs` that can be built and run. - + ### Building the Library and the Applications #### Unix-like Operating Systems In the folder `usrsctp` type @@ -30,16 +30,17 @@ On Windows you need a compiler like Microsoft Visual Studio. You can build the l in the directory `usrsctp`. -#### CMake (experimental) +#### CMake Create a directory outside the `usrsctp` directory, enter it and generate files by typing $ cmake <path-to-usrsctp-sources> + $ cmake --build . -By using the `-G`flag you can specify the target buildsystem e.g. `cmake -G Xcode ../usrsctp` will generate project files for Xcode. +By default CMake generates a DEBUG build with verbose output. ### Running the Test Programs -Several test programs are included, including a discard server and a client. You can run both to send data from the client to the server. The client reads data from stdin and sends them to the server, which prints the message in the terminal and discards it. The sources of the server are also provided [here](https://github.com/sctplab/usrsctp/blob/master/programs/discard_server.c) and those of the client [here](https://github.com/sctplab/usrsctp/blob/master/programs/client.c). +Several test programs are included, including a discard server and a client. You can run both to send data from the client to the server. The client reads data from stdin and sends them to the server, which prints the message in the terminal and discards it. The sources of the server are also provided [here](https://github.com/sctplab/usrsctp/blob/master/programs/discard_server.c) and those of the client [here](https://github.com/sctplab/usrsctp/blob/master/programs/client.c). ### Using UDP Encapsulation @@ -86,13 +87,13 @@ The `discard_server` has a flag to switch between the two modi. If `use_cb` is ## Basic Operations -All system calls start with the prefix `usrsctp_` to distinguish them from the kernel variants. Some of them are changed to account for the different demands in the userland environment. +All system calls start with the prefix `usrsctp_` to distinguish them from the kernel variants. Some of them are changed to account for the different demands in the userland environment. ## Differences to RFC 6458 ### usrsctp_init() -Every application has to start with `usrsctp_init()`. This function calls `sctp_init()` and reserves the memory necessary to administer the data transfer. The function prototype is +Every application has to start with `usrsctp_init()`. This function calls `sctp_init()` and reserves the memory necessary to administer the data transfer. The function prototype is ```c void usrsctp_init(uint16_t udp_port) @@ -102,7 +103,7 @@ As it is not always possible to send data directly over SCTP because not all NAT ### usrsctp_finish() -At the end of the program `usrsctp_finish()` should be called to free all the memory that has been allocated before. The function prototype is +At the end of the program `usrsctp_finish()` should be called to free all the memory that has been allocated before. The function prototype is ```c int usrsctp_finish(void) @@ -112,20 +113,20 @@ The return code is 0 on success and -1 in case of an error. ### usrsctp_socket() -A representation of an SCTP endpoint is a socket. Is it created with `usrsctp_socket()`. The function prototype is +A representation of an SCTP endpoint is a socket. Is it created with `usrsctp_socket()`. The function prototype is ```c struct socket * -usrsctp_socket(int domain, - int type, +usrsctp_socket(int domain, + int type, int protocol, - int (*receive_cb)(struct socket *sock, - union sctp_sockstore addr, + int (*receive_cb)(struct socket *sock, + union sctp_sockstore addr, void *data, - size_t datalen, - struct sctp_rcvinfo, + size_t datalen, + struct sctp_rcvinfo, int flags), - int (*send_cb)(struct socket *sock, + int (*send_cb)(struct socket *sock, uint32_t sb_free), uint32_t sb_threshold) ``` @@ -133,7 +134,7 @@ usrsctp_socket(int domain, and the arguments taken from [RFC 6458](http://tools.ietf.org/html/rfc6458) are * domain: PF_INET or PF_INET6 can be used. -* type: In case of a one-to-many style socket it is SOCK_SEQPACKET, in case of a one-to-one style +* type: In case of a one-to-many style socket it is SOCK_SEQPACKET, in case of a one-to-one style socket it is SOCK_STREAM. For an explanation of the differences between the socket types please refer to [RFC 6458](http://tools.ietf.org/html/rfc6458). * protocol: Set IPPROTO_SCTP. @@ -144,13 +145,13 @@ On success `usrsctp_socket()` returns the pointer to the new socket in the `stru ### usrsctp_close() -The function prototype of `usrsctp_close()` is +The function prototype of `usrsctp_close()` is -```c +```c void usrsctp_close(struct socket *so) ``` -Thus the only difference is the absence of a return code. - +Thus the only difference is the absence of a return code. + ## Same Functionality as RFC 6458 The following functions have the same functionality as their kernel pendants. There prototypes @@ -333,7 +334,7 @@ Option | Datatype | r/w SCTP_RTOINFO | struct sctp_rtoinfo | r/w SCTP_ASSOCINFO | struct sctp_assocparams | r/w SCTP_INITMSG | struct sctp_initmsg | r/w -SCTP_NODELAY | int | r/w +SCTP_NODELAY | int | r/w SCTP_AUTOCLOSE | int | r/w SCTP_PRIMARY_ADDR | struct sctp_setprim | r/w SCTP_ADAPTATION_LAYER | struct sctp_setadaptation | r/w @@ -414,19 +415,19 @@ This parameter configures the threshold below which more space should be added t ## Configure RTO -The retransmission timeout (RTO), i.e. the time that controls the retransmission of messages, has several parameters, that can be changed, for example to shorten the time, before a message is retransmitted. The range of these parameters is between 0 and `2^32 - 1`ms. +The retransmission timeout (RTO), i.e. the time that controls the retransmission of messages, has several parameters, that can be changed, for example to shorten the time, before a message is retransmitted. The range of these parameters is between 0 and `2^32 - 1`ms. #### usrsctp_sysctl_set_sctp_rto_max_default() -The default value for the maximum retransmission timeout in ms is 60,000 (60secs). +The default value for the maximum retransmission timeout in ms is 60,000 (60secs). #### usrsctp_sysctl_set_sctp_rto_min_default() -The default value for the minimum retransmission timeout in ms is 1,000 (1sec). +The default value for the minimum retransmission timeout in ms is 1,000 (1sec). #### usrsctp_sysctl_set_sctp_rto_initial_default() The default value for the initial retransmission timeout in ms is 3,000 (3sec). This value is only needed before the first calculation of a round trip time took place. #### usrsctp_sysctl_set_sctp_init_rto_max_default() -The default value for the maximum retransmission timeout for an INIT chunk in ms is 60,000 (60secs). +The default value for the maximum retransmission timeout for an INIT chunk in ms is 60,000 (60secs). ## Set Timers @@ -491,7 +492,7 @@ This is a flag to turn the controlling of the coherence of SACKs on or off. The If a slow hosts receives data on a lossy link it is possible that its receiver window is full and new data can only be accepted if one chunk with a higher TSN (Transmission Sequence Number) that has previously been acknowledged is dropped. As a consequence the sender has to store data, even if they have been acknowledged in case they have to be retransmitted. If this behavior is not necessary, non-renegable SACKs can be turned on. By default the use of non-renegable SACKs is turned off. #### usrsctp_sysctl_set_sctp_enable_sack_immediately() -In some cases it is not desirable to wait for the SACK timer to expire before a SACK is sent. In these cases a bit called SACK-IMMEDIATELY (see [draft-tuexen-tsvwg-sctp-sack-immediately-09](https://tools.ietf.org/html/draft-tuexen-tsvwg-sctp-sack-immediately-09)) can be set to provoke the instant sending of a SACK. The default is to turn it off. +In some cases it is not desirable to wait for the SACK timer to expire before a SACK is sent. In these cases a bit called SACK-IMMEDIATELY (see [draft-tuexen-tsvwg-sctp-sack-immediately-09](https://tools.ietf.org/html/draft-tuexen-tsvwg-sctp-sack-immediately-09)) can be set to provoke the instant sending of a SACK. The default is to turn it off. #### usrsctp_sysctl_set_sctp_L2_abc_variable() TBD @@ -550,7 +551,7 @@ What to return when rtt and bw are unchanged. Default: 0 ## Influence the Congestion Control -The congestion control should protect the network against fast senders. +The congestion control should protect the network against fast senders. #### usrsctp_sysctl_set_sctp_ecn_enable Explicit congestion notifications are turned on by default. @@ -629,7 +630,7 @@ Enable SCTP fast handoff. default: 0 Calculating the checksum for packets sent on loopback is turned off by default. To turn it on, set this parameter to 0. #### usrsctp_sysctl_set_sctp_nr_outgoing_streams_default() -The peer is notified about the number of outgoing streams in the INIT or INIT-ACK chunk. The default is 10. +The peer is notified about the number of outgoing streams in the INIT or INIT-ACK chunk. The default is 10. #### usrsctp_sysctl_set_sctp_do_drain() Determines whether SCTP should respond to the drain calls. Default: 1 @@ -693,7 +694,7 @@ sctp_use_cwnd_based_maxburst | Use max burst based on the size of the congestion sctp_hb_maxburst | Confirmation Heartbeat max burst | 4 sctp_max_chunks_on_queue | Default max chunks on queue per asoc | 512 sctp_min_split_point | Minimum size when splitting a chunk | 2904 -sctp_chunkscale | Tunable for Scaling of number of chunks and messages | 10 +sctp_chunkscale | Tunable for Scaling of number of chunks and messages | 10 sctp_mbuf_threshold_count | Maximum number of small mbufs in a chain | 5 sctp_heartbeat_interval_default | Deafult time between two Heartbeats | 30000ms sctp_pmtu_raise_time_default | Default PMTU raise timer | 600secs diff --git a/chromium/third_party/usrsctp/usrsctplib/README.md b/chromium/third_party/usrsctp/usrsctplib/README.md index c49ab631711..a59711a1252 100644 --- a/chromium/third_party/usrsctp/usrsctplib/README.md +++ b/chromium/third_party/usrsctp/usrsctplib/README.md @@ -4,4 +4,5 @@ This is a userland SCTP stack supporting FreeBSD, Linux, Mac OS X and Windows. See [manual](Manual.md) for more information. -The status of continous integration testing is available from [grid](http://212.201.121.77:18010/grid) and [waterfall](http://212.201.121.77:18010/waterfall). +The status of continous integration testing is available from [grid](http://212.201.121.110:18010/grid) and [waterfall](http://212.201.121.110:18010/waterfall). +If you are only interested in a single branch, just append `?branch=BRANCHNAME` to the URL, for example [waterfall](http://212.201.121.110:18010/waterfall?branch=master). diff --git a/chromium/third_party/usrsctp/usrsctplib/bootstrap b/chromium/third_party/usrsctp/usrsctplib/bootstrap index 0f543bc56c4..89c7bbabd90 100755 --- a/chromium/third_party/usrsctp/usrsctplib/bootstrap +++ b/chromium/third_party/usrsctp/usrsctplib/bootstrap @@ -29,23 +29,38 @@ # SUCH DAMAGE. # -if [ -e /usr/bin/glibtoolize ] ; then - glibtoolize --force -elif [ -e /usr/bin/libtoolize ] ; then - libtoolize --force -elif [ -e /usr/local/bin/libtoolize ] ; then - libtoolize --force -elif [ -e /usr/local/bin/glibtoolize ] ; then - glibtoolize --force +#bail out on error +set -e + +#detect (g)libtoolize +if which libtoolize >/dev/null +then + _LIBTOOLIZE=`which libtoolize` +elif which glibtoolize >/dev/null +then + _LIBTOOLIZE=`which glibtoolize` else - echo "ERROR: I cannot find libtoolize or glibtoolize!" - exit 1 + echo "ERROR: I cannot find libtoolize or glibtoolize!" + exit 1 fi -if [ -e /usr/local/share/aclocal ] ; then +#execute (g)libtoolize +${_LIBTOOLIZE} + +#execute aclocal +if [ -e /usr/local/share/aclocal ] +then aclocal -I /usr/local/share/aclocal -else +elif [ -e /usr/share/aclocal ] +then aclocal -I /usr/share/aclocal +else + aclocal fi + +#execute autoconf autoconf + +#generate the ./configure automake --foreign --add-missing --copy + diff --git a/chromium/third_party/usrsctp/usrsctplib/configure.ac b/chromium/third_party/usrsctp/usrsctplib/configure.ac index f3375cc46cb..efe2c31d627 100644 --- a/chromium/third_party/usrsctp/usrsctplib/configure.ac +++ b/chromium/third_party/usrsctp/usrsctplib/configure.ac @@ -28,7 +28,7 @@ dnl OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF dnl SUCH DAMAGE. dnl -AC_INIT([libusrsctp], [0.9.2.1]) +AC_INIT([libusrsctp], [0.9.3.0]) AM_INIT_AUTOMAKE AC_PROG_CC diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/CMakeLists.txt b/chromium/third_party/usrsctp/usrsctplib/programs/CMakeLists.txt index f4f549d1e24..e211260ed13 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/CMakeLists.txt +++ b/chromium/third_party/usrsctp/usrsctplib/programs/CMakeLists.txt @@ -28,7 +28,6 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -message(">> WARNINING: CMAKE SUPPORT IS EXPERIMENTAL <<") cmake_minimum_required(VERSION 2.6) include_directories(../usrsctplib) @@ -89,12 +88,17 @@ if(HAVE_SIN6_LEN) add_definitions(-DHAVE_SIN6_LEN) endif() +check_struct_has_member("struct sockaddr_conn" "sconn_len" "usrsctp.h" HAVE_SCONN_LEN) +if(HAVE_SCONN_LEN) + add_definitions(-DHAVE_SCONN_LEN) +endif() + ################################################# # CHECK OPTIONS ################################################# -option(SCTP_DEBUG "Provide debug information" 0) +option(SCTP_DEBUG "Provide debug information" 1) if (SCTP_DEBUG) add_definitions(-DSCTP_DEBUG) endif() @@ -110,6 +114,7 @@ if (INET6) endif() option(LINK_STATIC "Link static" 0) + # xxx enable W32 support for shared lib ... if (LINK_STATIC OR WIN32) set(LINK_STATIC "usrsctp-static") @@ -119,6 +124,7 @@ endif() option(WERROR "Warning as error" ON) + ################################################# # OS DEPENDENT ################################################# @@ -127,19 +133,10 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") add_definitions(-D_GNU_SOURCE) endif() -if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") - add_definitions(-DHAVE_SCONN_LEN) -endif() - if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_definitions(-DHAVE_SCONN_LEN) add_definitions(-D__APPLE_USE_RFC_2292) endif() -if (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") - add_definitions(-DHAVE_SCONN_LEN) -endif() - ################################################# # MISC @@ -162,10 +159,35 @@ SET (check_PROGRAMS ekr_loop.c ekr_peer.c ekr_server.c + http_client.c rtcweb.c + test_libmgmt.c tsctp.c ) +# SETTINGS FOR UNIX COMPILER +IF ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang" OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xGNU") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -std=c99") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -std=c99") + if (WERROR) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + endif() +ENDIF () + +# SETTINGS FOR VISUAL STUDIO COMPILER +IF ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC") + IF (CMAKE_C_FLAGS MATCHES "/W[0-4]") + STRING(REGEX REPLACE "/W[0-4]" "/W3" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + ELSE () + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3") + ENDIF () + + IF (WERROR) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") + ENDIF() +ENDIF () + FOREACH (source_file ${check_PROGRAMS}) GET_FILENAME_COMPONENT (source_file_we ${source_file} NAME_WE) ADD_EXECUTABLE ( @@ -179,27 +201,4 @@ FOREACH (source_file ${check_PROGRAMS}) ) ADD_TEST (${source_file_we} ${source_file_we}) - - IF ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang" OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xGNU") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pedantic -Wall -std=c99") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -pedantic -Wall -std=c99") - if (WERROR) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") - endif() - ENDIF () - - IF ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC") - IF (CMAKE_C_FLAGS MATCHES "/W[0-4]") - STRING(REGEX REPLACE "/W[0-4]" "/W3" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - ELSE () - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3") - ENDIF () - - IF (WERROR) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") - ENDIF() - - - ENDIF () ENDFOREACH () diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/Makefile.am b/chromium/third_party/usrsctp/usrsctplib/programs/Makefile.am index c1759f12b90..5f4fb4ebcc5 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/Makefile.am +++ b/chromium/third_party/usrsctp/usrsctplib/programs/Makefile.am @@ -29,8 +29,11 @@ # AM_CPPFLAGS = -I$(srcdir)/../usrsctplib -EXTRA_DIST = Makefile.nmake tsctp.c daytime_server.c discard_server.c echo_server.c client.c rtcweb.c ekr_client.c ekr_server.c ekr_loop.c -noinst_PROGRAMS = tsctp daytime_server discard_server echo_server client rtcweb ekr_client ekr_server ekr_peer ekr_loop +EXTRA_DIST = Makefile.nmake tsctp.c daytime_server.c discard_server.c echo_server.c client.c rtcweb.c ekr_client.c ekr_server.c ekr_loop.c test_libmgmt.c http_client.c + +noinst_PROGRAMS = tsctp daytime_server discard_server echo_server client rtcweb ekr_client ekr_server ekr_peer ekr_loop test_libmgmt http_client +test_libmgmt_SOURCES = test_libmgmt.c +test_libmgmt_LDADD = ../usrsctplib/libusrsctp.la tsctp_SOURCES = tsctp.c tsctp_LDADD = ../usrsctplib/libusrsctp.la daytime_server_SOURCES = daytime_server.c @@ -51,4 +54,5 @@ ekr_peer_SOURCES = ekr_peer.c ekr_peer_LDADD = ../usrsctplib/libusrsctp.la ekr_loop_SOURCES = ekr_loop.c ekr_loop_LDADD = ../usrsctplib/libusrsctp.la - +http_client_SOURCES = http_client.c +http_client_LDADD = ../usrsctplib/libusrsctp.la diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/Makefile.nmake b/chromium/third_party/usrsctp/usrsctplib/programs/Makefile.nmake index 9fe03bc4d9b..f3800e22e5d 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/Makefile.nmake +++ b/chromium/third_party/usrsctp/usrsctplib/programs/Makefile.nmake @@ -47,7 +47,9 @@ all: \ ekr_client \ ekr_server \ ekr_peer \ - ekr_loop + ekr_loop \ + test_libmgmt \ + http_client client: $(CC) $(CFLAGS) $(CVARSDLL) -c client.c @@ -89,6 +91,14 @@ ekr_loop: $(CC) $(CFLAGS) $(CVARSDLL) -c ekr_loop.c link -out:ekr_loop.exe ekr_loop.obj $(LINKFLAGS) +test_libmgmt: + $(CC) $(CFLAGS) $(CVARSDLL) -c test_libmgmt.c + link -out:test_libmgmt.exe test_libmgmt.obj $(LINKFLAGS) + +http_client: + $(CC) $(CFLAGS) $(CVARSDLL) -c http_client.c + link -out:http_client.exe http_client.obj $(LINKFLAGS) + clean: del /F client.exe del /F client.obj @@ -110,3 +120,7 @@ clean: del /F ekr_peer.obj del /F ekr_loop.exe del /F ekr_loop.obj + del /F test_libmgmt.exe + del /F test_libmgmt.obj + del /F http_client.exe + del /F http_client.obj diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/client.c b/chromium/third_party/usrsctp/usrsctplib/programs/client.c index 02d20b97498..54c7148a36f 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/client.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/client.c @@ -64,7 +64,7 @@ receive_cb(struct socket *sock, union sctp_sockstore addr, void *data, usrsctp_close(sock); } else { #ifdef _WIN32 - _write(_fileno(stdout), data, datalen); + _write(_fileno(stdout), data, (unsigned int)datalen); #else if (write(fileno(stdout), data, datalen) < 0) { perror("write"); @@ -169,8 +169,8 @@ main(int argc, char *argv[]) const char *name; sin = (struct sockaddr_in *)addr; - name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN); - printf("%s", name); + name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN); + printf("%s", name); #ifndef HAVE_SA_LEN addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in)); #endif @@ -183,8 +183,8 @@ main(int argc, char *argv[]) const char *name; sin6 = (struct sockaddr_in6 *)addr; - name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN); - printf("%s", name); + name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN); + printf("%s", name); #ifndef HAVE_SA_LEN addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6)); #endif @@ -217,8 +217,8 @@ main(int argc, char *argv[]) const char *name; sin = (struct sockaddr_in *)addr; - name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN); - printf("%s", name); + name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN); + printf("%s", name); #ifndef HAVE_SA_LEN addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in)); #endif @@ -231,8 +231,8 @@ main(int argc, char *argv[]) const char *name; sin6 = (struct sockaddr_in6 *)addr; - name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN); - printf("%s", name); + name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN); + printf("%s", name); #ifndef HAVE_SA_LEN addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6)); #endif diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/datachan_serv.c b/chromium/third_party/usrsctp/usrsctplib/programs/datachan_serv.c index 3bd2a578197..13a0c27c566 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/datachan_serv.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/datachan_serv.c @@ -417,7 +417,7 @@ main(int argc, char *argv[]) else { struct rtcweb_datachannel_msg msg[4]; /* cheat to get space for label */ int stream, reliable; - int len; + size_t len; uint32_t timeout; uint32_t flags; diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/discard_server.c b/chromium/third_party/usrsctp/usrsctplib/programs/discard_server.c index 2a50d6fd75a..e7c789ddf3f 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/discard_server.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/discard_server.c @@ -91,7 +91,7 @@ receive_cb(struct socket *sock, union sctp_sockstore addr, void *data, port = 0; break; } - printf("Msg of length %d received from %s:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u.\n", + printf("Msg of length %d received from %s:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u.\n", (int)datalen, name, port, @@ -147,7 +147,7 @@ main(int argc, char *argv[]) usrsctp_init(9899, NULL, debug_printf); } #ifdef SCTP_DEBUG - usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE); + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); #endif usrsctp_sysctl_set_sctp_blackhole(2); @@ -215,7 +215,7 @@ main(int argc, char *argv[]) printf("Notification of length %llu received.\n", (unsigned long long)n); } else { if (infotype == SCTP_RECVV_RCVINFO) { - printf("Msg of length %llu received from %s:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u, complete %d.\n", + printf("Msg of length %llu received from %s:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u, complete %d.\n", (unsigned long long)n, inet_ntop(AF_INET6, &addr.sin6_addr, name, INET6_ADDRSTRLEN), ntohs(addr.sin6_port), rcv_info.rcv_sid, diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/echo_server.c b/chromium/third_party/usrsctp/usrsctplib/programs/echo_server.c index ae507b7b18b..38f1e133339 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/echo_server.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/echo_server.c @@ -91,7 +91,7 @@ receive_cb(struct socket *sock, union sctp_sockstore addr, void *data, port = 0; break; } - printf("Msg of length %d received from %s:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u.\n", + printf("Msg of length %d received from %s:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u.\n", (int)datalen, name, port, @@ -230,7 +230,7 @@ main(int argc, char *argv[]) printf("Notification of length %llu received.\n", (unsigned long long)n); } else { if (infotype == SCTP_RECVV_RCVINFO) { - printf("Msg of length %llu received from %s:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u, complete %d.\n", + printf("Msg of length %llu received from %s:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u, complete %d.\n", (unsigned long long)n, inet_ntop(AF_INET6, &addr.sin6_addr, name, INET6_ADDRSTRLEN), ntohs(addr.sin6_port), rcv_info.rcv_sid, diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/ekr_client.c b/chromium/third_party/usrsctp/usrsctplib/programs/ekr_client.c index 8e745c608c3..e1ed50961d3 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/ekr_client.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/ekr_client.c @@ -75,6 +75,9 @@ handle_packets(void *arg) fdp = (int *)arg; #endif for (;;) { +#if defined(__NetBSD__) + pthread_testcancel(); +#endif length = recv(*fdp, buf, MAX_PACKET_SIZE, 0); if (length > 0) { if ((dump_buf = usrsctp_dumppacket(buf, (size_t)length, SCTP_DUMP_INBOUND)) != NULL) { @@ -111,7 +114,7 @@ conn_output(void *addr, void *buf, size_t length, uint8_t tos, uint8_t set_df) usrsctp_freedumpbuffer(dump_buf); } #ifdef _WIN32 - if (send(*fdp, buf, length, 0) == SOCKET_ERROR) { + if (send(*fdp, buf, (int)length, 0) == SOCKET_ERROR) { return (WSAGetLastError()); #else if (send(*fdp, buf, length, 0) < 0) { @@ -131,7 +134,7 @@ receive_cb(struct socket *sock, union sctp_sockstore addr, void *data, if (flags & MSG_NOTIFICATION) { printf("Notification of length %d received.\n", (int)datalen); } else { - printf("Msg of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u.\n", + printf("Msg of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u.\n", (int)datalen, addr.sconn.sconn_addr, ntohs(addr.sconn.sconn_port), @@ -196,7 +199,7 @@ main(int argc, char *argv[]) /* set up a connected UDP socket */ #ifdef _WIN32 if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { - printf("socket() failed with error: %ld\n", WSAGetLastError()); + printf("socket() failed with error: %d\n", WSAGetLastError()); } #else if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { @@ -215,7 +218,7 @@ main(int argc, char *argv[]) } #ifdef _WIN32 if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("bind() failed with error: %ld\n", WSAGetLastError()); + printf("bind() failed with error: %d\n", WSAGetLastError()); } #else if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) { @@ -234,7 +237,7 @@ main(int argc, char *argv[]) } #ifdef _WIN32 if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("connect() failed with error: %ld\n", WSAGetLastError()); + printf("connect() failed with error: %d\n", WSAGetLastError()); } #else if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) { @@ -299,7 +302,7 @@ main(int argc, char *argv[]) TerminateThread(tid, 0); WaitForSingleObject(tid, INFINITE); if (closesocket(fd) == SOCKET_ERROR) { - printf("closesocket() failed with error: %ld\n", WSAGetLastError()); + printf("closesocket() failed with error: %d\n", WSAGetLastError()); } WSACleanup(); #else diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/ekr_loop.c b/chromium/third_party/usrsctp/usrsctplib/programs/ekr_loop.c index b7c4dcb3f10..c81a9461e76 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/ekr_loop.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/ekr_loop.c @@ -75,6 +75,9 @@ handle_packets(void *arg) fdp = (int *)arg; #endif for (;;) { +#if defined(__NetBSD__) + pthread_testcancel(); +#endif length = recv(*fdp, buf, MAX_PACKET_SIZE, 0); if (length > 0) { if ((dump_buf = usrsctp_dumppacket(buf, (size_t)length, SCTP_DUMP_INBOUND)) != NULL) { @@ -111,7 +114,7 @@ conn_output(void *addr, void *buf, size_t length, uint8_t tos, uint8_t set_df) usrsctp_freedumpbuffer(dump_buf); } #ifdef _WIN32 - if (send(*fdp, buf, length, 0) == SOCKET_ERROR) { + if (send(*fdp, buf, (int)length, 0) == SOCKET_ERROR) { return (WSAGetLastError()); #else if (send(*fdp, buf, length, 0) < 0) { @@ -129,7 +132,7 @@ receive_cb(struct socket *sock, union sctp_sockstore addr, void *data, printf("Message %p received on sock = %p.\n", data, (void *)sock); if (data) { if ((flags & MSG_NOTIFICATION) == 0) { - printf("Messsage of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u, flags %x.\n", + printf("Messsage of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u, flags %x.\n", (int)datalen, addr.sconn.sconn_addr, ntohs(addr.sconn.sconn_port), @@ -296,11 +299,11 @@ main(void) /* set up a connected UDP socket */ #ifdef _WIN32 if ((fd_c = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { - printf("socket() failed with error: %ld\n", WSAGetLastError()); + printf("socket() failed with error: %d\n", WSAGetLastError()); exit(EXIT_FAILURE); } if ((fd_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { - printf("socket() failed with error: %ld\n", WSAGetLastError()); + printf("socket() failed with error: %d\n", WSAGetLastError()); exit(EXIT_FAILURE); } #else @@ -325,15 +328,15 @@ main(void) #ifdef HAVE_SIN_LEN sin_s.sin_len = sizeof(struct sockaddr_in); #endif - sin_s.sin_port = htons(9899); + sin_s.sin_port = htons(9901); sin_s.sin_addr.s_addr = htonl(INADDR_LOOPBACK); #ifdef _WIN32 if (bind(fd_c, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("bind() failed with error: %ld\n", WSAGetLastError()); + printf("bind() failed with error: %d\n", WSAGetLastError()); exit(EXIT_FAILURE); } if (bind(fd_s, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("bind() failed with error: %ld\n", WSAGetLastError()); + printf("bind() failed with error: %d\n", WSAGetLastError()); exit(EXIT_FAILURE); } #else @@ -348,11 +351,11 @@ main(void) #endif #ifdef _WIN32 if (connect(fd_c, (struct sockaddr *)&sin_s, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("connect() failed with error: %ld\n", WSAGetLastError()); + printf("connect() failed with error: %d\n", WSAGetLastError()); exit(EXIT_FAILURE); } if (connect(fd_s, (struct sockaddr *)&sin_c, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("connect() failed with error: %ld\n", WSAGetLastError()); + printf("connect() failed with error: %d\n", WSAGetLastError()); exit(EXIT_FAILURE); } #else @@ -380,7 +383,7 @@ main(void) }; #endif #ifdef SCTP_DEBUG - usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE); + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); #endif usrsctp_sysctl_set_sctp_ecn_enable(0); usrsctp_register_address((void *)&fd_c); @@ -508,11 +511,11 @@ main(void) TerminateThread(tid_s, 0); WaitForSingleObject(tid_s, INFINITE); if (closesocket(fd_c) == SOCKET_ERROR) { - printf("closesocket() failed with error: %ld\n", WSAGetLastError()); + printf("closesocket() failed with error: %d\n", WSAGetLastError()); exit(EXIT_FAILURE); } if (closesocket(fd_s) == SOCKET_ERROR) { - printf("closesocket() failed with error: %ld\n", WSAGetLastError()); + printf("closesocket() failed with error: %d\n", WSAGetLastError()); exit(EXIT_FAILURE); } WSACleanup(); diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/ekr_peer.c b/chromium/third_party/usrsctp/usrsctplib/programs/ekr_peer.c index 4c583e40d86..7613e42da12 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/ekr_peer.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/ekr_peer.c @@ -75,6 +75,9 @@ handle_packets(void *arg) fdp = (int *)arg; #endif for (;;) { +#if defined(__NetBSD__) + pthread_testcancel(); +#endif length = recv(*fdp, buf, MAX_PACKET_SIZE, 0); if (length > 0) { usrsctp_conninput(fdp, buf, (size_t)length, 0); @@ -102,7 +105,7 @@ conn_output(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df fdp = (int *)addr; #endif #ifdef _WIN32 - if (send(*fdp, buffer, length, 0) == SOCKET_ERROR) { + if (send(*fdp, buffer, (int)length, 0) == SOCKET_ERROR) { return (WSAGetLastError()); #else if (send(*fdp, buffer, length, 0) < 0) { @@ -261,7 +264,7 @@ handle_send_failed_event(struct sctp_send_failed_event *ssfe) if (ssfe->ssfe_flags & ~(SCTP_DATA_SENT | SCTP_DATA_UNSENT)) { printf("(flags = %x) ", ssfe->ssfe_flags); } - printf("message with PPID = %d, SID = %d, flags: 0x%04x due to error = 0x%08x", + printf("message with PPID = %u, SID = %d, flags: 0x%04x due to error = 0x%08x", ntohl(ssfe->ssfe_info.snd_ppid), ssfe->ssfe_info.snd_sid, ssfe->ssfe_info.snd_flags, ssfe->ssfe_error); n = ssfe->ssfe_length - sizeof(struct sctp_send_failed_event); @@ -321,7 +324,7 @@ receive_cb(struct socket *sock, union sctp_sockstore addr, void *data, if (flags & MSG_NOTIFICATION) { handle_notification((union sctp_notification *)data, datalen); } else { - printf("Msg of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u.\n", + printf("Msg of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u.\n", (int)datalen, addr.sconn.sconn_addr, ntohs(addr.sconn.sconn_port), @@ -391,7 +394,7 @@ main(int argc, char *argv[]) /* set up a connected UDP socket */ #ifdef _WIN32 if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { - printf("socket() failed with error: %ld\n", WSAGetLastError()); + printf("socket() failed with error: %d\n", WSAGetLastError()); } #else if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { @@ -410,7 +413,7 @@ main(int argc, char *argv[]) } #ifdef _WIN32 if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("bind() failed with error: %ld\n", WSAGetLastError()); + printf("bind() failed with error: %d\n", WSAGetLastError()); } #else if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) { @@ -429,7 +432,7 @@ main(int argc, char *argv[]) } #ifdef _WIN32 if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("connect() failed with error: %ld\n", WSAGetLastError()); + printf("connect() failed with error: %d\n", WSAGetLastError()); } #else if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) { @@ -521,7 +524,7 @@ main(int argc, char *argv[]) TerminateThread(tid, 0); WaitForSingleObject(tid, INFINITE); if (closesocket(fd) == SOCKET_ERROR) { - printf("closesocket() failed with error: %ld\n", WSAGetLastError()); + printf("closesocket() failed with error: %d\n", WSAGetLastError()); } WSACleanup(); #else diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/ekr_server.c b/chromium/third_party/usrsctp/usrsctplib/programs/ekr_server.c index 61c44a0ca53..6f812175f11 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/ekr_server.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/ekr_server.c @@ -74,6 +74,9 @@ handle_packets(void *arg) fdp = (int *)arg; #endif for (;;) { +#if defined(__NetBSD__) + pthread_testcancel(); +#endif length = recv(*fdp, buf, MAX_PACKET_SIZE, 0); if (length > 0) { if ((dump_buf = usrsctp_dumppacket(buf, (size_t)length, SCTP_DUMP_INBOUND)) != NULL) { @@ -110,7 +113,7 @@ conn_output(void *addr, void *buf, size_t length, uint8_t tos, uint8_t set_df) usrsctp_freedumpbuffer(dump_buf); } #ifdef _WIN32 - if (send(*fdp, buf, length, 0) == SOCKET_ERROR) { + if (send(*fdp, buf, (int)length, 0) == SOCKET_ERROR) { return (WSAGetLastError()); #else if (send(*fdp, buf, length, 0) < 0) { @@ -130,7 +133,7 @@ receive_cb(struct socket *s, union sctp_sockstore addr, void *data, if (flags & MSG_NOTIFICATION) { printf("Notification of length %d received.\n", (int)datalen); } else { - printf("Msg of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u.\n", + printf("Msg of length %d received via %p:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u.\n", (int)datalen, addr.sconn.sconn_addr, ntohs(addr.sconn.sconn_port), @@ -192,7 +195,7 @@ main(int argc, char *argv[]) /* set up a connected UDP socket */ #ifdef _WIN32 if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { - printf("socket() failed with error: %ld\n", WSAGetLastError()); + printf("socket() failed with error: %d\n", WSAGetLastError()); } #else if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { @@ -211,7 +214,7 @@ main(int argc, char *argv[]) } #ifdef _WIN32 if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("bind() failed with error: %ld\n", WSAGetLastError()); + printf("bind() failed with error: %d\n", WSAGetLastError()); } #else if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) { @@ -230,7 +233,7 @@ main(int argc, char *argv[]) } #ifdef _WIN32 if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { - printf("connect() failed with error: %ld\n", WSAGetLastError()); + printf("connect() failed with error: %d\n", WSAGetLastError()); } #else if (connect(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) { @@ -281,7 +284,7 @@ main(int argc, char *argv[]) TerminateThread(tid, 0); WaitForSingleObject(tid, INFINITE); if (closesocket(fd) == SOCKET_ERROR) { - printf("closesocket() failed with error: %ld\n", WSAGetLastError()); + printf("closesocket() failed with error: %d\n", WSAGetLastError()); } WSACleanup(); #else diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/http_client.c b/chromium/third_party/usrsctp/usrsctplib/programs/http_client.c new file mode 100644 index 00000000000..6dfd1ee7dd8 --- /dev/null +++ b/chromium/third_party/usrsctp/usrsctplib/programs/http_client.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2016 Felix Weinrank + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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. + */ + +/* + * Usage: http_client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri] + */ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#ifndef _WIN32 +#include <unistd.h> +#endif +#include <sys/types.h> +#ifndef _WIN32 +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#else +#include <io.h> +#endif +#include <usrsctp.h> + +int done = 0; +static const char *request_prefix = "GET"; +static const char *request_postfix = "HTTP/1.0\r\nUser-agent: libusrsctp\r\nConnection: close\r\n\r\n"; +char request[512]; + +#ifdef _WIN32 +typedef char* caddr_t; +#endif + +static int +receive_cb(struct socket *sock, union sctp_sockstore addr, void *data, + size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info) +{ + if (data == NULL) { + done = 1; + usrsctp_close(sock); + } else { +#ifdef _WIN32 + _write(_fileno(stdout), data, (unsigned int)datalen); +#else + if (write(fileno(stdout), data, datalen) < 0) { + perror("write"); + } +#endif + free(data); + } + return (1); +} + +void +debug_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); +} + +int +main(int argc, char *argv[]) +{ + struct socket *sock; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + struct sctp_udpencaps encaps; + int result; + + if (argc < 3) { + printf("Usage: http_client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri]\n"); + return(EXIT_FAILURE); + } + + result = 0; + if (argc > 4) { + usrsctp_init(atoi(argv[4]), NULL, debug_printf); + } else { + usrsctp_init(9899, NULL, debug_printf); + } + +#ifdef SCTP_DEBUG + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); +#endif + + usrsctp_sysctl_set_sctp_blackhole(2); + + if ((sock = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, receive_cb, NULL, 0, NULL)) == NULL) { + perror("usrsctp_socket"); + result = 1; + goto out; + } + + if (argc > 3) { + memset((void *)&addr6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN6_LEN + addr6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(atoi(argv[3])); + addr6.sin6_addr = in6addr_any; + if (usrsctp_bind(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) { + perror("bind"); + usrsctp_close(sock); + result = 2; + goto out; + } + } + + if (argc > 5) { + memset(&encaps, 0, sizeof(struct sctp_udpencaps)); + encaps.sue_address.ss_family = AF_INET6; + encaps.sue_port = htons(atoi(argv[5])); + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void *)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) { + perror("setsockopt"); + usrsctp_close(sock); + result = 3; + goto out; + } + } + + if (argc > 6) { +#ifdef _WIN32 + _snprintf(request, sizeof(request), "%s %s %s", request_prefix, argv[6], request_postfix); +#else + snprintf(request, sizeof(request), "%s %s %s", request_prefix, argv[6], request_postfix); +#endif + } else { +#ifdef _WIN32 + _snprintf(request, sizeof(request), "%s %s %s", request_prefix, "/", request_postfix); +#else + snprintf(request, sizeof(request), "%s %s %s", request_prefix, "/", request_postfix); +#endif + } + + printf("\nHTTP request:\n%s\n", request); + printf("\nHTTP response:\n"); + + memset((void *)&addr4, 0, sizeof(struct sockaddr_in)); + memset((void *)&addr6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN_LEN + addr4.sin_len = sizeof(struct sockaddr_in); +#endif +#ifdef HAVE_SIN6_LEN + addr6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr4.sin_family = AF_INET; + addr6.sin6_family = AF_INET6; + addr4.sin_port = htons(atoi(argv[2])); + addr6.sin6_port = htons(atoi(argv[2])); + if (inet_pton(AF_INET6, argv[1], &addr6.sin6_addr) == 1) { + if (usrsctp_connect(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) { + perror("usrsctp_connect"); + usrsctp_close(sock); + result = 4; + goto out; + } + } else if (inet_pton(AF_INET, argv[1], &addr4.sin_addr) == 1) { + if (usrsctp_connect(sock, (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)) < 0) { + perror("usrsctp_connect"); + usrsctp_close(sock); + result = 5; + goto out; + } + } else { + printf("Illegal destination address\n"); + usrsctp_close(sock); + result = 6; + goto out; + } + + /* send GET request */ + if (usrsctp_sendv(sock, request, strlen(request), NULL, 0, NULL, 0, SCTP_SENDV_NOINFO, 0) < 0) { + perror("usrsctp_sendv"); + usrsctp_close(sock); + result = 6; + goto out; + } + + while (!done) { +#ifdef _WIN32 + Sleep(1*1000); +#else + sleep(1); +#endif + } +out: + while (usrsctp_finish() != 0) { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + return (result); +} diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/test_libmgmt.c b/chromium/third_party/usrsctp/usrsctplib/programs/test_libmgmt.c new file mode 100644 index 00000000000..de5e0f02a80 --- /dev/null +++ b/chromium/third_party/usrsctp/usrsctplib/programs/test_libmgmt.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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. + */ + +#ifndef _WIN32 +#include <unistd.h> +#endif +#include "usrsctp.h" + +int +main(void) +{ + int i; + + for (i = 0; i < 10000; i++) { + usrsctp_init(0, NULL, NULL); + while (usrsctp_finish() != 0) { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + } + return (0); +} diff --git a/chromium/third_party/usrsctp/usrsctplib/programs/tsctp.c b/chromium/third_party/usrsctp/usrsctplib/programs/tsctp.c index f7975712934..b35fb2a0f22 100644 --- a/chromium/third_party/usrsctp/usrsctplib/programs/tsctp.c +++ b/chromium/third_party/usrsctp/usrsctplib/programs/tsctp.c @@ -318,7 +318,7 @@ server_receive_cb(struct socket *sock, union sctp_sockstore addr, void *data, return (1); } if (first_length == 0) { - first_length = datalen; + first_length = (unsigned int)datalen; gettimeofday(&start_time, NULL); } sum += datalen; @@ -747,7 +747,7 @@ int main(int argc, char **argv) } if (use_cb) { - while (!done && (messages < (number_of_messages - 1))) { + while (done < 2 && (messages < (number_of_messages - 1))) { #ifdef _WIN32 Sleep(1000); #else diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/CMakeLists.txt b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/CMakeLists.txt index e6d5d221925..b8dacb8e4ce 100644 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/CMakeLists.txt +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/CMakeLists.txt @@ -30,10 +30,10 @@ # cmake_minimum_required(VERSION 2.6) -message(">> WARNINING: CMAKE SUPPORT IS EXPERIMENTAL <<") project(usrsctplib) + ################################################# # INCLUDE MODULES ################################################# @@ -50,10 +50,9 @@ SET (prefix ${CMAKE_INSTALL_PREFIX}) SET (exec_prefix "\${prefix}") SET (libdir "\${exec_prefix}/lib") SET (includedir "\${prefix}/include/usrsctp") +SET (CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}) -#include_directories(netinet netinet6) - ################################################# # CHECK FOR TYPES AND FUNCTIONS ################################################# @@ -67,37 +66,44 @@ check_include_file(sys/queue.h HAVE_SYS_QUEUE_H) check_include_file(linux/if_addr.h HAVE_LINUX_IF_ADDR_H) check_include_file(linux/rtnetlink.h HAVE_LINUX_RTNETLINK_H) check_include_file(netinet/ip_icmp.h HAVE_NETINET_IP_ICMP_H) +check_include_file(usrsctp.h HAVE_USRSCTP_H) check_function_exists("socket" HAVE_SOCKET) check_function_exists("inet_addr" HAVE_INET_ADDR) - add_definitions(-D__Userspace__) add_definitions(-D__Userspace_os_${CMAKE_SYSTEM_NAME}) add_definitions(-D_GNU_SOURCE) + ################################################# # CHECK STRUCT MEMBERS ################################################# check_struct_has_member("struct sockaddr" "sa_len" "sys/types.h;sys/socket.h" HAVE_SA_LEN) if(HAVE_SA_LEN) - message("HAVE_SA_LEN") + message(STATUS "HAVE_SA_LEN") add_definitions(-DHAVE_SA_LEN) endif() check_struct_has_member("struct sockaddr_in" "sin_len" "sys/types.h;netinet/in.h" HAVE_SIN_LEN) if(HAVE_SIN_LEN) - message("HAVE_SIN_LEN") + message(STATUS "HAVE_SIN_LEN") add_definitions(-DHAVE_SIN_LEN) endif() check_struct_has_member("struct sockaddr_in6" "sin6_len" "sys/types.h;netinet/in.h" HAVE_SIN6_LEN) if(HAVE_SIN6_LEN) - message("HAVE_SIN6_LEN") + message(STATUS "HAVE_SIN6_LEN") add_definitions(-DHAVE_SIN6_LEN) endif() +check_struct_has_member("struct sockaddr_conn" "sconn_len" "usrsctp.h" HAVE_SCONN_LEN) +if(HAVE_SCONN_LEN) + message(STATUS "HAVE_SCONN_LEN") + add_definitions(-DHAVE_SCONN_LEN) +endif() + ################################################# # OS DEPENDENT @@ -109,11 +115,9 @@ endif() if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") add_definitions(-U__FreeBSD__) - add_definitions(-DHAVE_SCONN_LEN) endif() if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_definitions(-DHAVE_SCONN_LEN) add_definitions(-U__APPLE__) add_definitions(-D__APPLE_USE_RFC_2292) endif() @@ -127,7 +131,6 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") endif() if (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") - add_definitions(-DHAVE_SCONN_LEN) add_definitions(-U__OpenBSD__) endif() @@ -201,15 +204,15 @@ option(WERROR "Warning as error" ON) include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/netinet ${PROJECT_SOURCE_DIR}/netinet6) LIST (APPEND usrsctp_root_HEADERS -user_atomic.h user_inpcb.h user_ip_icmp.h user_mbuf.h user_recv_thread.h user_socketvar.h usrsctp.h -user_environment.h user_ip6_var.h user_malloc.h user_queue.h user_route.h user_uma.h + user_atomic.h user_inpcb.h user_ip_icmp.h user_mbuf.h user_recv_thread.h user_socketvar.h usrsctp.h + user_environment.h user_ip6_var.h user_malloc.h user_queue.h user_route.h user_uma.h ) LIST (APPEND usrsctp_netinet_HEADERS -netinet/sctp_asconf.h netinet/sctp_constants.h netinet/sctp_indata.h netinet/sctp_os_userspace.h netinet/sctp_process_lock.h netinet/sctp_timer.h -netinet/sctp_auth.h netinet/sctp_crc32.h netinet/sctp_input.h netinet/sctp_output.h netinet/sctp_sha1.h netinet/sctp_uio.h -netinet/sctp_bsd_addr.h netinet/sctp.h netinet/sctp_lock_userspace.h netinet/sctp_pcb.h netinet/sctp_structs.h netinet/sctputil.h -netinet/sctp_callout.h netinet/sctp_header.h netinet/sctp_os.h netinet/sctp_peeloff.h netinet/sctp_sysctl.h netinet/sctp_var.h + netinet/sctp_asconf.h netinet/sctp_constants.h netinet/sctp_indata.h netinet/sctp_os_userspace.h netinet/sctp_process_lock.h netinet/sctp_timer.h + netinet/sctp_auth.h netinet/sctp_crc32.h netinet/sctp_input.h netinet/sctp_output.h netinet/sctp_sha1.h netinet/sctp_uio.h + netinet/sctp_bsd_addr.h netinet/sctp.h netinet/sctp_lock_userspace.h netinet/sctp_pcb.h netinet/sctp_structs.h netinet/sctputil.h + netinet/sctp_callout.h netinet/sctp_header.h netinet/sctp_os.h netinet/sctp_peeloff.h netinet/sctp_sysctl.h netinet/sctp_var.h ) LIST (APPEND usrsctp_netinet6_HEADERS @@ -223,17 +226,17 @@ LIST (APPEND usrsctp_HEADERS ) LIST (APPEND usrsctp_SOURCES -netinet6/sctp6_usrreq.c netinet/sctp_callout.c netinet/sctp_input.c netinet/sctp_sha1.c netinet/sctp_userspace.c user_mbuf.c -netinet/sctp_asconf.c netinet/sctp_cc_functions.c netinet/sctp_output.c netinet/sctp_ss_functions.c netinet/sctp_usrreq.c user_recv_thread.c -netinet/sctp_auth.c netinet/sctp_crc32.c netinet/sctp_pcb.c netinet/sctp_sysctl.c netinet/sctputil.c user_socket.c -netinet/sctp_bsd_addr.c netinet/sctp_indata.c netinet/sctp_peeloff.c netinet/sctp_timer.c user_environment.c + netinet6/sctp6_usrreq.c netinet/sctp_callout.c netinet/sctp_input.c netinet/sctp_sha1.c netinet/sctp_userspace.c user_mbuf.c + netinet/sctp_asconf.c netinet/sctp_cc_functions.c netinet/sctp_output.c netinet/sctp_ss_functions.c netinet/sctp_usrreq.c user_recv_thread.c + netinet/sctp_auth.c netinet/sctp_crc32.c netinet/sctp_pcb.c netinet/sctp_sysctl.c netinet/sctputil.c user_socket.c + netinet/sctp_bsd_addr.c netinet/sctp_indata.c netinet/sctp_peeloff.c netinet/sctp_timer.c user_environment.c ) add_library(usrsctp SHARED ${usrsctp_SOURCES} ${usrsctp_HEADERS}) add_library(usrsctp-static STATIC ${usrsctp_SOURCES} ${usrsctp_HEADERS}) if(WIN32) - message("link library: ws2_32") + message(STATUS "link library: ws2_32") target_link_libraries(usrsctp ws2_32) target_link_libraries(usrsctp-static ws2_32) endif() @@ -242,26 +245,27 @@ SET_TARGET_PROPERTIES (usrsctp-static PROPERTIES OUTPUT_NAME "usrsctp") SET_TARGET_PROPERTIES (usrsctp PROPERTIES IMPORT_SUFFIX "_import.lib") SET_TARGET_PROPERTIES (usrsctp PROPERTIES SOVERSION 1 VERSION 1.0.0) +# SETTINGS FOR UNIX COMPILER IF ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang" OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xGNU") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pedantic -Wall -std=c99") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -pedantic -Wall -std=c99") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -std=c99") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -std=c99") if (WERROR) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") endif() - MESSAGE(STATUS "COMPILE FLAGS: ${CMAKE_C_FLAGS}") - #SET_PROPERTY (TARGET usrsctp APPEND_STRING PROPERTY COMPILE_FLAGS "-g -pedantic -Wall -Werror -std=c99") - #SET_PROPERTY (TARGET usrsctp-static APPEND_STRING PROPERTY COMPILE_FLAGS "-g -pedantic -Wall -Werror -std=c99") ENDIF () + +# SETTINGS FOR VISUAL STUDIO COMPILER IF ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC") - IF (CMAKE_C_FLAGS MATCHES "/W[0-4]") - STRING(REGEX REPLACE "/W[0-4]" "/W3" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - ELSE () - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3") - ENDIF () - if (WERROR) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") - endif() + IF (CMAKE_C_FLAGS MATCHES "/W[0-4]") + STRING(REGEX REPLACE "/W[0-4]" "/W3" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + ELSE () + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3") + ENDIF () + + IF (WERROR) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") + ENDIF() ENDIF () IF ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC90" OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC10") diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp.h index 6a24b77d21c..276cade2837 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp.h 287717 2015-09-12 17:08:51Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp.h 297662 2016-04-07 09:10:34Z rrs $"); #endif #ifndef _NETINET_SCTP_H_ @@ -202,6 +202,9 @@ struct sctp_paramhdr { #define SCTP_PLUGGABLE_SS 0x00001203 #define SCTP_SS_VALUE 0x00001204 #define SCTP_CC_OPTION 0x00001205 /* Options for CC modules */ +/* For I-DATA */ +#define SCTP_INTERLEAVING_SUPPORTED 0x00001206 + /* read only */ #define SCTP_GET_SNDBUF_USE 0x00001101 #define SCTP_GET_STAT_LOG 0x00001103 @@ -466,6 +469,7 @@ struct sctp_error_auth_invalid_hmac { /* EY nr_sack chunk id*/ #define SCTP_NR_SELECTIVE_ACK 0x10 /************0x40 series ***********/ +#define SCTP_IDATA 0x40 /************0x80 series ***********/ /* RFC5061 */ #define SCTP_ASCONF_ACK 0x80 @@ -481,7 +485,7 @@ struct sctp_error_auth_invalid_hmac { #define SCTP_FORWARD_CUM_TSN 0xc0 /* RFC5061 */ #define SCTP_ASCONF 0xc1 - +#define SCTP_IFORWARD_CUM_TSN 0xc2 /* ABORT and SHUTDOWN COMPLETE FLAG */ #define SCTP_HAD_NO_TCB 0x01 diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_asconf.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_asconf.c index 3b75e90d893..0c837bf7680 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_asconf.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_asconf.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 285925 2015-07-27 22:35:54Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 298847 2016-04-30 14:25:00Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -248,8 +248,9 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap m_reply = sctp_asconf_error_response(aph->correlation_id, SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, aparam_length); - } else if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE, - SCTP_ADDR_DYNAMIC_ADDED) != 0) { + } else if (sctp_add_remote_addr(stcb, sa, &net, stcb->asoc.port, + SCTP_DONOT_SETSCOPE, + SCTP_ADDR_DYNAMIC_ADDED) != 0) { SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: error adding address\n"); m_reply = sctp_asconf_error_response(aph->correlation_id, @@ -3270,6 +3271,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, } else { struct sctp_asconf_iterator *asc; struct sctp_laddr *wi; + int ret; SCTP_MALLOC(asc, struct sctp_asconf_iterator *, sizeof(struct sctp_asconf_iterator), @@ -3291,7 +3293,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, wi->action = type; atomic_add_int(&ifa->refcount, 1); LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); - (void)sctp_initiate_iterator(sctp_asconf_iterator_ep, + ret = sctp_initiate_iterator(sctp_asconf_iterator_ep, sctp_asconf_iterator_stcb, sctp_asconf_iterator_ep_end, SCTP_PCB_ANY_FLAGS, @@ -3299,6 +3301,12 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, SCTP_ASOC_ANY_STATE, (void *)asc, 0, sctp_asconf_iterator_end, inp, 0); + if (ret) { + SCTP_PRINTF("Failed to initiate iterator for addr_mgmt_ep_sa\n"); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EFAULT); + sctp_asconf_iterator_end(asc, 0); + return (EFAULT); + } } return (0); } else { diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_auth.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_auth.c index 3135b6bc186..1f080f40660 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_auth.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_auth.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 289570 2015-10-19 11:17:54Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_auth.c 302928 2016-07-16 07:48:01Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -544,7 +544,7 @@ sctp_insert_sharedkey(struct sctp_keyhead *shared_keys, } } /* shouldn't reach here */ - return (0); + return (EINVAL); } void @@ -624,8 +624,11 @@ sctp_copy_skeylist(const struct sctp_keyhead *src, struct sctp_keyhead *dest) LIST_FOREACH(skey, src, next) { new_skey = sctp_copy_sharedkey(skey); if (new_skey != NULL) { - (void)sctp_insert_sharedkey(dest, new_skey); - count++; + if (sctp_insert_sharedkey(dest, new_skey)) { + sctp_free_sharedkey(new_skey); + } else { + count++; + } } } return (count); diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_bsd_addr.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_bsd_addr.c index 00772b69d39..eece86fafdf 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_bsd_addr.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_bsd_addr.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.c 276914 2015-01-10 20:49:57Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_bsd_addr.c 298942 2016-05-02 20:56:11Z pfg $"); #endif #include <netinet/sctp_os.h> @@ -306,19 +306,10 @@ sctp_is_vmware_interface(struct ifnet *ifn) #endif #if defined(__Userspace_os_Windows) -#ifdef MALLOC -#undef MALLOC -#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) -#endif -#ifdef FREE -#undef FREE -#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) -#endif static void sctp_init_ifns_for_vrf(int vrfid) { #if defined(INET) || defined(INET6) - struct ifaddrs *ifa; struct sctp_ifa *sctp_ifa; DWORD Err, AdapterAddrsSize; PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt; @@ -344,6 +335,7 @@ sctp_init_ifns_for_vrf(int vrfid) /* Get actual adapter information */ if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { SCTP_PRINTF("GetAdaptersV4Addresses() failed with error code %d\n", Err); + GlobalFree(pAdapterAddrs); return; } /* Enumerate through each returned adapter and save its information */ @@ -353,20 +345,14 @@ sctp_init_ifns_for_vrf(int vrfid) if (IN4_ISLINKLOCAL_ADDRESS(&(((struct sockaddr_in *)(pUnicast->Address.lpSockaddr))->sin_addr))) { continue; } - ifa = (struct ifaddrs*)malloc(sizeof(struct ifaddrs)); - ifa->ifa_name = _strdup(pAdapt->AdapterName); - ifa->ifa_flags = pAdapt->Flags; - ifa->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in)); - memcpy(ifa->ifa_addr, pUnicast->Address.lpSockaddr, sizeof(struct sockaddr_in)); - sctp_ifa = sctp_add_addr_to_vrf(0, - ifa, + NULL, pAdapt->IfIndex, (pAdapt->IfType == IF_TYPE_IEEE80211)?MIB_IF_TYPE_ETHERNET:pAdapt->IfType, - ifa->ifa_name, - (void *)ifa, - ifa->ifa_addr, - ifa->ifa_flags, + pAdapt->AdapterName, + NULL, + pUnicast->Address.lpSockaddr, + pAdapt->Flags, 0); if (sctp_ifa) { sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; @@ -374,8 +360,7 @@ sctp_init_ifns_for_vrf(int vrfid) } } } - if (pAdapterAddrs) - FREE(pAdapterAddrs); + GlobalFree(pAdapterAddrs); #endif #ifdef INET6 AdapterAddrsSize = 0; @@ -395,25 +380,21 @@ sctp_init_ifns_for_vrf(int vrfid) /* Get actual adapter information */ if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { SCTP_PRINTF("GetAdaptersV6Addresses() failed with error code %d\n", Err); + GlobalFree(pAdapterAddrs); return; } /* Enumerate through each returned adapter and save its information */ for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { if (pAdapt->IfType == IF_TYPE_IEEE80211 || pAdapt->IfType == IF_TYPE_ETHERNET_CSMACD) { for (pUnicast = pAdapt->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { - ifa = (struct ifaddrs*)malloc(sizeof(struct ifaddrs)); - ifa->ifa_name = _strdup(pAdapt->AdapterName); - ifa->ifa_flags = pAdapt->Flags; - ifa->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in6)); - memcpy(ifa->ifa_addr, pUnicast->Address.lpSockaddr, sizeof(struct sockaddr_in6)); sctp_ifa = sctp_add_addr_to_vrf(0, - ifa, + NULL, pAdapt->Ipv6IfIndex, (pAdapt->IfType == IF_TYPE_IEEE80211)?MIB_IF_TYPE_ETHERNET:pAdapt->IfType, - ifa->ifa_name, - (void *)ifa, - ifa->ifa_addr, - ifa->ifa_flags, + pAdapt->AdapterName, + NULL, + pUnicast->Address.lpSockaddr, + pAdapt->Flags, 0); if (sctp_ifa) { sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; @@ -421,8 +402,7 @@ sctp_init_ifns_for_vrf(int vrfid) } } } - if (pAdapterAddrs) - FREE(pAdapterAddrs); + GlobalFree(pAdapterAddrs); #endif } #elif defined(__Userspace__) @@ -431,15 +411,15 @@ sctp_init_ifns_for_vrf(int vrfid) { #if defined(INET) || defined(INET6) int rc; - struct ifaddrs *ifa = NULL; + struct ifaddrs *ifa, *ifas; struct sctp_ifa *sctp_ifa; uint32_t ifa_flags; - rc = getifaddrs(&g_interfaces); + rc = getifaddrs(&ifas); if (rc != 0) { return; } - for (ifa = g_interfaces; ifa; ifa = ifa->ifa_next) { + for (ifa = ifas; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) { continue; } @@ -474,11 +454,11 @@ sctp_init_ifns_for_vrf(int vrfid) #endif ifa_flags = 0; sctp_ifa = sctp_add_addr_to_vrf(vrfid, - ifa, + NULL, if_nametoindex(ifa->ifa_name), 0, ifa->ifa_name, - (void *)ifa, + NULL, ifa->ifa_addr, ifa_flags, 0); @@ -486,6 +466,7 @@ sctp_init_ifns_for_vrf(int vrfid) sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; } } + freeifaddrs(ifas); #endif } #endif @@ -551,11 +532,11 @@ sctp_init_ifns_for_vrf(int vrfid) } snprintf(name, SCTP_IFNAMSIZ, "%s%d", ifnet_name(ifn), ifnet_unit(ifn)); sctp_ifa = sctp_add_addr_to_vrf(vrfid, - (void *)ifn, + (void *)ifn, /* XXX */ ifnet_index(ifn), ifnet_type(ifn), name, - (void *)ifa, + (void *)ifa, /* XXX */ ifa->ifa_addr, ifa_flags, 0); @@ -682,10 +663,14 @@ sctp_addr_change(struct ifaddr *ifa, int cmd) return; #else uint32_t ifa_flags = 0; + + if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { + return; + } /* BSD only has one VRF, if this changes * we will need to hook in the right * things here to get the id to pass to - * the address managment routine. + * the address management routine. */ if (SCTP_BASE_VAR(first_time) == 0) { /* Special test to see if my ::1 will showup with this */ diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_cc_functions.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_cc_functions.c index 5b84bbd4249..b9a684b27b6 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_cc_functions.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_cc_functions.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 283650 2015-05-28 16:00:23Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_cc_functions.c 298942 2016-05-02 20:56:11Z pfg $"); #endif #include <netinet/sctp_os.h> @@ -100,7 +100,7 @@ sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) sctp_enforce_cwnd_limit(assoc, net); net->ssthresh = assoc->peers_rwnd; #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, init, + SDT_PROBE5(sctp, cwnd, net, init, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 0, net->cwnd); #endif @@ -195,7 +195,7 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, net->cwnd = net->ssthresh; sctp_enforce_cwnd_limit(asoc, net); #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, fr, + SDT_PROBE5(sctp, cwnd, net, fr, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, old_cwnd, net->cwnd); #endif @@ -245,7 +245,7 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, } /* Defines for instantaneous bw decisions */ -#define SCTP_INST_LOOSING 1 /* Loosing to other flows */ +#define SCTP_INST_LOOSING 1 /* Losing to other flows */ #define SCTP_INST_NEUTRAL 2 /* Neutral, no indication */ #define SCTP_INST_GAINING 3 /* Gaining, step down possible */ @@ -276,7 +276,7 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 /* Probe point 5 */ probepoint |= ((5 << 16) | 1); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -299,7 +299,7 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -325,7 +325,7 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 /* Probe point 6 */ probepoint |= ((6 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -339,7 +339,7 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -371,7 +371,7 @@ cc_bw_same(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_t nb #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 /* Probe point 7 */ probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -432,7 +432,7 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 /* PROBE POINT 1 */ probepoint |= ((1 << 16) | 1); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -449,7 +449,7 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 /* Probe point 2 */ probepoint |= ((2 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -464,7 +464,7 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -489,7 +489,7 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 /* Probe point 3 */ probepoint |= ((3 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -503,7 +503,7 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -525,7 +525,7 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 /* Probe point 4 */ probepoint |= ((4 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -539,7 +539,7 @@ cc_bw_decrease(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -587,7 +587,7 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 /* PROBE POINT 0 */ probepoint = (((uint64_t)net->cwnd) << 32); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -601,7 +601,7 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -618,7 +618,7 @@ cc_bw_increase(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, uint64_ return (0); } -/* RTCC Algoritm to limit growth of cwnd, return +/* RTCC Algorithm to limit growth of cwnd, return * true if you want to NOT allow cwnd growth */ static int @@ -712,7 +712,7 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) #endif } #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((nbw << 32) | inst_bw), ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), @@ -886,7 +886,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, nbw, ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -986,7 +986,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, SCTP_CWND_LOG_FROM_SS); } #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, ack, + SDT_PROBE5(sctp, cwnd, net, ack, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1050,7 +1050,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, net->cwnd += incr; sctp_enforce_cwnd_limit(asoc, net); #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, ack, + SDT_PROBE5(sctp, cwnd, net, ack, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1091,7 +1091,7 @@ sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_n #endif net->cwnd = net->mtu; #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, ack, + SDT_PROBE5(sctp, cwnd, net, ack, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, old_cwnd, net->cwnd); #endif @@ -1164,7 +1164,7 @@ sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) net->cwnd = net->mtu; net->partial_bytes_acked = 0; #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, to, + SDT_PROBE5(sctp, cwnd, net, to, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1199,7 +1199,7 @@ sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets * sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT); } } else { - /* Further tuning down required over the drastic orginal cut */ + /* Further tuning down required over the drastic original cut */ net->ssthresh -= (net->mtu * num_pkt_lost); net->cwnd -= (net->mtu * num_pkt_lost); if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { @@ -1219,7 +1219,7 @@ sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets * } net->cwnd = net->ssthresh; #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, ecn, + SDT_PROBE5(sctp, cwnd, net, ecn, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1340,7 +1340,7 @@ sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, if (net->cwnd - old_cwnd != 0) { /* log only changes */ #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, pd, + SDT_PROBE5(sctp, cwnd, net, pd, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1365,7 +1365,7 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb, net->cwnd = (net->flight_size + (burst_limit * net->mtu)); sctp_enforce_cwnd_limit(&stcb->asoc, net); #if defined(__FreeBSD__) && __FreeBSD_version >= 803000 - SDT_PROBE(sctp, cwnd, net, bl, + SDT_PROBE5(sctp, cwnd, net, bl, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1382,7 +1382,7 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, struct sctp_association *asoc, int accum_moved, int reneged_all, int will_exit) { - /* Passing a zero argument in last disables the rtcc algoritm */ + /* Passing a zero argument in last disables the rtcc algorithm */ sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0); } @@ -1390,13 +1390,13 @@ static void sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, int in_window, int num_pkt_lost) { - /* Passing a zero argument in last disables the rtcc algoritm */ + /* Passing a zero argument in last disables the rtcc algorithm */ sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0); } /* Here starts the RTCCVAR type CC invented by RRS which * is a slight mod to RFC2581. We reuse a common routine or - * two since these algoritms are so close and need to + * two since these algorithms are so close and need to * remain the same. */ static void @@ -1443,7 +1443,7 @@ sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, probepoint = (((uint64_t)net->cwnd) << 32); /* Probe point 8 */ probepoint |= ((8 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | 0), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -1504,7 +1504,7 @@ sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, vtag = (net->rtt << 32) | (((uint32_t)(stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, 0, 0, @@ -1601,7 +1601,7 @@ sctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb, struct sctp_association *asoc, int accum_moved, int reneged_all, int will_exit) { - /* Passing a one argument at the last enables the rtcc algoritm */ + /* Passing a one argument at the last enables the rtcc algorithm */ sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1); } @@ -1617,13 +1617,13 @@ sctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_hs_raise_drop { int32_t cwnd; - int32_t increase; - int32_t drop_percent; + int8_t increase; + int8_t drop_percent; }; #define SCTP_HS_TABLE_SIZE 73 -struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { +static const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = { {38, 1, 50}, /* 0 */ {118, 2, 44}, /* 1 */ {221, 3, 41}, /* 2 */ @@ -1723,7 +1723,7 @@ sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net) } } net->last_hs_used = indx; - incr = ((sctp_cwnd_adjust[indx].increase) << 10); + incr = (((int32_t)sctp_cwnd_adjust[indx].increase) << 10); net->cwnd += incr; } sctp_enforce_cwnd_limit(&stcb->asoc, net); @@ -1749,7 +1749,7 @@ sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) } else { /* drop by the proper amount */ net->ssthresh = net->cwnd - (int)((net->cwnd / 100) * - sctp_cwnd_adjust[net->last_hs_used].drop_percent); + (int32_t)sctp_cwnd_adjust[net->last_hs_used].drop_percent); net->cwnd = net->ssthresh; /* now where are we */ indx = net->last_hs_used; @@ -2406,7 +2406,7 @@ sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, } } -struct sctp_cc_functions sctp_cc_functions[] = { +const struct sctp_cc_functions sctp_cc_functions[] = { { #if defined(__Windows__) || defined(__Userspace_os_Windows) sctp_set_initial_cc_param, diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_constants.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_constants.h index ec9b86e578f..2b5ac25a668 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_constants.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_constants.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_constants.h 287669 2015-09-11 13:54:33Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_constants.h 302949 2016-07-17 13:14:51Z tuexen $"); #endif #ifndef _NETINET_SCTP_CONSTANTS_H_ @@ -73,6 +73,8 @@ extern void getwintimeofday(struct timeval *tv); /* Largest length of a chunk */ #define SCTP_MAX_CHUNK_LENGTH 0xffff +/* Largest length of an error cause */ +#define SCTP_MAX_CAUSE_LENGTH 0xffff /* Number of addresses where we just skip the counting */ #define SCTP_COUNT_LIMIT 40 @@ -278,7 +280,7 @@ extern void getwintimeofday(struct timeval *tv); #define SCTP_DEFAULT_MULTIPLE_ASCONFS 0 /* - * Theshold for rwnd updates, we have to read (sb_hiwat >> + * Threshold for rwnd updates, we have to read (sb_hiwat >> * SCTP_RWND_HIWAT_SHIFT) before we will look to see if we need to send a * window update sack. When we look, we compare the last rwnd we sent vs the * current rwnd. It too must be greater than this value. Using 3 divdes the @@ -348,6 +350,7 @@ extern void getwintimeofday(struct timeval *tv); #define SCTP_RTT_FROM_NON_DATA 0 #define SCTP_RTT_FROM_DATA 1 +#define PR_SCTP_UNORDERED_FLAG 0x0001 /* IP hdr (20/40) + 12+2+2 (enet) + sctp common 12 */ #define SCTP_FIRST_MBUF_RESV 68 @@ -389,8 +392,8 @@ extern void getwintimeofday(struct timeval *tv); /* align to 32-bit sizes */ #define SCTP_SIZE32(x) ((((x) + 3) >> 2) << 2) -#define IS_SCTP_CONTROL(a) ((a)->chunk_type != SCTP_DATA) -#define IS_SCTP_DATA(a) ((a)->chunk_type == SCTP_DATA) +#define IS_SCTP_CONTROL(a) (((a)->chunk_type != SCTP_DATA) && ((a)->chunk_type != SCTP_IDATA)) +#define IS_SCTP_DATA(a) (((a)->chunk_type == SCTP_DATA) || ((a)->chunk_type == SCTP_IDATA)) /* SCTP parameter types */ @@ -519,7 +522,7 @@ extern void getwintimeofday(struct timeval *tv); /* Maximum the mapping array will grow to (TSN mapping array) */ #define SCTP_MAPPING_ARRAY 512 -/* size of the inital malloc on the mapping array */ +/* size of the initial malloc on the mapping array */ #define SCTP_INITIAL_MAPPING_ARRAY 16 /* how much we grow the mapping array each call */ #define SCTP_MAPPING_ARRAY_INCR 32 @@ -652,7 +655,7 @@ extern void getwintimeofday(struct timeval *tv); #define SCTP_DEF_PMTU_RAISE_SEC 600 /* 10 min between raise attempts */ -/* How many streams I request initally by default */ +/* How many streams I request initially by default */ #define SCTP_OSTREAM_INITIAL 10 #define SCTP_ISTREAM_INITIAL 2048 @@ -909,12 +912,19 @@ extern void getwintimeofday(struct timeval *tv); /* modular comparison */ /* See RFC 1982 for details. */ -#define SCTP_SSN_GT(a, b) (((a < b) && ((uint16_t)(b - a) > (1U<<15))) || \ - ((a > b) && ((uint16_t)(a - b) < (1U<<15)))) -#define SCTP_SSN_GE(a, b) (SCTP_SSN_GT(a, b) || (a == b)) -#define SCTP_TSN_GT(a, b) (((a < b) && ((uint32_t)(b - a) > (1U<<31))) || \ - ((a > b) && ((uint32_t)(a - b) < (1U<<31)))) -#define SCTP_TSN_GE(a, b) (SCTP_TSN_GT(a, b) || (a == b)) +#define SCTP_UINT16_GT(a, b) (((a < b) && ((uint16_t)(b - a) > (1U<<15))) || \ + ((a > b) && ((uint16_t)(a - b) < (1U<<15)))) +#define SCTP_UINT16_GE(a, b) (SCTP_UINT16_GT(a, b) || (a == b)) +#define SCTP_UINT32_GT(a, b) (((a < b) && ((uint32_t)(b - a) > (1U<<31))) || \ + ((a > b) && ((uint32_t)(a - b) < (1U<<31)))) +#define SCTP_UINT32_GE(a, b) (SCTP_UINT32_GT(a, b) || (a == b)) + +#define SCTP_SSN_GT(a, b) SCTP_UINT16_GT(a, b) +#define SCTP_SSN_GE(a, b) SCTP_UINT16_GE(a, b) +#define SCTP_TSN_GT(a, b) SCTP_UINT32_GT(a, b) +#define SCTP_TSN_GE(a, b) SCTP_UINT32_GE(a, b) +#define SCTP_MSGID_GT(o, a, b) ((o == 1) ? SCTP_UINT16_GT((uint16_t)a, (uint16_t)b) : SCTP_UINT32_GT(a, b)) +#define SCTP_MSGID_GE(o, a, b) ((o == 1) ? SCTP_UINT16_GE((uint16_t)a, (uint16_t)b) : SCTP_UINT32_GE(a, b)) /* Mapping array manipulation routines */ #define SCTP_IS_TSN_PRESENT(arry, gap) ((arry[(gap >> 3)] >> (gap & 0x07)) & 0x01) @@ -937,7 +947,7 @@ extern void getwintimeofday(struct timeval *tv); * element. Each entry will take 2 4 byte ints (and of course the overhead * of the next pointer as well). Using 15 as an example will yield * ((8 * * 15) + 8) or 128 bytes of overhead for each timewait block that gets - * initialized. Increasing it to 31 would yeild 256 bytes per block. + * initialized. Increasing it to 31 would yield 256 bytes per block. */ #define SCTP_NUMBER_IN_VTAG_BLOCK 15 /* @@ -1003,10 +1013,7 @@ extern void getwintimeofday(struct timeval *tv); (((uint8_t *)&(a)->s_addr)[1] == 168))) #define IN4_ISLOOPBACK_ADDRESS(a) \ - ((((uint8_t *)&(a)->s_addr)[0] == 127) && \ - (((uint8_t *)&(a)->s_addr)[1] == 0) && \ - (((uint8_t *)&(a)->s_addr)[2] == 0) && \ - (((uint8_t *)&(a)->s_addr)[3] == 1)) + (((uint8_t *)&(a)->s_addr)[0] == 127) #define IN4_ISLINKLOCAL_ADDRESS(a) \ ((((uint8_t *)&(a)->s_addr)[0] == 169) && \ diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_crc32.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_crc32.c index b994aaace0e..6c9ac280668 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_crc32.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_crc32.c @@ -94,7 +94,7 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_crc32.c 235828 2012-05-23 11:26:28Z tu * File Name = ............................ 8x256_tables.c */ -static uint32_t sctp_crc_tableil8_o32[256] = +static const uint32_t sctp_crc_tableil8_o32[256] = { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, @@ -150,7 +150,7 @@ static uint32_t sctp_crc_tableil8_o32[256] = * File Name = ............................ 8x256_tables.c */ -static uint32_t sctp_crc_tableil8_o40[256] = +static const uint32_t sctp_crc_tableil8_o40[256] = { 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, @@ -206,7 +206,7 @@ static uint32_t sctp_crc_tableil8_o40[256] = * File Name = ............................ 8x256_tables.c */ -static uint32_t sctp_crc_tableil8_o48[256] = +static const uint32_t sctp_crc_tableil8_o48[256] = { 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, @@ -262,7 +262,7 @@ static uint32_t sctp_crc_tableil8_o48[256] = * File Name = ............................ 8x256_tables.c */ -static uint32_t sctp_crc_tableil8_o56[256] = +static const uint32_t sctp_crc_tableil8_o56[256] = { 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, @@ -318,7 +318,7 @@ static uint32_t sctp_crc_tableil8_o56[256] = * File Name = ............................ 8x256_tables.c */ -static uint32_t sctp_crc_tableil8_o64[256] = +static const uint32_t sctp_crc_tableil8_o64[256] = { 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, @@ -374,7 +374,7 @@ static uint32_t sctp_crc_tableil8_o64[256] = * File Name = ............................ 8x256_tables.c */ -uint32_t sctp_crc_tableil8_o72[256] = +static const uint32_t sctp_crc_tableil8_o72[256] = { 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, @@ -430,7 +430,7 @@ uint32_t sctp_crc_tableil8_o72[256] = * File Name = ............................ 8x256_tables.c */ -static uint32_t sctp_crc_tableil8_o80[256] = +static const uint32_t sctp_crc_tableil8_o80[256] = { 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, @@ -486,7 +486,7 @@ static uint32_t sctp_crc_tableil8_o80[256] = * File Name = ............................ 8x256_tables.c */ -static uint32_t sctp_crc_tableil8_o88[256] = +static const uint32_t sctp_crc_tableil8_o88[256] = { 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, @@ -613,7 +613,7 @@ multitable_crc32c(uint32_t crc32c, return (sctp_crc32c_sb8_64_bit(crc32c, buffer, length, to_even_word)); } -static uint32_t sctp_crc_c[256] = { +static const uint32_t sctp_crc_c[256] = { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_header.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_header.h index ad03007aa22..13efa71b91c 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_header.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_header.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_header.h 287717 2015-09-12 17:08:51Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_header.h 302949 2016-07-17 13:14:51Z tuexen $"); #endif #ifndef _NETINET_SCTP_HEADER_H_ @@ -164,6 +164,23 @@ struct sctp_data_chunk { struct sctp_data dp; } SCTP_PACKED; +struct sctp_idata { + uint32_t tsn; + uint16_t stream_id; + uint16_t reserved; /* Where does the SSN go? */ + uint32_t msg_id; + union { + uint32_t protocol_id; + uint32_t fsn; /* Fragment Sequence Number */ + } ppid_fsn; + /* user data follows */ +} SCTP_PACKED; + +struct sctp_idata_chunk { + struct sctp_chunkhdr ch; + struct sctp_idata dp; +} SCTP_PACKED; + /* * Structures for the control chunks */ @@ -396,6 +413,12 @@ struct sctp_strseq { uint16_t sequence; } SCTP_PACKED; +struct sctp_strseq_mid { + uint16_t stream; + uint16_t flags; + uint32_t msg_id; +}; + struct sctp_forward_tsn_msg { struct sctphdr sh; struct sctp_forward_tsn_chunk msg; diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_indata.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_indata.c index 878b58e214e..29b204ee066 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_indata.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_indata.c @@ -32,22 +32,30 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 291700 2015-12-03 15:19:29Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 303927 2016-08-10 17:19:33Z tuexen $"); #endif #include <netinet/sctp_os.h> +#ifdef __FreeBSD__ +#include <sys/proc.h> +#endif #include <netinet/sctp_var.h> #include <netinet/sctp_sysctl.h> -#include <netinet/sctp_pcb.h> #include <netinet/sctp_header.h> +#include <netinet/sctp_pcb.h> #include <netinet/sctputil.h> #include <netinet/sctp_output.h> -#include <netinet/sctp_input.h> -#include <netinet/sctp_indata.h> #include <netinet/sctp_uio.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> +#ifdef __FreeBSD__ +#include <netinet/sctp_lock_bsd.h> +#endif /* * NOTES: On the outbound side of things I need to check the sack timer to * see if I should generate a sack into the chunk queue (if I have data to @@ -57,6 +65,13 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 291700 2015-12-03 15:19:29Z t * This will cause sctp_service_queues() to get called on the top entry in * the list. */ +static void +sctp_add_chk_to_control(struct sctp_queued_to_read *control, + struct sctp_stream_in *strm, + struct sctp_tcb *stcb, + struct sctp_association *asoc, + struct sctp_tmit_chunk *chk, int lock_held); + void sctp_set_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) @@ -76,8 +91,9 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) * sctp_soreceive then we will fix this so that ONLY this * associations data is taken into account. */ - if (stcb->sctp_socket == NULL) + if (stcb->sctp_socket == NULL) { return (calc); + } if (stcb->asoc.sb_cc == 0 && asoc->size_on_reasm_queue == 0 && @@ -88,7 +104,6 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) } /* get actual space */ calc = (uint32_t) sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv); - /* * take out what has NOT been put on socket queue and we yet hold * for putting up. @@ -97,7 +112,6 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc) asoc->cnt_on_reasm_queue * MSIZE)); calc = sctp_sbspace_sub(calc, (uint32_t)(asoc->size_on_all_streams + asoc->cnt_on_all_streams * MSIZE)); - if (calc == 0) { /* out of space */ return (calc); @@ -124,7 +138,7 @@ sctp_build_readq_entry(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t tsn, uint32_t ppid, uint32_t context, uint16_t stream_no, - uint16_t stream_seq, uint8_t flags, + uint32_t stream_seq, uint8_t flags, struct mbuf *dm) { struct sctp_queued_to_read *read_queue_e = NULL; @@ -133,73 +147,26 @@ sctp_build_readq_entry(struct sctp_tcb *stcb, if (read_queue_e == NULL) { goto failed_build; } + memset(read_queue_e, 0, sizeof(struct sctp_queued_to_read)); read_queue_e->sinfo_stream = stream_no; read_queue_e->sinfo_ssn = stream_seq; read_queue_e->sinfo_flags = (flags << 8); read_queue_e->sinfo_ppid = ppid; read_queue_e->sinfo_context = context; - read_queue_e->sinfo_timetolive = 0; read_queue_e->sinfo_tsn = tsn; read_queue_e->sinfo_cumtsn = tsn; read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb); + read_queue_e->top_fsn = read_queue_e->fsn_included = 0xffffffff; + TAILQ_INIT(&read_queue_e->reasm); read_queue_e->whoFrom = net; - read_queue_e->length = 0; atomic_add_int(&net->ref_count, 1); read_queue_e->data = dm; - read_queue_e->spec_flags = 0; - read_queue_e->tail_mbuf = NULL; - read_queue_e->aux_data = NULL; read_queue_e->stcb = stcb; read_queue_e->port_from = stcb->rport; - read_queue_e->do_not_ref_stcb = 0; - read_queue_e->end_added = 0; - read_queue_e->some_taken = 0; - read_queue_e->pdapi_aborted = 0; failed_build: return (read_queue_e); } - -/* - * Build out our readq entry based on the incoming packet. - */ -static struct sctp_queued_to_read * -sctp_build_readq_entry_chk(struct sctp_tcb *stcb, - struct sctp_tmit_chunk *chk) -{ - struct sctp_queued_to_read *read_queue_e = NULL; - - sctp_alloc_a_readq(stcb, read_queue_e); - if (read_queue_e == NULL) { - goto failed_build; - } - read_queue_e->sinfo_stream = chk->rec.data.stream_number; - read_queue_e->sinfo_ssn = chk->rec.data.stream_seq; - read_queue_e->sinfo_flags = (chk->rec.data.rcv_flags << 8); - read_queue_e->sinfo_ppid = chk->rec.data.payloadtype; - read_queue_e->sinfo_context = stcb->asoc.context; - read_queue_e->sinfo_timetolive = 0; - read_queue_e->sinfo_tsn = chk->rec.data.TSN_seq; - read_queue_e->sinfo_cumtsn = chk->rec.data.TSN_seq; - read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb); - read_queue_e->whoFrom = chk->whoTo; - read_queue_e->aux_data = NULL; - read_queue_e->length = 0; - atomic_add_int(&chk->whoTo->ref_count, 1); - read_queue_e->data = chk->data; - read_queue_e->tail_mbuf = NULL; - read_queue_e->stcb = stcb; - read_queue_e->port_from = stcb->rport; - read_queue_e->spec_flags = 0; - read_queue_e->do_not_ref_stcb = 0; - read_queue_e->end_added = 0; - read_queue_e->some_taken = 0; - read_queue_e->pdapi_aborted = 0; -failed_build: - return (read_queue_e); -} - - struct mbuf * sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo) { @@ -336,7 +303,7 @@ sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn) { uint32_t gap, i, cumackp1; int fnd = 0; - + int in_r=0, in_nr=0; if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { return; } @@ -348,15 +315,20 @@ sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn) return; } SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn); - if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { + in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap); + in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap); + if ((in_r == 0) && (in_nr == 0)) { +#ifdef INVARIANTS + panic("Things are really messed up now"); +#else SCTP_PRINTF("gap:%x tsn:%x\n", gap, tsn); sctp_print_mapping_array(asoc); -#ifdef INVARIANTS - panic("Things are really messed up now!!"); #endif } - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); + if (in_nr == 0) + SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); + if (in_r) + SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { asoc->highest_tsn_inside_nr_map = tsn; } @@ -376,197 +348,158 @@ sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn) } } - -/* - * We are delivering currently from the reassembly queue. We must continue to - * deliver until we either: 1) run out of space. 2) run out of sequential - * TSN's 3) hit the SCTP_DATA_LAST_FRAG flag. - */ -static void -sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc) +static int +sctp_place_control_in_stream(struct sctp_stream_in *strm, + struct sctp_association *asoc, + struct sctp_queued_to_read *control) { - struct sctp_tmit_chunk *chk, *nchk; - uint16_t nxt_todel; - uint16_t stream_no; - int end = 0; - int cntDel; - struct sctp_queued_to_read *control, *ctl, *nctl; - - if (stcb == NULL) - return; - - cntDel = stream_no = 0; - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || - (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { - /* socket above is long gone or going.. */ - abandon: - asoc->fragmented_delivery_inprogress = 0; - TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - asoc->size_on_reasm_queue -= chk->send_size; - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - /* - * Lose the data pointer, since its in the socket - * buffer - */ - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; + struct sctp_queued_to_read *at; + struct sctp_readhead *q; + uint8_t bits, unordered; + + bits = (control->sinfo_flags >> 8); + unordered = bits & SCTP_DATA_UNORDERED; + if (unordered) { + q = &strm->uno_inqueue; + if (asoc->idata_supported == 0) { + if (!TAILQ_EMPTY(q)) { + /* Only one stream can be here in old style -- abort */ + return (-1); } - /* Now free the address and data */ - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - /*sa_ignore FREED_MEMORY*/ + TAILQ_INSERT_TAIL(q, control, next_instrm); + control->on_strm_q = SCTP_ON_UNORDERED; + return (0); } - return; + } else { + q = &strm->inqueue; } - SCTP_TCB_LOCK_ASSERT(stcb); - TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { - if (chk->rec.data.TSN_seq != (asoc->tsn_last_delivered + 1)) { - /* Can't deliver more :< */ - return; - } - stream_no = chk->rec.data.stream_number; - nxt_todel = asoc->strmin[stream_no].last_sequence_delivered + 1; - if (nxt_todel != chk->rec.data.stream_seq && - (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { - /* - * Not the next sequence to deliver in its stream OR - * unordered - */ - return; - } - if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - - control = sctp_build_readq_entry_chk(stcb, chk); - if (control == NULL) { - /* out of memory? */ - return; - } - /* save it off for our future deliveries */ - stcb->asoc.control_pdapi = control; - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) - end = 1; - else - end = 0; - sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq); - sctp_add_to_readq(stcb->sctp_ep, - stcb, control, &stcb->sctp_socket->so_rcv, end, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - cntDel++; + if ((bits & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { + control->end_added = control->last_frag_seen = control->first_frag_seen = 1; + } + if (TAILQ_EMPTY(q)) { + /* Empty queue */ + TAILQ_INSERT_HEAD(q, control, next_instrm); + if (unordered) { + control->on_strm_q = SCTP_ON_UNORDERED; } else { - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) - end = 1; - else - end = 0; - sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq); - if (sctp_append_to_readq(stcb->sctp_ep, stcb, - stcb->asoc.control_pdapi, - chk->data, end, chk->rec.data.TSN_seq, - &stcb->sctp_socket->so_rcv)) { + control->on_strm_q = SCTP_ON_ORDERED; + } + return (0); + } else { + TAILQ_FOREACH(at, q, next_instrm) { + if (SCTP_TSN_GT(at->msg_id, control->msg_id)) { /* - * something is very wrong, either - * control_pdapi is NULL, or the tail_mbuf - * is corrupt, or there is a EOM already on - * the mbuf chain. + * one in queue is bigger than the + * new one, insert before this one */ - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - goto abandon; + TAILQ_INSERT_BEFORE(at, control, next_instrm); + if (unordered) { + control->on_strm_q = SCTP_ON_UNORDERED; } else { -#ifdef INVARIANTS - if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) { - panic("This should not happen control_pdapi NULL?"); + control->on_strm_q = SCTP_ON_ORDERED ; + } + break; + } else if (at->msg_id == control->msg_id) { + /* + * Gak, He sent me a duplicate msg + * id number?? return -1 to abort. + */ + return (-1); + } else { + if (TAILQ_NEXT(at, next_instrm) == NULL) { + /* + * We are at the end, insert + * it after this one + */ + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { + sctp_log_strm_del(control, at, + SCTP_STR_LOG_FROM_INSERT_TL); } - /* if we did not panic, it was a EOM */ - panic("Bad chunking ??"); -#else - if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) { - SCTP_PRINTF("This should not happen control_pdapi NULL?\n"); + TAILQ_INSERT_AFTER(q, + at, control, next_instrm); + if (unordered) { + control->on_strm_q = SCTP_ON_UNORDERED ; + } else { + control->on_strm_q = SCTP_ON_ORDERED ; } - SCTP_PRINTF("Bad chunking ??\n"); - SCTP_PRINTF("Dumping re-assembly queue this will probably hose the association\n"); - -#endif - goto abandon; + break; } } - cntDel++; } - /* pull it we did it */ - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - asoc->fragmented_delivery_inprogress = 0; - if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { - asoc->strmin[stream_no].last_sequence_delivered++; - } - if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) { - SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); - } - } else if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - /* - * turn the flag back on since we just delivered - * yet another one. - */ - asoc->fragmented_delivery_inprogress = 1; - } - asoc->tsn_of_pdapi_last_delivered = chk->rec.data.TSN_seq; - asoc->last_flags_delivered = chk->rec.data.rcv_flags; - asoc->last_strm_seq_delivered = chk->rec.data.stream_seq; - asoc->last_strm_no_delivered = chk->rec.data.stream_number; + } + return (0); +} - asoc->tsn_last_delivered = chk->rec.data.TSN_seq; - asoc->size_on_reasm_queue -= chk->send_size; - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - /* free up the chk */ +static void +sctp_abort_in_reasm(struct sctp_tcb *stcb, + struct sctp_queued_to_read *control, + struct sctp_tmit_chunk *chk, + int *abort_flag, int opspot) +{ + char msg[SCTP_DIAG_INFO_LEN]; + struct mbuf *oper; + + if (stcb->asoc.idata_supported) { + snprintf(msg, sizeof(msg), + "Reass %x,CF:%x,TSN=%8.8x,SID=%4.4x,FSN=%8.8x,MID:%8.8x", + opspot, + control->fsn_included, + chk->rec.data.TSN_seq, + chk->rec.data.stream_number, + chk->rec.data.fsn_num, chk->rec.data.stream_seq); + } else { + snprintf(msg, sizeof(msg), + "Reass %x,CI:%x,TSN=%8.8x,SID=%4.4x,FSN=%4.4x,SSN:%4.4x", + opspot, + control->fsn_included, + chk->rec.data.TSN_seq, + chk->rec.data.stream_number, + chk->rec.data.fsn_num, + (uint16_t)chk->rec.data.stream_seq); + } + oper = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + sctp_m_freem(chk->data); + chk->data = NULL; + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1; + sctp_abort_an_association(stcb->sctp_ep, stcb, oper, SCTP_SO_NOT_LOCKED); + *abort_flag = 1; +} + +static void +sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control) +{ + /* + * The control could not be placed and must be cleaned. + */ + struct sctp_tmit_chunk *chk, *nchk; + TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { + TAILQ_REMOVE(&control->reasm, chk, sctp_next); + if (chk->data) + sctp_m_freem(chk->data); chk->data = NULL; sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - - if (asoc->fragmented_delivery_inprogress == 0) { - /* - * Now lets see if we can deliver the next one on - * the stream - */ - struct sctp_stream_in *strm; - - strm = &asoc->strmin[stream_no]; - nxt_todel = strm->last_sequence_delivered + 1; - TAILQ_FOREACH_SAFE(ctl, &strm->inqueue, next, nctl) { - /* Deliver more if we can. */ - if (nxt_todel == ctl->sinfo_ssn) { - TAILQ_REMOVE(&strm->inqueue, ctl, next); - asoc->size_on_all_streams -= ctl->length; - sctp_ucount_decr(asoc->cnt_on_all_streams); - strm->last_sequence_delivered++; - sctp_mark_non_revokable(asoc, ctl->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - ctl, - &stcb->sctp_socket->so_rcv, 1, - SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - } else { - break; - } - nxt_todel = strm->last_sequence_delivered + 1; - } - break; - } } + sctp_free_a_readq(stcb, control); } /* * Queue the chunk either right into the socket buffer if it is the next one * to go OR put it in the correct place in the delivery queue. If we do - * append to the so_buf, keep doing so until we are out of order. One big - * question still remains, what to do when the socket buffer is FULL?? + * append to the so_buf, keep doing so until we are out of order as + * long as the control's entered are non-fragmented. */ static void -sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_queued_to_read *control, int *abort_flag) +sctp_queue_data_to_stream(struct sctp_tcb *stcb, + struct sctp_stream_in *strm, + struct sctp_association *asoc, + struct sctp_queued_to_read *control, int *abort_flag, int *need_reasm) { /* * FIX-ME maybe? What happens when the ssn wraps? If we are getting * all the data in one stream this could happen quite rapidly. One * could use the TSN to keep track of things, but this scheme breaks - * down in the other type of stream useage that could occur. Send a + * down in the other type of stream usage that could occur. Send a * single msg to stream 0, send 4Billion messages to stream 1, now * send a message to stream 0. You have a situation where the TSN * has wrapped but not in the stream. Is this worth worrying about @@ -580,61 +513,57 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, * SSN alone. Maybe a hybred approach is the answer * */ - struct sctp_stream_in *strm; struct sctp_queued_to_read *at; int queue_needed; - uint16_t nxt_todel; + uint32_t nxt_todel; struct mbuf *op_err; char msg[SCTP_DIAG_INFO_LEN]; - queue_needed = 1; - asoc->size_on_all_streams += control->length; - sctp_ucount_incr(asoc->cnt_on_all_streams); - strm = &asoc->strmin[control->sinfo_stream]; - nxt_todel = strm->last_sequence_delivered + 1; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INTO_STRD); } - SCTPDBG(SCTP_DEBUG_INDATA1, - "queue to stream called for sid:%u ssn:%u tsn:%u lastdel:%u nxt:%u\n", - (uint32_t)control->sinfo_stream, (uint32_t)control->sinfo_ssn, - (uint32_t)control->sinfo_tsn, - (uint32_t)strm->last_sequence_delivered, (uint32_t)nxt_todel); - if (SCTP_SSN_GE(strm->last_sequence_delivered, control->sinfo_ssn)) { + if (SCTP_MSGID_GT((!asoc->idata_supported), strm->last_sequence_delivered, control->sinfo_ssn)) { /* The incoming sseq is behind where we last delivered? */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ:%d delivered:%d from peer, Abort association\n", + SCTPDBG(SCTP_DEBUG_INDATA1, "Duplicate S-SEQ: %u delivered: %u from peer, Abort association\n", control->sinfo_ssn, strm->last_sequence_delivered); protocol_error: /* * throw it in the stream so it gets cleaned up in * association destruction */ - TAILQ_INSERT_HEAD(&strm->inqueue, control, next); + TAILQ_INSERT_HEAD(&strm->inqueue, control, next_instrm); snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", strm->last_sequence_delivered, control->sinfo_tsn, control->sinfo_stream, control->sinfo_ssn); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; } -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - struct socket *so; - - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - SCTP_SOCKET_UNLOCK(so, 1); - return; + if ((SCTP_TSN_GE(asoc->cumulative_tsn, control->sinfo_tsn)) && (asoc->idata_supported == 0)) { + goto protocol_error; } -#endif + queue_needed = 1; + asoc->size_on_all_streams += control->length; + sctp_ucount_incr(asoc->cnt_on_all_streams); + nxt_todel = strm->last_sequence_delivered + 1; if (nxt_todel == control->sinfo_ssn) { +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + struct socket *so; + + so = SCTP_INP_SO(stcb->sctp_ep); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_SOCKET_LOCK(so, 1); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { + SCTP_SOCKET_UNLOCK(so, 1); + return; + } +#endif /* can be delivered right away? */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_IMMED_DEL); @@ -644,19 +573,27 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, asoc->size_on_all_streams -= control->length; sctp_ucount_decr(asoc->cnt_on_all_streams); strm->last_sequence_delivered++; - sctp_mark_non_revokable(asoc, control->sinfo_tsn); sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED); - TAILQ_FOREACH_SAFE(control, &strm->inqueue, next, at) { + TAILQ_FOREACH_SAFE(control, &strm->inqueue, next_instrm, at) { /* all delivered */ nxt_todel = strm->last_sequence_delivered + 1; - if (nxt_todel == control->sinfo_ssn) { - TAILQ_REMOVE(&strm->inqueue, control, next); + if ((nxt_todel == control->sinfo_ssn) && + (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) { asoc->size_on_all_streams -= control->length; sctp_ucount_decr(asoc->cnt_on_all_streams); + if (control->on_strm_q == SCTP_ON_ORDERED) { + TAILQ_REMOVE(&strm->inqueue, control, next_instrm); +#ifdef INVARIANTS + } else { + panic("Huh control: %p is on_strm_q: %d", + control, control->on_strm_q); +#endif + } + control->on_strm_q = 0; strm->last_sequence_delivered++; /* * We ignore the return of deliver_data here @@ -675,189 +612,668 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_LOCKED); continue; + } else if (nxt_todel == control->sinfo_ssn) { + *need_reasm = 1; } break; } +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + SCTP_SOCKET_UNLOCK(so, 1); +#endif } if (queue_needed) { /* * Ok, we did not deliver this guy, find the correct place * to put it on the queue. */ - if (SCTP_TSN_GE(asoc->cumulative_tsn, control->sinfo_tsn)) { -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - SCTP_SOCKET_UNLOCK(so, 1); + if (sctp_place_control_in_stream(strm, asoc, control)) { + snprintf(msg, sizeof(msg), + "Queue to str msg_id: %u duplicate", + control->msg_id); + sctp_clean_up_control(stcb, control); + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3; + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + *abort_flag = 1; + } + } +} + + +static void +sctp_setup_tail_pointer(struct sctp_queued_to_read *control) +{ + struct mbuf *m, *prev = NULL; + struct sctp_tcb *stcb; + + stcb = control->stcb; + control->held_length = 0; + control->length = 0; + m = control->data; + while (m) { + if (SCTP_BUF_LEN(m) == 0) { + /* Skip mbufs with NO length */ + if (prev == NULL) { + /* First one */ + control->data = sctp_m_free(m); + m = control->data; + } else { + SCTP_BUF_NEXT(prev) = sctp_m_free(m); + m = SCTP_BUF_NEXT(prev); + } + if (m == NULL) { + control->tail_mbuf = prev; + } + continue; + } + prev = m; + atomic_add_int(&control->length, SCTP_BUF_LEN(m)); + if (control->on_read_q) { + /* + * On read queue so we must increment the + * SB stuff, we assume caller has done any locks of SB. + */ + sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m); + } + m = SCTP_BUF_NEXT(m); + } + if (prev) { + control->tail_mbuf = prev; + } +} + +static void +sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m) +{ + struct mbuf *prev=NULL; + struct sctp_tcb *stcb; + + stcb = control->stcb; + if (stcb == NULL) { +#ifdef INVARIANTS + panic("Control broken"); +#else + return; #endif - goto protocol_error; + } + if (control->tail_mbuf == NULL) { + /* TSNH */ + control->data = m; + sctp_setup_tail_pointer(control); + return; + } + control->tail_mbuf->m_next = m; + while (m) { + if (SCTP_BUF_LEN(m) == 0) { + /* Skip mbufs with NO length */ + if (prev == NULL) { + /* First one */ + control->tail_mbuf->m_next = sctp_m_free(m); + m = control->tail_mbuf->m_next; + } else { + SCTP_BUF_NEXT(prev) = sctp_m_free(m); + m = SCTP_BUF_NEXT(prev); + } + if (m == NULL) { + control->tail_mbuf = prev; + } + continue; } - if (TAILQ_EMPTY(&strm->inqueue)) { - /* Empty queue */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, NULL, SCTP_STR_LOG_FROM_INSERT_HD); + prev = m; + if (control->on_read_q) { + /* + * On read queue so we must increment the + * SB stuff, we assume caller has done any locks of SB. + */ + sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m); + } + atomic_add_int(&control->length, SCTP_BUF_LEN(m)); + m = SCTP_BUF_NEXT(m); + } + if (prev) { + control->tail_mbuf = prev; + } +} + +static void +sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queued_to_read *control) +{ + memset(nc, 0, sizeof(struct sctp_queued_to_read)); + nc->sinfo_stream = control->sinfo_stream; + nc->sinfo_ssn = control->sinfo_ssn; + TAILQ_INIT(&nc->reasm); + nc->top_fsn = control->top_fsn; + nc->msg_id = control->msg_id; + nc->sinfo_flags = control->sinfo_flags; + nc->sinfo_ppid = control->sinfo_ppid; + nc->sinfo_context = control->sinfo_context; + nc->fsn_included = 0xffffffff; + nc->sinfo_tsn = control->sinfo_tsn; + nc->sinfo_cumtsn = control->sinfo_cumtsn; + nc->sinfo_assoc_id = control->sinfo_assoc_id; + nc->whoFrom = control->whoFrom; + atomic_add_int(&nc->whoFrom->ref_count, 1); + nc->stcb = control->stcb; + nc->port_from = control->port_from; +} + +static void +sctp_reset_a_control(struct sctp_queued_to_read *control, + struct sctp_inpcb *inp, uint32_t tsn) +{ + control->fsn_included = tsn; + if (control->on_read_q) { + /* + * We have to purge it from there, + * hopefully this will work :-) + */ + TAILQ_REMOVE(&inp->read_queue, control, next); + control->on_read_q = 0; + } +} + +static int +sctp_handle_old_unordered_data(struct sctp_tcb *stcb, + struct sctp_association *asoc, + struct sctp_stream_in *strm, + struct sctp_queued_to_read *control, + uint32_t pd_point, + int inp_read_lock_held) +{ + /* Special handling for the old un-ordered data chunk. + * All the chunks/TSN's go to msg_id 0. So + * we have to do the old style watching to see + * if we have it all. If you return one, no other + * control entries on the un-ordered queue will + * be looked at. In theory there should be no others + * entries in reality, unless the guy is sending both + * unordered NDATA and unordered DATA... + */ + struct sctp_tmit_chunk *chk, *lchk, *tchk; + uint32_t fsn; + struct sctp_queued_to_read *nc; + int cnt_added; + + if (control->first_frag_seen == 0) { + /* Nothing we can do, we have not seen the first piece yet */ + return (1); + } + /* Collapse any we can */ + cnt_added = 0; +restart: + fsn = control->fsn_included + 1; + /* Now what can we add? */ + TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) { + if (chk->rec.data.fsn_num == fsn) { + /* Ok lets add it */ + sctp_alloc_a_readq(stcb, nc); + if (nc == NULL) { + break; } - TAILQ_INSERT_HEAD(&strm->inqueue, control, next); - } else { - TAILQ_FOREACH(at, &strm->inqueue, next) { - if (SCTP_SSN_GT(at->sinfo_ssn, control->sinfo_ssn)) { - /* - * one in queue is bigger than the - * new one, insert before this one + memset(nc, 0, sizeof(struct sctp_queued_to_read)); + TAILQ_REMOVE(&control->reasm, chk, sctp_next); + sctp_add_chk_to_control(control, strm, stcb, asoc, chk, SCTP_READ_LOCK_NOT_HELD); + fsn++; + cnt_added++; + chk = NULL; + if (control->end_added) { + /* We are done */ + if (!TAILQ_EMPTY(&control->reasm)) { + /* + * Ok we have to move anything left on + * the control queue to a new control. */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, at, - SCTP_STR_LOG_FROM_INSERT_MD); + sctp_build_readq_entry_from_ctl(nc, control); + tchk = TAILQ_FIRST(&control->reasm); + if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { + TAILQ_REMOVE(&control->reasm, tchk, sctp_next); + nc->first_frag_seen = 1; + nc->fsn_included = tchk->rec.data.fsn_num; + nc->data = tchk->data; + nc->sinfo_ppid = tchk->rec.data.payloadtype; + nc->sinfo_tsn = tchk->rec.data.TSN_seq; + sctp_mark_non_revokable(asoc, tchk->rec.data.TSN_seq); + tchk->data = NULL; + sctp_free_a_chunk(stcb, tchk, SCTP_SO_NOT_LOCKED); + sctp_setup_tail_pointer(nc); + tchk = TAILQ_FIRST(&control->reasm); } - TAILQ_INSERT_BEFORE(at, control, next); - break; - } else if (at->sinfo_ssn == control->sinfo_ssn) { - /* - * Gak, He sent me a duplicate str - * seq number - */ - /* - * foo bar, I guess I will just free - * this new guy, should we abort - * too? FIX ME MAYBE? Or it COULD be - * that the SSN's have wrapped. - * Maybe I should compare to TSN - * somehow... sigh for now just blow - * away the chunk! - */ - - if (control->data) - sctp_m_freem(control->data); - control->data = NULL; - asoc->size_on_all_streams -= control->length; - sctp_ucount_decr(asoc->cnt_on_all_streams); - if (control->whoFrom) { - sctp_free_remote_addr(control->whoFrom); - control->whoFrom = NULL; + /* Spin the rest onto the queue */ + while (tchk) { + TAILQ_REMOVE(&control->reasm, tchk, sctp_next); + TAILQ_INSERT_TAIL(&nc->reasm, tchk, sctp_next); + tchk = TAILQ_FIRST(&control->reasm); } - sctp_free_a_readq(stcb, control); -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - SCTP_SOCKET_UNLOCK(so, 1); + /* Now lets add it to the queue after removing control */ + TAILQ_INSERT_TAIL(&strm->uno_inqueue, nc, next_instrm); + nc->on_strm_q = SCTP_ON_UNORDERED; + if (control->on_strm_q) { + TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); + control->on_strm_q = 0; + } + } + if (control->pdapi_started) { + strm->pd_api_started = 0; + control->pdapi_started = 0; + } + if (control->on_strm_q) { + TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); + control->on_strm_q = 0; + SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); + } + if (control->on_read_q == 0) { + sctp_add_to_readq(stcb->sctp_ep, stcb, control, + &stcb->sctp_socket->so_rcv, control->end_added, + inp_read_lock_held, SCTP_SO_NOT_LOCKED); +#if defined(__Userspace__) + } else { + sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, inp_read_lock_held); #endif - return; + } + sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); + if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) { + /* Switch to the new guy and continue */ + control = nc; + goto restart; } else { - if (TAILQ_NEXT(at, next) == NULL) { - /* - * We are at the end, insert - * it after this one - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del(control, at, - SCTP_STR_LOG_FROM_INSERT_TL); - } - TAILQ_INSERT_AFTER(&strm->inqueue, - at, control, next); - break; + if (nc->on_strm_q == 0) { + sctp_free_a_readq(stcb, nc); } } + return (1); + } else { + sctp_free_a_readq(stcb, nc); } + } else { + /* Can't add more */ + break; } } -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - SCTP_SOCKET_UNLOCK(so, 1); -#endif + if ((control->length > pd_point) && (strm->pd_api_started == 0)) { + strm->pd_api_started = 1; + control->pdapi_started = 1; + sctp_add_to_readq(stcb->sctp_ep, stcb, control, + &stcb->sctp_socket->so_rcv, control->end_added, + inp_read_lock_held, SCTP_SO_NOT_LOCKED); + sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); + return (0); + } else { + return (1); + } +} + +static void +sctp_inject_old_unordered_data(struct sctp_tcb *stcb, + struct sctp_association *asoc, + struct sctp_queued_to_read *control, + struct sctp_tmit_chunk *chk, + int *abort_flag) +{ + struct sctp_tmit_chunk *at; + int inserted; + /* + * Here we need to place the chunk into the control structure + * sorted in the correct order. + */ + if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { + /* Its the very first one. */ + SCTPDBG(SCTP_DEBUG_XXX, + "chunk is a first fsn: %u becomes fsn_included\n", + chk->rec.data.fsn_num); + if (control->first_frag_seen) { + /* + * In old un-ordered we can reassembly on + * one control multiple messages. As long + * as the next FIRST is greater then the old + * first (TSN i.e. FSN wise) + */ + struct mbuf *tdata; + uint32_t tmp; + + if (SCTP_TSN_GT(chk->rec.data.fsn_num, control->fsn_included)) { + /* Easy way the start of a new guy beyond the lowest */ + goto place_chunk; + } + if ((chk->rec.data.fsn_num == control->fsn_included) || + (control->pdapi_started)) { + /* + * Ok this should not happen, if it does + * we started the pd-api on the higher TSN (since + * the equals part is a TSN failure it must be that). + * + * We are completly hosed in that case since I have + * no way to recover. This really will only happen + * if we can get more TSN's higher before the pd-api-point. + */ + sctp_abort_in_reasm(stcb, control, chk, + abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_4); + + return; + } + /* + * Ok we have two firsts and the one we just got + * is smaller than the one we previously placed.. yuck! + * We must swap them out. + */ + /* swap the mbufs */ + tdata = control->data; + control->data = chk->data; + chk->data = tdata; + /* Save the lengths */ + chk->send_size = control->length; + /* Recompute length of control and tail pointer */ + sctp_setup_tail_pointer(control); + /* Fix the FSN included */ + tmp = control->fsn_included; + control->fsn_included = chk->rec.data.fsn_num; + chk->rec.data.fsn_num = tmp; + /* Fix the TSN included */ + tmp = control->sinfo_tsn; + control->sinfo_tsn = chk->rec.data.TSN_seq; + chk->rec.data.TSN_seq = tmp; + /* Fix the PPID included */ + tmp = control->sinfo_ppid; + control->sinfo_ppid = chk->rec.data.payloadtype; + chk->rec.data.payloadtype = tmp; + /* Fix tail pointer */ + goto place_chunk; + } + control->first_frag_seen = 1; + control->top_fsn = control->fsn_included = chk->rec.data.fsn_num; + control->sinfo_tsn = chk->rec.data.TSN_seq; + control->sinfo_ppid = chk->rec.data.payloadtype; + control->data = chk->data; + sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq); + chk->data = NULL; + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); + sctp_setup_tail_pointer(control); + return; + } +place_chunk: + inserted = 0; + TAILQ_FOREACH(at, &control->reasm, sctp_next) { + if (SCTP_TSN_GT(at->rec.data.fsn_num, chk->rec.data.fsn_num)) { + /* + * This one in queue is bigger than the new one, insert + * the new one before at. + */ + asoc->size_on_reasm_queue += chk->send_size; + sctp_ucount_incr(asoc->cnt_on_reasm_queue); + inserted = 1; + TAILQ_INSERT_BEFORE(at, chk, sctp_next); + break; + } else if (at->rec.data.fsn_num == chk->rec.data.fsn_num) { + /* + * They sent a duplicate fsn number. This + * really should not happen since the FSN is + * a TSN and it should have been dropped earlier. + */ + sctp_abort_in_reasm(stcb, control, chk, + abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_5); + return; + } + + } + if (inserted == 0) { + /* Its at the end */ + asoc->size_on_reasm_queue += chk->send_size; + sctp_ucount_incr(asoc->cnt_on_reasm_queue); + control->top_fsn = chk->rec.data.fsn_num; + TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next); + } } -/* - * Returns two things: You get the total size of the deliverable parts of the - * first fragmented message on the reassembly queue. And you get a 1 back if - * all of the message is ready or a 0 back if the message is still incomplete - */ static int -sctp_is_all_msg_on_reasm(struct sctp_association *asoc, uint32_t *t_size) +sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc, + struct sctp_stream_in *strm, int inp_read_lock_held) { - struct sctp_tmit_chunk *chk; - uint32_t tsn; + /* + * Given a stream, strm, see if any of + * the SSN's on it that are fragmented + * are ready to deliver. If so go ahead + * and place them on the read queue. In + * so placing if we have hit the end, then + * we need to remove them from the stream's queue. + */ + struct sctp_queued_to_read *control, *nctl=NULL; + uint32_t next_to_del; + uint32_t pd_point; + int ret = 0; + + if (stcb->sctp_socket) { + pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT, + stcb->sctp_ep->partial_delivery_point); + } else { + pd_point = stcb->sctp_ep->partial_delivery_point; + } + control = TAILQ_FIRST(&strm->uno_inqueue); - *t_size = 0; - chk = TAILQ_FIRST(&asoc->reasmqueue); - if (chk == NULL) { - /* nothing on the queue */ + if ((control) && + (asoc->idata_supported == 0)) { + /* Special handling needed for "old" data format */ + if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) { + goto done_un; + } + } + if (strm->pd_api_started) { + /* Can't add more */ return (0); } - if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) { - /* Not a first on the queue */ + while (control) { + SCTPDBG(SCTP_DEBUG_XXX, "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u -uo\n", + control, control->end_added, control->sinfo_ssn, control->top_fsn, control->fsn_included); + nctl = TAILQ_NEXT(control, next_instrm); + if (control->end_added) { + /* We just put the last bit on */ + if (control->on_strm_q) { +#ifdef INVARIANTS + if (control->on_strm_q != SCTP_ON_UNORDERED ) { + panic("Huh control: %p on_q: %d -- not unordered?", + control, control->on_strm_q); + } +#endif + SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); + TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); + control->on_strm_q = 0; + } + if (control->on_read_q == 0) { + sctp_add_to_readq(stcb->sctp_ep, stcb, + control, + &stcb->sctp_socket->so_rcv, control->end_added, + inp_read_lock_held, SCTP_SO_NOT_LOCKED); + } + } else { + /* Can we do a PD-API for this un-ordered guy? */ + if ((control->length >= pd_point) && (strm->pd_api_started == 0)) { + strm->pd_api_started = 1; + control->pdapi_started = 1; + sctp_add_to_readq(stcb->sctp_ep, stcb, + control, + &stcb->sctp_socket->so_rcv, control->end_added, + inp_read_lock_held, SCTP_SO_NOT_LOCKED); + + break; + } + } + control = nctl; + } +done_un: + control = TAILQ_FIRST(&strm->inqueue); + if (strm->pd_api_started) { + /* Can't add more */ return (0); } - tsn = chk->rec.data.TSN_seq; - TAILQ_FOREACH(chk, &asoc->reasmqueue, sctp_next) { - if (tsn != chk->rec.data.TSN_seq) { - return (0); + if (control == NULL) { + return (ret); + } + if (strm->last_sequence_delivered == control->sinfo_ssn) { + /* Ok the guy at the top was being partially delivered + * completed, so we remove it. Note + * the pd_api flag was taken off when the + * chunk was merged on in sctp_queue_data_for_reasm below. + */ + nctl = TAILQ_NEXT(control, next_instrm); + SCTPDBG(SCTP_DEBUG_XXX, + "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (lastdel: %u)- o\n", + control, control->end_added, control->sinfo_ssn, + control->top_fsn, control->fsn_included, + strm->last_sequence_delivered); + if (control->end_added) { + if (control->on_strm_q) { +#ifdef INVARIANTS + if (control->on_strm_q != SCTP_ON_ORDERED ) { + panic("Huh control: %p on_q: %d -- not ordered?", + control, control->on_strm_q); + } +#endif + SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); + TAILQ_REMOVE(&strm->inqueue, control, next_instrm); + control->on_strm_q = 0; + } + if (strm->pd_api_started && control->pdapi_started) { + control->pdapi_started = 0; + strm->pd_api_started = 0; + } + if (control->on_read_q == 0) { + sctp_add_to_readq(stcb->sctp_ep, stcb, + control, + &stcb->sctp_socket->so_rcv, control->end_added, + inp_read_lock_held, SCTP_SO_NOT_LOCKED); + } + control = nctl; } - *t_size += chk->send_size; - if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { - return (1); + } + if (strm->pd_api_started) { + /* Can't add more must have gotten an un-ordered above being partially delivered. */ + return (0); + } +deliver_more: + next_to_del = strm->last_sequence_delivered + 1; + if (control) { + SCTPDBG(SCTP_DEBUG_XXX, + "Looking at control: %p e(%d) ssn: %u top_fsn: %u inc_fsn: %u (nxtdel: %u)- o\n", + control, control->end_added, control->sinfo_ssn, control->top_fsn, control->fsn_included, + next_to_del); + nctl = TAILQ_NEXT(control, next_instrm); + if ((control->sinfo_ssn == next_to_del) && + (control->first_frag_seen)) { + int done; + + /* Ok we can deliver it onto the stream. */ + if (control->end_added) { + /* We are done with it afterwards */ + if (control->on_strm_q) { +#ifdef INVARIANTS + if (control->on_strm_q != SCTP_ON_ORDERED ) { + panic("Huh control: %p on_q: %d -- not ordered?", + control, control->on_strm_q); + } +#endif + SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); + TAILQ_REMOVE(&strm->inqueue, control, next_instrm); + control->on_strm_q = 0; + } + ret++; + } + if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { + /* A singleton now slipping through - mark it non-revokable too */ + sctp_mark_non_revokable(asoc, control->sinfo_tsn); + } else if (control->end_added == 0) { + /* Check if we can defer adding until its all there */ + if ((control->length < pd_point) || (strm->pd_api_started)) { + /* Don't need it or cannot add more (one being delivered that way) */ + goto out; + } + } + done = (control->end_added) && (control->last_frag_seen); + if (control->on_read_q == 0) { + sctp_add_to_readq(stcb->sctp_ep, stcb, + control, + &stcb->sctp_socket->so_rcv, control->end_added, + inp_read_lock_held, SCTP_SO_NOT_LOCKED); + } + strm->last_sequence_delivered = next_to_del; + if (done) { + control = nctl; + goto deliver_more; + } else { + /* We are now doing PD API */ + strm->pd_api_started = 1; + control->pdapi_started = 1; + } } - tsn++; } - return (0); +out: + return (ret); } -static void -sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc) + +void +sctp_add_chk_to_control(struct sctp_queued_to_read *control, + struct sctp_stream_in *strm, + struct sctp_tcb *stcb, struct sctp_association *asoc, + struct sctp_tmit_chunk *chk, int hold_rlock) { - struct sctp_tmit_chunk *chk; - uint16_t nxt_todel; - uint32_t tsize, pd_point; - - doit_again: - chk = TAILQ_FIRST(&asoc->reasmqueue); - if (chk == NULL) { - /* Huh? */ - asoc->size_on_reasm_queue = 0; - asoc->cnt_on_reasm_queue = 0; - return; + /* + * Given a control and a chunk, merge the + * data from the chk onto the control and free + * up the chunk resources. + */ + int i_locked = 0; + + if (control->on_read_q && (hold_rlock == 0)) { + /* + * Its being pd-api'd so we must + * do some locks. + */ + SCTP_INP_READ_LOCK(stcb->sctp_ep); + i_locked = 1; } - if (asoc->fragmented_delivery_inprogress == 0) { - nxt_todel = - asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered + 1; - if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) && - (nxt_todel == chk->rec.data.stream_seq || - (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED))) { - /* - * Yep the first one is here and its ok to deliver - * but should we? - */ - if (stcb->sctp_socket) { - pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT, - stcb->sctp_ep->partial_delivery_point); - } else { - pd_point = stcb->sctp_ep->partial_delivery_point; + if (control->data == NULL) { + control->data = chk->data; + sctp_setup_tail_pointer(control); + } else { + sctp_add_to_tail_pointer(control, chk->data); + } + control->fsn_included = chk->rec.data.fsn_num; + asoc->size_on_reasm_queue -= chk->send_size; + sctp_ucount_decr(asoc->cnt_on_reasm_queue); + sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq); + chk->data = NULL; + if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { + control->first_frag_seen = 1; + } + if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { + /* Its complete */ + if ((control->on_strm_q) && (control->on_read_q)) { + if (control->pdapi_started) { + control->pdapi_started = 0; + strm->pd_api_started = 0; } - if (sctp_is_all_msg_on_reasm(asoc, &tsize) || (tsize >= pd_point)) { - /* - * Yes, we setup to start reception, by - * backing down the TSN just in case we - * can't deliver. If we - */ - asoc->fragmented_delivery_inprogress = 1; - asoc->tsn_last_delivered = - chk->rec.data.TSN_seq - 1; - asoc->str_of_pdapi = - chk->rec.data.stream_number; - asoc->ssn_of_pdapi = chk->rec.data.stream_seq; - asoc->pdapi_ppid = chk->rec.data.payloadtype; - asoc->fragment_flags = chk->rec.data.rcv_flags; - sctp_service_reassembly(stcb, asoc); + if (control->on_strm_q == SCTP_ON_UNORDERED) { + /* Unordered */ + TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); + control->on_strm_q = 0; + } else if (control->on_strm_q == SCTP_ON_ORDERED) { + /* Ordered */ + TAILQ_REMOVE(&strm->inqueue, control, next_instrm); + control->on_strm_q = 0; +#ifdef INVARIANTS + } else if (control->on_strm_q) { + panic("Unknown state on ctrl: %p on_strm_q: %d", control, + control->on_strm_q); +#endif } } - } else { - /* Service re-assembly will deliver stream data queued - * at the end of fragmented delivery.. but it wont know - * to go back and call itself again... we do that here - * with the got doit_again - */ - sctp_service_reassembly(stcb, asoc); - if (asoc->fragmented_delivery_inprogress == 0) { - /* finished our Fragmented delivery, could be - * more waiting? - */ - goto doit_again; - } + control->end_added = 1; + control->last_frag_seen = 1; + } + if (i_locked) { + SCTP_INP_READ_UNLOCK(stcb->sctp_ep); } + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); } /* @@ -868,462 +1284,352 @@ sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc) */ static void sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_tmit_chunk *chk, int *abort_flag) + struct sctp_stream_in *strm, + struct sctp_queued_to_read *control, + struct sctp_tmit_chunk *chk, + int created_control, + int *abort_flag, uint32_t tsn) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; - uint32_t cum_ackp1, prev_tsn, post_tsn; - struct sctp_tmit_chunk *at, *prev, *next; - - prev = next = NULL; - cum_ackp1 = asoc->tsn_last_delivered + 1; - if (TAILQ_EMPTY(&asoc->reasmqueue)) { - /* This is the first one on the queue */ - TAILQ_INSERT_HEAD(&asoc->reasmqueue, chk, sctp_next); - /* - * we do not check for delivery of anything when only one - * fragment is here - */ - asoc->size_on_reasm_queue = chk->send_size; - sctp_ucount_incr(asoc->cnt_on_reasm_queue); - if (chk->rec.data.TSN_seq == cum_ackp1) { - if (asoc->fragmented_delivery_inprogress == 0 && - (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) != - SCTP_DATA_FIRST_FRAG) { - /* - * An empty queue, no delivery inprogress, - * we hit the next one and it does NOT have - * a FIRST fragment mark. - */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, its not first, no fragmented delivery in progress\n"); - snprintf(msg, sizeof(msg), - "Expected B-bit for TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - } else if (asoc->fragmented_delivery_inprogress && - (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) { - /* - * We are doing a partial delivery and the - * NEXT chunk MUST be either the LAST or - * MIDDLE fragment NOT a FIRST - */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it IS a first and fragmented delivery in progress\n"); - snprintf(msg, sizeof(msg), - "Didn't expect B-bit for TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - } else if (asoc->fragmented_delivery_inprogress) { - /* - * Here we are ok with a MIDDLE or LAST - * piece - */ - if (chk->rec.data.stream_number != - asoc->str_of_pdapi) { - /* Got to be the right STR No */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it IS not same stream number %d vs %d\n", - chk->rec.data.stream_number, - asoc->str_of_pdapi); - snprintf(msg, sizeof(msg), - "Expected SID=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - asoc->str_of_pdapi, - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_4; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - } else if ((asoc->fragment_flags & SCTP_DATA_UNORDERED) != - SCTP_DATA_UNORDERED && - chk->rec.data.stream_seq != asoc->ssn_of_pdapi) { - /* Got to be the right STR Seq */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it IS not same stream seq %d vs %d\n", - chk->rec.data.stream_seq, - asoc->ssn_of_pdapi); - snprintf(msg, sizeof(msg), - "Expected SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - asoc->ssn_of_pdapi, - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_5; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - } + uint32_t next_fsn; + struct sctp_tmit_chunk *at, *nat; + int do_wakeup, unordered; + + /* + * For old un-ordered data chunks. + */ + if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { + unordered = 1; + } else { + unordered = 0; + } + /* Must be added to the stream-in queue */ + if (created_control) { + if (sctp_place_control_in_stream(strm, asoc, control)) { + /* Duplicate SSN? */ + sctp_clean_up_control(stcb, control); + sctp_abort_in_reasm(stcb, control, chk, + abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_6); + return; + } + if ((tsn == (asoc->cumulative_tsn + 1) && (asoc->idata_supported == 0))) { + /* Ok we created this control and now + * lets validate that its legal i.e. there + * is a B bit set, if not and we have + * up to the cum-ack then its invalid. + */ + if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0) { + sctp_abort_in_reasm(stcb, control, chk, + abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_7); + return; } } + } + if ((asoc->idata_supported == 0) && (unordered == 1)) { + sctp_inject_old_unordered_data(stcb, asoc, control, chk, abort_flag); return; } - /* Find its place */ - TAILQ_FOREACH(at, &asoc->reasmqueue, sctp_next) { - if (SCTP_TSN_GT(at->rec.data.TSN_seq, chk->rec.data.TSN_seq)) { - /* - * one in queue is bigger than the new one, insert - * before this one - */ - /* A check */ - asoc->size_on_reasm_queue += chk->send_size; - sctp_ucount_incr(asoc->cnt_on_reasm_queue); - next = at; - TAILQ_INSERT_BEFORE(at, chk, sctp_next); - break; - } else if (at->rec.data.TSN_seq == chk->rec.data.TSN_seq) { - /* Gak, He sent me a duplicate str seq number */ + /* + * Ok we must queue the chunk into the reasembly portion: + * o if its the first it goes to the control mbuf. + * o if its not first but the next in sequence it goes to the control, + * and each succeeding one in order also goes. + * o if its not in order we place it on the list in its place. + */ + if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { + /* Its the very first one. */ + SCTPDBG(SCTP_DEBUG_XXX, + "chunk is a first fsn: %u becomes fsn_included\n", + chk->rec.data.fsn_num); + if (control->first_frag_seen) { /* - * foo bar, I guess I will just free this new guy, - * should we abort too? FIX ME MAYBE? Or it COULD be - * that the SSN's have wrapped. Maybe I should - * compare to TSN somehow... sigh for now just blow - * away the chunk! + * Error on senders part, they either + * sent us two data chunks with FIRST, + * or they sent two un-ordered chunks that + * were fragmented at the same time in the same stream. */ - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); + sctp_abort_in_reasm(stcb, control, chk, + abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_8); return; + } + control->first_frag_seen = 1; + control->fsn_included = chk->rec.data.fsn_num; + control->data = chk->data; + sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq); + chk->data = NULL; + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); + sctp_setup_tail_pointer(control); + } else { + /* Place the chunk in our list */ + int inserted=0; + if (control->last_frag_seen == 0) { + /* Still willing to raise highest FSN seen */ + if (SCTP_TSN_GT(chk->rec.data.fsn_num, control->top_fsn)) { + SCTPDBG(SCTP_DEBUG_XXX, + "We have a new top_fsn: %u\n", + chk->rec.data.fsn_num); + control->top_fsn = chk->rec.data.fsn_num; + } + if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { + SCTPDBG(SCTP_DEBUG_XXX, + "The last fsn is now in place fsn: %u\n", + chk->rec.data.fsn_num); + control->last_frag_seen = 1; + } + if (asoc->idata_supported || control->first_frag_seen) { + /* + * For IDATA we always check since we know that + * the first fragment is 0. For old DATA we have + * to receive the first before we know the first FSN + * (which is the TSN). + */ + if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn_num)) { + /* We have already delivered up to this so its a dup */ + sctp_abort_in_reasm(stcb, control, chk, + abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_9); + return; + } + } } else { - prev = at; - if (TAILQ_NEXT(at, sctp_next) == NULL) { + if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { + /* Second last? huh? */ + SCTPDBG(SCTP_DEBUG_XXX, + "Duplicate last fsn: %u (top: %u) -- abort\n", + chk->rec.data.fsn_num, control->top_fsn); + sctp_abort_in_reasm(stcb, control, + chk, abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_10); + return; + } + if (asoc->idata_supported || control->first_frag_seen) { + /* + * For IDATA we always check since we know that + * the first fragment is 0. For old DATA we have + * to receive the first before we know the first FSN + * (which is the TSN). + */ + + if (SCTP_TSN_GE(control->fsn_included, chk->rec.data.fsn_num)) { + /* We have already delivered up to this so its a dup */ + SCTPDBG(SCTP_DEBUG_XXX, + "New fsn: %u is already seen in included_fsn: %u -- abort\n", + chk->rec.data.fsn_num, control->fsn_included); + sctp_abort_in_reasm(stcb, control, chk, + abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_11); + return; + } + } + /* validate not beyond top FSN if we have seen last one */ + if (SCTP_TSN_GT(chk->rec.data.fsn_num, control->top_fsn)) { + SCTPDBG(SCTP_DEBUG_XXX, + "New fsn: %u is beyond or at top_fsn: %u -- abort\n", + chk->rec.data.fsn_num, + control->top_fsn); + sctp_abort_in_reasm(stcb, control, chk, + abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_12); + return; + } + } + /* + * If we reach here, we need to place the + * new chunk in the reassembly for this + * control. + */ + SCTPDBG(SCTP_DEBUG_XXX, + "chunk is a not first fsn: %u needs to be inserted\n", + chk->rec.data.fsn_num); + TAILQ_FOREACH(at, &control->reasm, sctp_next) { + if (SCTP_TSN_GT(at->rec.data.fsn_num, chk->rec.data.fsn_num)) { /* - * We are at the end, insert it after this - * one + * This one in queue is bigger than the new one, insert + * the new one before at. */ - /* check it first */ + SCTPDBG(SCTP_DEBUG_XXX, + "Insert it before fsn: %u\n", + at->rec.data.fsn_num); asoc->size_on_reasm_queue += chk->send_size; sctp_ucount_incr(asoc->cnt_on_reasm_queue); - TAILQ_INSERT_AFTER(&asoc->reasmqueue, at, chk, sctp_next); + TAILQ_INSERT_BEFORE(at, chk, sctp_next); + inserted = 1; break; - } - } - } - /* Now the audits */ - if (prev) { - prev_tsn = chk->rec.data.TSN_seq - 1; - if (prev_tsn == prev->rec.data.TSN_seq) { - /* - * Ok the one I am dropping onto the end is the - * NEXT. A bit of valdiation here. - */ - if ((prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == - SCTP_DATA_FIRST_FRAG || - (prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == - SCTP_DATA_MIDDLE_FRAG) { + } else if (at->rec.data.fsn_num == chk->rec.data.fsn_num) { + /* Gak, He sent me a duplicate str seq number */ /* - * Insert chk MUST be a MIDDLE or LAST - * fragment + * foo bar, I guess I will just free this new guy, + * should we abort too? FIX ME MAYBE? Or it COULD be + * that the SSN's have wrapped. Maybe I should + * compare to TSN somehow... sigh for now just blow + * away the chunk! */ - if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == - SCTP_DATA_FIRST_FRAG) { - SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - It can be a midlle or last but not a first\n"); - SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it's a FIRST!\n"); - snprintf(msg, sizeof(msg), - "Can't handle B-bit, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_6; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } - if (chk->rec.data.stream_number != - prev->rec.data.stream_number) { - /* - * Huh, need the correct STR here, - * they must be the same. - */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - Gak, Evil plot, sid:%d not the same as at:%d\n", - chk->rec.data.stream_number, - prev->rec.data.stream_number); - snprintf(msg, sizeof(msg), - "Expect SID=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - prev->rec.data.stream_number, - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_7; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } - if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != - (prev->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) { - /* - * Huh, need the same ordering here, - * they must be the same. - */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - Gak, Evil plot, U-bit not constant\n"); - snprintf(msg, sizeof(msg), - "Expect U-bit=%d for TSN=%8.8x, got U-bit=%d", - (prev->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0, - chk->rec.data.TSN_seq, - (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_8; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } - if ((prev->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0 && - chk->rec.data.stream_seq != - prev->rec.data.stream_seq) { - /* - * Huh, need the correct STR here, - * they must be the same. - */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - Gak, Evil plot, sseq:%d not the same as at:%d\n", - chk->rec.data.stream_seq, - prev->rec.data.stream_seq); - snprintf(msg, sizeof(msg), - "Expect SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - prev->rec.data.stream_seq, - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_9; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } - } else if ((prev->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == - SCTP_DATA_LAST_FRAG) { - /* Insert chk MUST be a FIRST */ - if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != - SCTP_DATA_FIRST_FRAG) { - SCTPDBG(SCTP_DEBUG_INDATA1, "Prev check - Gak, evil plot, its not FIRST and it must be!\n"); - snprintf(msg, sizeof(msg), - "Expect B-bit, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_10; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } + SCTPDBG(SCTP_DEBUG_XXX, + "Duplicate to fsn: %u -- abort\n", + at->rec.data.fsn_num); + sctp_abort_in_reasm(stcb, control, + chk, abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_13); + return; } } + if (inserted == 0) { + /* Goes on the end */ + SCTPDBG(SCTP_DEBUG_XXX, "Inserting at tail of list fsn: %u\n", + chk->rec.data.fsn_num); + asoc->size_on_reasm_queue += chk->send_size; + sctp_ucount_incr(asoc->cnt_on_reasm_queue); + TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next); + } } - if (next) { - post_tsn = chk->rec.data.TSN_seq + 1; - if (post_tsn == next->rec.data.TSN_seq) { - /* - * Ok the one I am inserting ahead of is my NEXT - * one. A bit of valdiation here. - */ - if (next->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { - /* Insert chk MUST be a last fragment */ - if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) - != SCTP_DATA_LAST_FRAG) { - SCTPDBG(SCTP_DEBUG_INDATA1, "Next chk - Next is FIRST, we must be LAST\n"); - SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, its not a last!\n"); - snprintf(msg, sizeof(msg), - "Expect only E-bit, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_11; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } - } else if ((next->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == - SCTP_DATA_MIDDLE_FRAG || - (next->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == - SCTP_DATA_LAST_FRAG) { - /* - * Insert chk CAN be MIDDLE or FIRST NOT - * LAST - */ - if ((chk->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) == - SCTP_DATA_LAST_FRAG) { - SCTPDBG(SCTP_DEBUG_INDATA1, "Next chk - Next is a MIDDLE/LAST\n"); - SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, new prev chunk is a LAST\n"); - snprintf(msg, sizeof(msg), - "Didn't expect E-bit, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_12; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } - if (chk->rec.data.stream_number != - next->rec.data.stream_number) { - /* - * Huh, need the correct STR here, - * they must be the same. - */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Next chk - Gak, Evil plot, ssn:%d not the same as at:%d\n", - chk->rec.data.stream_number, - next->rec.data.stream_number); - snprintf(msg, sizeof(msg), - "Required SID %4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - next->rec.data.stream_number, - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_13; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; - } - if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != - (next->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) { - /* - * Huh, need the same ordering here, - * they must be the same. - */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Next check - Gak, Evil plot, U-bit not constant\n"); - snprintf(msg, sizeof(msg), - "Expect U-bit=%d for TSN=%8.8x, got U-bit=%d", - (next->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0, - chk->rec.data.TSN_seq, - (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_14; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; + /* + * Ok lets see if we can suck any up into the control + * structure that are in seq if it makes sense. + */ + do_wakeup = 0; + /* + * If the first fragment has not been + * seen there is no sense in looking. + */ + if (control->first_frag_seen) { + next_fsn = control->fsn_included + 1; + TAILQ_FOREACH_SAFE(at, &control->reasm, sctp_next, nat) { + if (at->rec.data.fsn_num == next_fsn) { + /* We can add this one now to the control */ + SCTPDBG(SCTP_DEBUG_XXX, + "Adding more to control: %p at: %p fsn: %u next_fsn: %u included: %u\n", + control, at, + at->rec.data.fsn_num, + next_fsn, control->fsn_included); + TAILQ_REMOVE(&control->reasm, at, sctp_next); + sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD); + if (control->on_read_q) { + do_wakeup = 1; } - if ((next->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0 && - chk->rec.data.stream_seq != - next->rec.data.stream_seq) { - /* - * Huh, need the correct STR here, - * they must be the same. - */ - SCTPDBG(SCTP_DEBUG_INDATA1, "Next chk - Gak, Evil plot, sseq:%d not the same as at:%d\n", - chk->rec.data.stream_seq, - next->rec.data.stream_seq); - snprintf(msg, sizeof(msg), - "Required SSN %4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - next->rec.data.stream_seq, - chk->rec.data.TSN_seq, - chk->rec.data.stream_number, - chk->rec.data.stream_seq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - return; + next_fsn++; + if (control->end_added && control->pdapi_started) { + if (strm->pd_api_started) { + strm->pd_api_started = 0; + control->pdapi_started = 0; + } + if (control->on_read_q == 0) { + sctp_add_to_readq(stcb->sctp_ep, stcb, + control, + &stcb->sctp_socket->so_rcv, control->end_added, + SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); + do_wakeup = 1; + } + break; } + } else { + break; } } } - /* Do we need to do some delivery? check */ - sctp_deliver_reasm_check(stcb, asoc); + if (do_wakeup) { +#if defined(__Userspace__) + sctp_invoke_recv_callback(stcb->sctp_ep, stcb, control, SCTP_READ_LOCK_NOT_HELD); +#endif + /* Need to wakeup the reader */ + sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); + } } -/* - * This is an unfortunate routine. It checks to make sure a evil guy is not - * stuffing us full of bad packet fragments. A broken peer could also do this - * but this is doubtful. It is to bad I must worry about evil crackers sigh - * :< more cycles. - */ -static int -sctp_does_tsn_belong_to_reasm(struct sctp_association *asoc, - uint32_t TSN_seq) +static struct sctp_queued_to_read * +sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t msg_id, int ordered, int old) { - struct sctp_tmit_chunk *at; - uint32_t tsn_est; - - TAILQ_FOREACH(at, &asoc->reasmqueue, sctp_next) { - if (SCTP_TSN_GT(TSN_seq, at->rec.data.TSN_seq)) { - /* is it one bigger? */ - tsn_est = at->rec.data.TSN_seq + 1; - if (tsn_est == TSN_seq) { - /* yep. It better be a last then */ - if ((at->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != - SCTP_DATA_LAST_FRAG) { - /* - * Ok this guy belongs next to a guy - * that is NOT last, it should be a - * middle/last, not a complete - * chunk. - */ - return (1); - } else { - /* - * This guy is ok since its a LAST - * and the new chunk is a fully - * self- contained one. - */ - return (0); - } + struct sctp_queued_to_read *control; + + if (ordered) { + TAILQ_FOREACH(control, &strm->inqueue, next_instrm) { + if (control->msg_id == msg_id) { + break; } - } else if (TSN_seq == at->rec.data.TSN_seq) { - /* Software error since I have a dup? */ - return (1); - } else { - /* - * Ok, 'at' is larger than new chunk but does it - * need to be right before it. - */ - tsn_est = TSN_seq + 1; - if (tsn_est == at->rec.data.TSN_seq) { - /* Yep, It better be a first */ - if ((at->rec.data.rcv_flags & SCTP_DATA_FRAG_MASK) != - SCTP_DATA_FIRST_FRAG) { - return (1); - } else { - return (0); - } + } + } else { + if (old) { + control = TAILQ_FIRST(&strm->uno_inqueue); + return (control); + } + TAILQ_FOREACH(control, &strm->uno_inqueue, next_instrm) { + if (control->msg_id == msg_id) { + break; } } } - return (0); + return (control); } static int sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct mbuf **m, int offset, struct sctp_data_chunk *ch, int chk_length, - struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag, - int *break_flag, int last_chunk) + struct mbuf **m, int offset, int chk_length, + struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag, + int *break_flag, int last_chunk, uint8_t chtype) { /* Process a data chunk */ /* struct sctp_tmit_chunk *chk; */ + struct sctp_data_chunk *ch; + struct sctp_idata_chunk *nch, chunk_buf; struct sctp_tmit_chunk *chk; - uint32_t tsn, gap; + uint32_t tsn, fsn, gap, msg_id; struct mbuf *dmbuf; int the_len; int need_reasm_check = 0; - uint16_t strmno, strmseq; + uint16_t strmno; struct mbuf *op_err; char msg[SCTP_DIAG_INFO_LEN]; - struct sctp_queued_to_read *control; - int ordered; + struct sctp_queued_to_read *control=NULL; uint32_t protocol_id; uint8_t chunk_flags; struct sctp_stream_reset_list *liste; + struct sctp_stream_in *strm; + int ordered; + size_t clen; + int created_control = 0; + uint8_t old_data; chk = NULL; - tsn = ntohl(ch->dp.tsn); + if (chtype == SCTP_IDATA) { + nch = (struct sctp_idata_chunk *)sctp_m_getptr(*m, offset, + sizeof(struct sctp_idata_chunk), (uint8_t *)&chunk_buf); + ch = (struct sctp_data_chunk *)nch; + clen = sizeof(struct sctp_idata_chunk); + tsn = ntohl(ch->dp.tsn); + msg_id = ntohl(nch->dp.msg_id); + protocol_id = nch->dp.ppid_fsn.protocol_id; + if (ch->ch.chunk_flags & SCTP_DATA_FIRST_FRAG) + fsn = 0; + else + fsn = ntohl(nch->dp.ppid_fsn.fsn); + old_data = 0; + } else { + ch = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset, + sizeof(struct sctp_data_chunk), (uint8_t *)&chunk_buf); + tsn = ntohl(ch->dp.tsn); + protocol_id = ch->dp.protocol_id; + clen = sizeof(struct sctp_data_chunk); + fsn = tsn; + msg_id = (uint32_t)(ntohs(ch->dp.stream_sequence)); + nch = NULL; + old_data = 1; + } chunk_flags = ch->ch.chunk_flags; + if ((size_t)chk_length == clen) { + /* + * Need to send an abort since we had a + * empty data chunk. + */ + op_err = sctp_generate_no_user_data_cause(ch->dp.tsn); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_14; + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + *abort_flag = 1; + return (0); + } if ((chunk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) { asoc->send_sack = 1; } - protocol_id = ch->dp.protocol_id; ordered = ((chunk_flags & SCTP_DATA_UNORDERED) == 0); if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS); @@ -1393,54 +1699,9 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, * for on a partial delivery API. */ - /* now do the tests */ - if (((asoc->cnt_on_all_streams + - asoc->cnt_on_reasm_queue + - asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) || - (((int)asoc->my_rwnd) <= 0)) { - /* - * When we have NO room in the rwnd we check to make sure - * the reader is doing its job... - */ - if (stcb->sctp_socket->so_rcv.sb_cc) { - /* some to read, wake-up */ -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - struct socket *so; - - so = SCTP_INP_SO(stcb->sctp_ep); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - /* assoc was freed while we were unlocked */ - SCTP_SOCKET_UNLOCK(so, 1); - return (0); - } -#endif - sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } - /* now is it in the mapping array of what we have accepted? */ - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) && - SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { - /* Nope not in the valid range dump it */ - sctp_set_rwnd(stcb, asoc); - if ((asoc->cnt_on_all_streams + - asoc->cnt_on_reasm_queue + - asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) { - SCTP_STAT_INCR(sctps_datadropchklmt); - } else { - SCTP_STAT_INCR(sctps_datadroprwnd); - } - *break_flag = 1; - return (0); - } - } + /* Is the stream valid? */ strmno = ntohs(ch->dp.stream_id); + if (strmno >= asoc->streamincnt) { struct sctp_error_invalid_stream *cause; @@ -1474,14 +1735,133 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, } return (0); } + strm = &asoc->strmin[strmno]; /* - * Before we continue lets validate that we are not being fooled by - * an evil attacker. We can only have 4k chunks based on our TSN - * spread allowed by the mapping array 512 * 8 bits, so there is no - * way our stream sequence numbers could have wrapped. We of course - * only validate the FIRST fragment so the bit must be set. + * If its a fragmented message, lets see if we can + * find the control on the reassembly queues. */ - strmseq = ntohs(ch->dp.stream_sequence); + if ((chtype == SCTP_IDATA) && + ((chunk_flags & SCTP_DATA_FIRST_FRAG) == 0) && + (fsn == 0)) { + /* + * The first *must* be fsn 0, and other + * (middle/end) pieces can *not* be fsn 0. + * XXX: This can happen in case of a wrap around. + * Ignore is for now. + */ + snprintf(msg, sizeof(msg), "FSN zero for MID=%8.8x, but flags=%2.2x", + msg_id, chunk_flags); + goto err_out; + } + control = sctp_find_reasm_entry(strm, msg_id, ordered, old_data); + SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n", + chunk_flags, control); + if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) { + /* See if we can find the re-assembly entity */ + if (control != NULL) { + /* We found something, does it belong? */ + if (ordered && (msg_id != control->sinfo_ssn)) { + snprintf(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", msg_id); + err_out: + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15; + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + *abort_flag = 1; + return (0); + } + if (ordered && ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED)) { + /* We can't have a switched order with an unordered chunk */ + snprintf(msg, sizeof(msg), "All fragments of a user message must be ordered or unordered (TSN=%8.8x)", + tsn); + goto err_out; + } + if (!ordered && (((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) == 0)) { + /* We can't have a switched unordered with a ordered chunk */ + snprintf(msg, sizeof(msg), "All fragments of a user message must be ordered or unordered (TSN=%8.8x)", + tsn); + goto err_out; + } + } + } else { + /* Its a complete segment. Lets validate we + * don't have a re-assembly going on with + * the same Stream/Seq (for ordered) or in + * the same Stream for unordered. + */ + if (control != NULL) { + if (ordered || (old_data == 0)) { + SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected on msg_id: %u\n", + chunk_flags, msg_id); + snprintf(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", msg_id); + goto err_out; + } else { + if ((tsn == control->fsn_included + 1) && + (control->end_added == 0)) { + snprintf(msg, sizeof(msg), "Illegal message sequence, missing end for MID: %8.8x", control->fsn_included); + goto err_out; + } else { + control = NULL; + } + } + } + } + /* now do the tests */ + if (((asoc->cnt_on_all_streams + + asoc->cnt_on_reasm_queue + + asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) || + (((int)asoc->my_rwnd) <= 0)) { + /* + * When we have NO room in the rwnd we check to make sure + * the reader is doing its job... + */ + if (stcb->sctp_socket->so_rcv.sb_cc) { + /* some to read, wake-up */ +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + struct socket *so; + + so = SCTP_INP_SO(stcb->sctp_ep); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_SOCKET_LOCK(so, 1); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); + if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { + /* assoc was freed while we were unlocked */ + SCTP_SOCKET_UNLOCK(so, 1); + return (0); + } +#endif + sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + SCTP_SOCKET_UNLOCK(so, 1); +#endif + } + /* now is it in the mapping array of what we have accepted? */ + if (nch == NULL) { + if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map) && + SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { + /* Nope not in the valid range dump it */ + dump_packet: + sctp_set_rwnd(stcb, asoc); + if ((asoc->cnt_on_all_streams + + asoc->cnt_on_reasm_queue + + asoc->cnt_msg_on_sb) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)) { + SCTP_STAT_INCR(sctps_datadropchklmt); + } else { + SCTP_STAT_INCR(sctps_datadroprwnd); + } + *break_flag = 1; + return (0); + } + } else { + if (control == NULL) { + goto dump_packet; + } + if (SCTP_TSN_GT(fsn, control->top_fsn)) { + goto dump_packet; + } + } + } #ifdef SCTP_ASOCLOG_OF_TSNS SCTP_TCB_LOCK_ASSERT(stcb); if (asoc->tsn_in_at >= SCTP_TSN_LOG_SIZE) { @@ -1490,7 +1870,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, } asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn; asoc->in_tsnlog[asoc->tsn_in_at].strm = strmno; - asoc->in_tsnlog[asoc->tsn_in_at].seq = strmseq; + asoc->in_tsnlog[asoc->tsn_in_at].seq = msg_id; asoc->in_tsnlog[asoc->tsn_in_at].sz = chk_length; asoc->in_tsnlog[asoc->tsn_in_at].flgs = chunk_flags; asoc->in_tsnlog[asoc->tsn_in_at].stcb = (void *)stcb; @@ -1498,17 +1878,24 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, asoc->in_tsnlog[asoc->tsn_in_at].in_out = 1; asoc->tsn_in_at++; #endif + /* + * Before we continue lets validate that we are not being fooled by + * an evil attacker. We can only have Nk chunks based on our TSN + * spread allowed by the mapping array N * 8 bits, so there is no + * way our stream sequence numbers could have wrapped. We of course + * only validate the FIRST fragment so the bit must be set. + */ if ((chunk_flags & SCTP_DATA_FIRST_FRAG) && (TAILQ_EMPTY(&asoc->resetHead)) && (chunk_flags & SCTP_DATA_UNORDERED) == 0 && - SCTP_SSN_GE(asoc->strmin[strmno].last_sequence_delivered, strmseq)) { + SCTP_MSGID_GE(old_data, asoc->strmin[strmno].last_sequence_delivered, msg_id)) { /* The incoming sseq is behind where we last delivered? */ - SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ:%d delivered:%d from peer, Abort!\n", - strmseq, asoc->strmin[strmno].last_sequence_delivered); + SCTPDBG(SCTP_DEBUG_INDATA1, "EVIL/Broken-Dup S-SEQ: %u delivered: %u from peer, Abort!\n", + msg_id, asoc->strmin[strmno].last_sequence_delivered); snprintf(msg, sizeof(msg), "Delivered SSN=%4.4x, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", asoc->strmin[strmno].last_sequence_delivered, - tsn, strmno, strmseq); + tsn, strmno, msg_id); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); @@ -1519,12 +1906,21 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, * From here down we may find ch-> invalid * so its a good idea NOT to use it. *************************************/ - - the_len = (chk_length - sizeof(struct sctp_data_chunk)); + if (nch) { + the_len = (chk_length - sizeof(struct sctp_idata_chunk)); + } else { + the_len = (chk_length - sizeof(struct sctp_data_chunk)); + } if (last_chunk == 0) { - dmbuf = SCTP_M_COPYM(*m, - (offset + sizeof(struct sctp_data_chunk)), - the_len, M_NOWAIT); + if (nch) { + dmbuf = SCTP_M_COPYM(*m, + (offset + sizeof(struct sctp_idata_chunk)), + the_len, M_NOWAIT); + } else { + dmbuf = SCTP_M_COPYM(*m, + (offset + sizeof(struct sctp_data_chunk)), + the_len, M_NOWAIT); + } #ifdef SCTP_MBUF_LOGGING if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { sctp_log_mbc(dmbuf, SCTP_MBUF_ICOPY); @@ -1535,7 +1931,11 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, int l_len; dmbuf = *m; /* lop off the top part */ - m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk))); + if (nch) { + m_adj(dmbuf, (offset + sizeof(struct sctp_idata_chunk))); + } else { + m_adj(dmbuf, (offset + sizeof(struct sctp_data_chunk))); + } if (SCTP_BUF_NEXT(dmbuf) == NULL) { l_len = SCTP_BUF_LEN(dmbuf); } else { @@ -1558,12 +1958,37 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, SCTP_STAT_INCR(sctps_nomem); return (0); } + /* + * Now no matter what we need a control, get one + * if we don't have one (we may have gotten it + * above when we found the message was fragmented + */ + if (control == NULL) { + sctp_alloc_a_readq(stcb, control); + sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn, + protocol_id, + strmno, msg_id, + chunk_flags, + NULL, fsn, msg_id); + if (control == NULL) { + SCTP_STAT_INCR(sctps_nomem); + return (0); + } + if ((chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { + control->data = dmbuf; + control->tail_mbuf = NULL; + control->end_added = control->last_frag_seen = control->first_frag_seen = 1; + control->top_fsn = control->fsn_included = fsn; + } + created_control = 1; + } + SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x ordered: %d msgid: %u control: %p\n", + chunk_flags, ordered, msg_id, control); if ((chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG && - asoc->fragmented_delivery_inprogress == 0 && TAILQ_EMPTY(&asoc->resetHead) && ((ordered == 0) || - ((uint16_t)(asoc->strmin[strmno].last_sequence_delivered + 1) == strmseq && - TAILQ_EMPTY(&asoc->strmin[strmno].inqueue)))) { + ((uint16_t)(asoc->strmin[strmno].last_sequence_delivered + 1) == msg_id && + TAILQ_EMPTY(&asoc->strmin[strmno].inqueue)))) { /* Candidate for express delivery */ /* * Its not fragmented, No PD-API is up, Nothing in the @@ -1572,107 +1997,31 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, * And there is room for it in the socket buffer. Lets just * stuff it up the buffer.... */ - - /* It would be nice to avoid this copy if we could :< */ - sctp_alloc_a_readq(stcb, control); - sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn, - protocol_id, - strmno, strmseq, - chunk_flags, - dmbuf); - if (control == NULL) { - goto failed_express_del; - } SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { asoc->highest_tsn_inside_nr_map = tsn; } + SCTPDBG(SCTP_DEBUG_XXX, "Injecting control: %p to be read (msg_id: %u)\n", + control, msg_id); + sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) { /* for ordered, bump what we delivered */ - asoc->strmin[strmno].last_sequence_delivered++; + strm->last_sequence_delivered++; } SCTP_STAT_INCR(sctps_recvexpress); if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del_alt(stcb, tsn, strmseq, strmno, + sctp_log_strm_del_alt(stcb, tsn, msg_id, strmno, SCTP_STR_LOG_FROM_EXPRS_DEL); } control = NULL; - goto finish_express_del; } -failed_express_del: - /* If we reach here this is a new chunk */ - chk = NULL; - control = NULL; - /* Express for fragmented delivery? */ - if ((asoc->fragmented_delivery_inprogress) && - (stcb->asoc.control_pdapi) && - (asoc->str_of_pdapi == strmno) && - (asoc->ssn_of_pdapi == strmseq) - ) { - control = stcb->asoc.control_pdapi; - if ((chunk_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) { - /* Can't be another first? */ - goto failed_pdapi_express_del; - } - if (tsn == (control->sinfo_tsn + 1)) { - /* Yep, we can add it on */ - int end = 0; - - if (chunk_flags & SCTP_DATA_LAST_FRAG) { - end = 1; - } - if (sctp_append_to_readq(stcb->sctp_ep, stcb, control, dmbuf, end, - tsn, - &stcb->sctp_socket->so_rcv)) { - SCTP_PRINTF("Append fails end:%d\n", end); - goto failed_pdapi_express_del; - } - - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { - asoc->highest_tsn_inside_nr_map = tsn; - } - SCTP_STAT_INCR(sctps_recvexpressm); - asoc->tsn_last_delivered = tsn; - asoc->fragment_flags = chunk_flags; - asoc->tsn_of_pdapi_last_delivered = tsn; - asoc->last_flags_delivered = chunk_flags; - asoc->last_strm_seq_delivered = strmseq; - asoc->last_strm_no_delivered = strmno; - if (end) { - /* clean up the flags and such */ - asoc->fragmented_delivery_inprogress = 0; - if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) { - asoc->strmin[strmno].last_sequence_delivered++; - } - stcb->asoc.control_pdapi = NULL; - if (TAILQ_EMPTY(&asoc->reasmqueue) == 0) { - /* There could be another message ready */ - need_reasm_check = 1; - } - } - control = NULL; - goto finish_express_del; - } - } - failed_pdapi_express_del: - control = NULL; - if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { - asoc->highest_tsn_inside_nr_map = tsn; - } - } else { - SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap); - if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) { - asoc->highest_tsn_inside_map = tsn; - } - } + + /* Now will we need a chunk too? */ if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) { sctp_alloc_a_chunk(stcb, chk); if (chk == NULL) { @@ -1686,7 +2035,8 @@ failed_express_del: } chk->rec.data.TSN_seq = tsn; chk->no_fr_allowed = 0; - chk->rec.data.stream_seq = strmseq; + chk->rec.data.fsn_num = fsn; + chk->rec.data.stream_seq = msg_id; chk->rec.data.stream_number = strmno; chk->rec.data.payloadtype = protocol_id; chk->rec.data.context = stcb->asoc.context; @@ -1695,192 +2045,109 @@ failed_express_del: chk->asoc = asoc; chk->send_size = the_len; chk->whoTo = net; + SCTPDBG(SCTP_DEBUG_XXX, "Building ck: %p for control: %p to be read (msg_id: %u)\n", + chk, + control, msg_id); atomic_add_int(&net->ref_count, 1); chk->data = dmbuf; + } + /* Set the appropriate TSN mark */ + if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { + SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); + if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_nr_map)) { + asoc->highest_tsn_inside_nr_map = tsn; + } } else { - sctp_alloc_a_readq(stcb, control); - sctp_build_readq_entry_mac(control, stcb, asoc->context, net, tsn, - protocol_id, - strmno, strmseq, - chunk_flags, - dmbuf); - if (control == NULL) { - /* No memory so we drop the chunk */ - SCTP_STAT_INCR(sctps_nomem); - if (last_chunk == 0) { - /* we copied it, free the copy */ - sctp_m_freem(dmbuf); - } - return (0); + SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap); + if (SCTP_TSN_GT(tsn, asoc->highest_tsn_inside_map)) { + asoc->highest_tsn_inside_map = tsn; } - control->length = the_len; } - - /* Mark it as received */ - /* Now queue it where it belongs */ - if (control != NULL) { - /* First a sanity check */ - if (asoc->fragmented_delivery_inprogress) { + /* Now is it complete (i.e. not fragmented)? */ + if ((chunk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { + /* + * Special check for when streams are resetting. We + * could be more smart about this and check the + * actual stream to see if it is not being reset.. + * that way we would not create a HOLB when amongst + * streams being reset and those not being reset. + * + */ + if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && + SCTP_TSN_GT(tsn, liste->tsn)) { /* - * Ok, we have a fragmented delivery in progress if - * this chunk is next to deliver OR belongs in our - * view to the reassembly, the peer is evil or - * broken. + * yep its past where we need to reset... go + * ahead and queue it. */ - uint32_t estimate_tsn; - - estimate_tsn = asoc->tsn_last_delivered + 1; - if (TAILQ_EMPTY(&asoc->reasmqueue) && - (estimate_tsn == control->sinfo_tsn)) { - /* Evil/Broke peer */ - sctp_m_freem(control->data); - control->data = NULL; - if (control->whoFrom) { - sctp_free_remote_addr(control->whoFrom); - control->whoFrom = NULL; - } - sctp_free_a_readq(stcb, control); - snprintf(msg, sizeof(msg), "Reas. queue emtpy, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - tsn, strmno, strmseq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - if (last_chunk) { - *m = NULL; - } - return (0); + if (TAILQ_EMPTY(&asoc->pending_reply_queue)) { + /* first one on */ + TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next); } else { - if (sctp_does_tsn_belong_to_reasm(asoc, control->sinfo_tsn)) { - sctp_m_freem(control->data); - control->data = NULL; - if (control->whoFrom) { - sctp_free_remote_addr(control->whoFrom); - control->whoFrom = NULL; - } - sctp_free_a_readq(stcb, control); - snprintf(msg, sizeof(msg), "PD ongoing, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - tsn, strmno, strmseq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - if (last_chunk) { - *m = NULL; + struct sctp_queued_to_read *ctlOn, *nctlOn; + unsigned char inserted = 0; + TAILQ_FOREACH_SAFE(ctlOn, &asoc->pending_reply_queue, next, nctlOn) { + if (SCTP_TSN_GT(control->sinfo_tsn, ctlOn->sinfo_tsn)) { + + continue; + } else { + /* found it */ + TAILQ_INSERT_BEFORE(ctlOn, control, next); + inserted = 1; + break; } - return (0); } - } - } else { - /* No PDAPI running */ - if (!TAILQ_EMPTY(&asoc->reasmqueue)) { - /* - * Reassembly queue is NOT empty validate - * that this tsn does not need to be in - * reasembly queue. If it does then our peer - * is broken or evil. - */ - if (sctp_does_tsn_belong_to_reasm(asoc, control->sinfo_tsn)) { - sctp_m_freem(control->data); - control->data = NULL; - if (control->whoFrom) { - sctp_free_remote_addr(control->whoFrom); - control->whoFrom = NULL; - } - sctp_free_a_readq(stcb, control); - snprintf(msg, sizeof(msg), "No PD ongoing, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", - tsn, strmno, strmseq); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - *abort_flag = 1; - if (last_chunk) { - *m = NULL; - } - return (0); + if (inserted == 0) { + /* + * must be put at end, use + * prevP (all setup from + * loop) to setup nextP. + */ + TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next); } } + goto finish_express_del; } - /* ok, if we reach here we have passed the sanity checks */ if (chunk_flags & SCTP_DATA_UNORDERED) { /* queue directly into socket buffer */ + SCTPDBG(SCTP_DEBUG_XXX, "Unordered data to be read control: %p msg_id: %u\n", + control, msg_id); sctp_mark_non_revokable(asoc, control->sinfo_tsn); sctp_add_to_readq(stcb->sctp_ep, stcb, control, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - } else { - /* - * Special check for when streams are resetting. We - * could be more smart about this and check the - * actual stream to see if it is not being reset.. - * that way we would not create a HOLB when amongst - * streams being reset and those not being reset. - * - * We take complete messages that have a stream reset - * intervening (aka the TSN is after where our - * cum-ack needs to be) off and put them on a - * pending_reply_queue. The reassembly ones we do - * not have to worry about since they are all sorted - * and proceessed by TSN order. It is only the - * singletons I must worry about. - */ - if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && - SCTP_TSN_GT(tsn, liste->tsn)) { - /* - * yep its past where we need to reset... go - * ahead and queue it. - */ - if (TAILQ_EMPTY(&asoc->pending_reply_queue)) { - /* first one on */ - TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next); - } else { - struct sctp_queued_to_read *ctlOn, *nctlOn; - unsigned char inserted = 0; + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - TAILQ_FOREACH_SAFE(ctlOn, &asoc->pending_reply_queue, next, nctlOn) { - if (SCTP_TSN_GT(control->sinfo_tsn, ctlOn->sinfo_tsn)) { - continue; - } else { - /* found it */ - TAILQ_INSERT_BEFORE(ctlOn, control, next); - inserted = 1; - break; - } - } - if (inserted == 0) { - /* - * must be put at end, use - * prevP (all setup from - * loop) to setup nextP. - */ - TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next); - } - } - } else { - sctp_queue_data_to_stream(stcb, asoc, control, abort_flag); - if (*abort_flag) { - if (last_chunk) { - *m = NULL; - } - return (0); + } else { + SCTPDBG(SCTP_DEBUG_XXX, "Queue control: %p for reordering msg_id: %u\n", control, + msg_id); + sctp_queue_data_to_stream(stcb, strm, asoc, control, abort_flag, &need_reasm_check); + if (*abort_flag) { + if (last_chunk) { + *m = NULL; } + return (0); } } - } else { - /* Into the re-assembly queue */ - sctp_queue_data_for_reasm(stcb, asoc, chk, abort_flag); - if (*abort_flag) { - /* - * the assoc is now gone and chk was put onto the - * reasm queue, which has all been freed. - */ - if (last_chunk) { - *m = NULL; - } - return (0); + goto finish_express_del; + } + /* If we reach here its a reassembly */ + need_reasm_check = 1; + SCTPDBG(SCTP_DEBUG_XXX, + "Queue data to stream for reasm control: %p msg_id: %u\n", + control, msg_id); + sctp_queue_data_for_reasm(stcb, asoc, strm, control, chk, created_control, abort_flag, tsn); + if (*abort_flag) { + /* + * the assoc is now gone and chk was put onto the + * reasm queue, which has all been freed. + */ + if (last_chunk) { + *m = NULL; } + return (0); } finish_express_del: + /* Here we tidy up things */ if (tsn == (asoc->cumulative_tsn + 1)) { /* Update cum-ack */ asoc->cumulative_tsn = tsn; @@ -1896,7 +2163,7 @@ finish_express_del: SCTP_STAT_INCR(sctps_recvdata); /* Set it present please */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_STR_LOGGING_ENABLE) { - sctp_log_strm_del_alt(stcb, tsn, strmseq, strmno, SCTP_STR_LOG_FROM_MARK_TSN); + sctp_log_strm_del_alt(stcb, tsn, msg_id, strmno, SCTP_STR_LOG_FROM_MARK_TSN); } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) { sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, @@ -1923,7 +2190,7 @@ finish_express_del: /* All can be removed */ TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) { TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next); - sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag); + sctp_queue_data_to_stream(stcb, strm, asoc, ctl, abort_flag, &need_reasm_check); if (*abort_flag) { return (0); } @@ -1939,7 +2206,7 @@ finish_express_del: * ctl->sinfo_tsn > liste->tsn */ TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next); - sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag); + sctp_queue_data_to_stream(stcb, strm, asoc, ctl, abort_flag, &need_reasm_check); if (*abort_flag) { return (0); } @@ -1949,18 +2216,18 @@ finish_express_del: * Now service re-assembly to pick up anything that has been * held on reassembly queue? */ - sctp_deliver_reasm_check(stcb, asoc); + (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD); need_reasm_check = 0; } if (need_reasm_check) { /* Another one waits ? */ - sctp_deliver_reasm_check(stcb, asoc); + (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD); } return (1); } -int8_t sctp_map_lookup_tab[256] = { +static const int8_t sctp_map_lookup_tab[256] = { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, @@ -2004,7 +2271,7 @@ sctp_slide_mapping_arrays(struct sctp_tcb *stcb) * 1) Did we move the cum-ack point? * * When you first glance at this you might think - * that all entries that make up the postion + * that all entries that make up the position * of the cum-ack would be in the nr-mapping array * only.. i.e. things up to the cum-ack are always * deliverable. Thats true with one exception, when @@ -2102,7 +2369,7 @@ sctp_slide_mapping_arrays(struct sctp_tcb *stcb) #ifdef INVARIANTS panic("impossible slide"); #else - SCTP_PRINTF("impossible slide lgap:%x slide_end:%x slide_from:%x? at:%d\n", + SCTP_PRINTF("impossible slide lgap: %x slide_end: %x slide_from: %x? at: %d\n", lgap, slide_end, slide_from, at); return; #endif @@ -2111,7 +2378,7 @@ sctp_slide_mapping_arrays(struct sctp_tcb *stcb) #ifdef INVARIANTS panic("would overrun buffer"); #else - SCTP_PRINTF("Gak, would have overrun map end:%d slide_end:%d\n", + SCTP_PRINTF("Gak, would have overrun map end: %d slide_end: %d\n", asoc->mapping_array_size, slide_end); slide_end = asoc->mapping_array_size; #endif @@ -2191,7 +2458,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap) if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_17); } sctp_send_shutdown(stcb, ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination)); @@ -2257,73 +2524,12 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap) } } -void -sctp_service_queues(struct sctp_tcb *stcb, struct sctp_association *asoc) -{ - struct sctp_tmit_chunk *chk; - uint32_t tsize, pd_point; - uint16_t nxt_todel; - - if (asoc->fragmented_delivery_inprogress) { - sctp_service_reassembly(stcb, asoc); - } - /* Can we proceed further, i.e. the PD-API is complete */ - if (asoc->fragmented_delivery_inprogress) { - /* no */ - return; - } - /* - * Now is there some other chunk I can deliver from the reassembly - * queue. - */ - doit_again: - chk = TAILQ_FIRST(&asoc->reasmqueue); - if (chk == NULL) { - asoc->size_on_reasm_queue = 0; - asoc->cnt_on_reasm_queue = 0; - return; - } - nxt_todel = asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered + 1; - if ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) && - ((nxt_todel == chk->rec.data.stream_seq) || - (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED))) { - /* - * Yep the first one is here. We setup to start reception, - * by backing down the TSN just in case we can't deliver. - */ - - /* - * Before we start though either all of the message should - * be here or the socket buffer max or nothing on the - * delivery queue and something can be delivered. - */ - if (stcb->sctp_socket) { - pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT, - stcb->sctp_ep->partial_delivery_point); - } else { - pd_point = stcb->sctp_ep->partial_delivery_point; - } - if (sctp_is_all_msg_on_reasm(asoc, &tsize) || (tsize >= pd_point)) { - asoc->fragmented_delivery_inprogress = 1; - asoc->tsn_last_delivered = chk->rec.data.TSN_seq - 1; - asoc->str_of_pdapi = chk->rec.data.stream_number; - asoc->ssn_of_pdapi = chk->rec.data.stream_seq; - asoc->pdapi_ppid = chk->rec.data.payloadtype; - asoc->fragment_flags = chk->rec.data.rcv_flags; - sctp_service_reassembly(stcb, asoc); - if (asoc->fragmented_delivery_inprogress == 0) { - goto doit_again; - } - } - } -} - int sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t *high_tsn) { - struct sctp_data_chunk *ch, chunk_buf; + struct sctp_chunkhdr *ch, chunk_buf; struct sctp_association *asoc; int num_chunks = 0; /* number of control chunks processed */ int stop_proc = 0; @@ -2373,7 +2579,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, /* copy the length and free up the old */ SCTP_BUF_LEN(m) = SCTP_BUF_LEN((*mm)); sctp_m_freem(*mm); - /* sucess, back copy */ + /* success, back copy */ *mm = m; } else { /* We are in trouble in the mbuf world .. yikes */ @@ -2382,8 +2588,8 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, } #endif /* get pointer to the first chunk header */ - ch = (struct sctp_data_chunk *)sctp_m_getptr(m, *offset, - sizeof(struct sctp_data_chunk), (uint8_t *) & chunk_buf); + ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, + sizeof(struct sctp_chunkhdr), (uint8_t *) & chunk_buf); if (ch == NULL) { return (1); } @@ -2395,14 +2601,44 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, asoc->data_pkts_seen++; while (stop_proc == 0) { /* validate chunk length */ - chk_length = ntohs(ch->ch.chunk_length); + chk_length = ntohs(ch->chunk_length); if (length - *offset < chk_length) { /* all done, mutulated chunk */ stop_proc = 1; continue; } - if (ch->ch.chunk_type == SCTP_DATA) { - if ((size_t)chk_length < sizeof(struct sctp_data_chunk)) { + if ((asoc->idata_supported == 1) && + (ch->chunk_type == SCTP_DATA)) { + struct mbuf *op_err; + char msg[SCTP_DIAG_INFO_LEN]; + + snprintf(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated"); + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18; + sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); + return (2); + } + if ((asoc->idata_supported == 0) && + (ch->chunk_type == SCTP_IDATA)) { + struct mbuf *op_err; + char msg[SCTP_DIAG_INFO_LEN]; + + snprintf(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated"); + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19; + sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); + return (2); + } + if ((ch->chunk_type == SCTP_DATA) || + (ch->chunk_type == SCTP_IDATA)) { + int clen; + + if (ch->chunk_type == SCTP_DATA) { + clen = sizeof(struct sctp_data_chunk); + } else { + clen = sizeof(struct sctp_idata_chunk); + } + if (chk_length < clen) { /* * Need to send an abort since we had a * invalid data chunk. @@ -2413,19 +2649,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, snprintf(msg, sizeof(msg), "DATA chunk of length %d", chk_length); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21; - sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); - return (2); - } - if ((size_t)chk_length == sizeof(struct sctp_data_chunk)) { - /* - * Need to send an abort since we had an - * empty data chunk. - */ - struct mbuf *op_err; - - op_err = sctp_generate_no_user_data_cause(ch->dp.tsn); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (2); } @@ -2437,9 +2661,9 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, } else { last_chunk = 0; } - if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset, ch, + if (sctp_process_a_data_chunk(stcb, asoc, mm, *offset, chk_length, net, high_tsn, &abort_flag, &break_flag, - last_chunk)) { + last_chunk, ch->chunk_type)) { num_chunks++; } if (abort_flag) @@ -2455,7 +2679,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, } } else { /* not a data chunk in the data region */ - switch (ch->ch.chunk_type) { + switch (ch->chunk_type) { case SCTP_INITIATION: case SCTP_INITIATION_ACK: case SCTP_SELECTIVE_ACK: @@ -2477,6 +2701,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, case SCTP_STREAM_RESET: case SCTP_FORWARD_CUM_TSN: case SCTP_ASCONF: + { /* * Now, what do we do with KNOWN chunks that * are NOT in the right place? @@ -2486,20 +2711,18 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, * switch out and do either an ABORT() or * possibly process them. */ - if (SCTP_BASE_SYSCTL(sctp_strict_data_order)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; + struct mbuf *op_err; + char msg[SCTP_DIAG_INFO_LEN]; - snprintf(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x", - ch->ch.chunk_type); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); - return (2); - } - break; + snprintf(msg, sizeof(msg), "DATA chunk followed by chunk of type %2.2x", + ch->chunk_type); + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); + return (2); + } default: /* unknown chunk type, use bit rules */ - if (ch->ch.chunk_type & 0x40) { + if (ch->chunk_type & 0x40) { /* Add a error report to the queue */ struct mbuf *op_err; struct sctp_gen_error_cause *cause; @@ -2509,7 +2732,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, if (op_err != NULL) { cause = mtod(op_err, struct sctp_gen_error_cause *); cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK); - cause->length = htons(chk_length + sizeof(struct sctp_gen_error_cause)); + cause->length = htons((uint16_t)(chk_length + sizeof(struct sctp_gen_error_cause))); SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause); SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT); if (SCTP_BUF_NEXT(op_err) != NULL) { @@ -2519,7 +2742,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, } } } - if ((ch->ch.chunk_type & 0x80) == 0) { + if ((ch->chunk_type & 0x80) == 0) { /* discard the rest of this packet */ stop_proc = 1; } /* else skip this bad chunk and @@ -2533,8 +2756,8 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, stop_proc = 1; continue; } - ch = (struct sctp_data_chunk *)sctp_m_getptr(m, *offset, - sizeof(struct sctp_data_chunk), (uint8_t *) & chunk_buf); + ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, + sizeof(struct sctp_chunkhdr), (uint8_t *) & chunk_buf); if (ch == NULL) { *offset = length; stop_proc = 1; @@ -2564,9 +2787,6 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd); } /* now service all of the reassm queue if needed */ - if (!(TAILQ_EMPTY(&asoc->reasmqueue))) - sctp_service_queues(stcb, asoc); - if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) { /* Assure that we ack right away */ stcb->asoc.send_sack = 1; @@ -2702,7 +2922,7 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1 sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_GAP, tp1->whoTo->flight_size, tp1->book_size, - (uintptr_t)tp1->whoTo, + (uint32_t)(uintptr_t)tp1->whoTo, tp1->rec.data.TSN_seq); } sctp_flight_size_decrease(tp1); @@ -2908,7 +3128,7 @@ sctp_check_for_revoked(struct sctp_tcb *stcb, sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE, tp1->whoTo->flight_size, tp1->book_size, - (uintptr_t)tp1->whoTo, + (uint32_t)(uintptr_t)tp1->whoTo, tp1->rec.data.TSN_seq); } sctp_flight_size_increase(tp1); @@ -3219,7 +3439,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND, (tp1->whoTo ? (tp1->whoTo->flight_size) : 0), tp1->book_size, - (uintptr_t)tp1->whoTo, + (uint32_t)(uintptr_t)tp1->whoTo, tp1->rec.data.TSN_seq); } if (tp1->whoTo) { @@ -3478,7 +3698,7 @@ sctp_fs_audit(struct sctp_association *asoc) TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { if (chk->sent < SCTP_DATAGRAM_RESEND) { - SCTP_PRINTF("Chk TSN:%u size:%d inflight cnt:%d\n", + SCTP_PRINTF("Chk TSN: %u size: %d inflight cnt: %d\n", chk->rec.data.TSN_seq, chk->send_size, chk->snd_count); @@ -3498,10 +3718,10 @@ sctp_fs_audit(struct sctp_association *asoc) #ifdef INVARIANTS panic("Flight size-express incorrect? \n"); #else - SCTP_PRINTF("asoc->total_flight:%d cnt:%d\n", + SCTP_PRINTF("asoc->total_flight: %d cnt: %d\n", entry_flight, entry_cnt); - SCTP_PRINTF("Flight size-express incorrect F:%d I:%d R:%d Ab:%d ACK:%d\n", + SCTP_PRINTF("Flight size-express incorrect F: %d I: %d R: %d Ab: %d ACK: %d\n", inflight, inbetween, resend, above, acked); ret = 1; #endif @@ -3521,7 +3741,7 @@ sctp_window_probe_recovery(struct sctp_tcb *stcb, sctp_misc_ints(SCTP_FLIGHT_LOG_DWN_WP_FWD, tp1->whoTo ? tp1->whoTo->flight_size : 0, tp1->book_size, - (uintptr_t)tp1->whoTo, + (uint32_t)(uintptr_t)tp1->whoTo, tp1->rec.data.TSN_seq); return; } @@ -3540,7 +3760,7 @@ sctp_window_probe_recovery(struct sctp_tcb *stcb, sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP, tp1->whoTo->flight_size, tp1->book_size, - (uintptr_t)tp1->whoTo, + (uint32_t)(uintptr_t)tp1->whoTo, tp1->rec.data.TSN_seq); } } @@ -3557,6 +3777,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, int win_probe_recovered = 0; int j, done_once = 0; int rto_ok = 1; + uint32_t send_s; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) { sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack, @@ -3609,29 +3830,25 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, (*stcb->asoc.cc_functions.sctp_cwnd_prepare_net_for_sack)(stcb, net); } } - if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) { - uint32_t send_s; - - if (!TAILQ_EMPTY(&asoc->sent_queue)) { - tp1 = TAILQ_LAST(&asoc->sent_queue, - sctpchunk_listhead); - send_s = tp1->rec.data.TSN_seq + 1; - } else { - send_s = asoc->sending_seq; - } - if (SCTP_TSN_GE(cumack, send_s)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; + if (!TAILQ_EMPTY(&asoc->sent_queue)) { + tp1 = TAILQ_LAST(&asoc->sent_queue, + sctpchunk_listhead); + send_s = tp1->rec.data.TSN_seq + 1; + } else { + send_s = asoc->sending_seq; + } + if (SCTP_TSN_GE(cumack, send_s)) { + struct mbuf *op_err; + char msg[SCTP_DIAG_INFO_LEN]; - *abort_now = 1; - /* XXX */ - snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x", - cumack, send_s); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - return; - } + *abort_now = 1; + /* XXX */ + snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x", + cumack, send_s); + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21; + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + return; } asoc->this_sack_highest_gap = cumack; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { @@ -3660,7 +3877,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA, tp1->whoTo->flight_size, tp1->book_size, - (uintptr_t)tp1->whoTo, + (uint32_t)(uintptr_t)tp1->whoTo, tp1->rec.data.TSN_seq); } sctp_flight_size_decrease(tp1); @@ -3853,7 +4070,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, net->dest_state &= ~SCTP_ADDR_PF; sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_24); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); /* Done with this net */ @@ -3936,7 +4153,7 @@ again: } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_25); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_23); } } } @@ -3976,27 +4193,8 @@ again: if ((asoc->stream_queue_cnt == 1) && ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) && - (asoc->locked_on_sending) - ) { - struct sctp_stream_queue_pending *sp; - /* I may be in a state where we got - * all across.. but cannot write more due - * to a shutdown... we abort since the - * user did not indicate EOR in this case. The - * sp will be cleaned during free of the asoc. - */ - sp = TAILQ_LAST(&((asoc->locked_on_sending)->outqueue), - sctp_streamhead); - if ((sp) && (sp->length == 0)) { - /* Let cleanup code purge it */ - if (sp->msg_is_complete) { - asoc->stream_queue_cnt--; - } else { - asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; - asoc->locked_on_sending = NULL; - asoc->stream_queue_cnt--; - } - } + ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc))) { + asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; } if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && (asoc->stream_queue_cnt == 0)) { @@ -4008,8 +4206,9 @@ again: *abort_now = 1; /* XXX */ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_26; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + return; } else { struct sctp_nets *netp; @@ -4191,40 +4390,38 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED); } } - if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) { - /* reality check */ - if (!TAILQ_EMPTY(&asoc->sent_queue)) { - tp1 = TAILQ_LAST(&asoc->sent_queue, - sctpchunk_listhead); - send_s = tp1->rec.data.TSN_seq + 1; - } else { - tp1 = NULL; - send_s = asoc->sending_seq; - } - if (SCTP_TSN_GE(cum_ack, send_s)) { - struct mbuf *op_err; - char msg[SCTP_DIAG_INFO_LEN]; + /* reality check */ + if (!TAILQ_EMPTY(&asoc->sent_queue)) { + tp1 = TAILQ_LAST(&asoc->sent_queue, + sctpchunk_listhead); + send_s = tp1->rec.data.TSN_seq + 1; + } else { + tp1 = NULL; + send_s = asoc->sending_seq; + } + if (SCTP_TSN_GE(cum_ack, send_s)) { + struct mbuf *op_err; + char msg[SCTP_DIAG_INFO_LEN]; - /* - * no way, we have not even sent this TSN out yet. - * Peer is hopelessly messed up with us. - */ - SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n", - cum_ack, send_s); - if (tp1) { - SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1:%p\n", - tp1->rec.data.TSN_seq, (void *)tp1); - } - hopeless_peer: - *abort_now = 1; - /* XXX */ - snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x", - cum_ack, send_s); - op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_27; - sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); - return; - } + /* + * no way, we have not even sent this TSN out yet. + * Peer is hopelessly messed up with us. + */ + SCTP_PRINTF("NEW cum_ack:%x send_s:%x is smaller or equal\n", + cum_ack, send_s); + if (tp1) { + SCTP_PRINTF("Got send_s from tsn:%x + 1 of tp1: %p\n", + tp1->rec.data.TSN_seq, (void *)tp1); + } + hopeless_peer: + *abort_now = 1; + /* XXX */ + snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x", + cum_ack, send_s); + op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25; + sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); + return; } /**********************/ /* 1) check the range */ @@ -4254,7 +4451,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, /* stop any timers */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_28); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); net->partial_bytes_acked = 0; net->flight_size = 0; } @@ -4318,7 +4515,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA, tp1->whoTo->flight_size, tp1->book_size, - (uintptr_t)tp1->whoTo, + (uint32_t)(uintptr_t)tp1->whoTo, tp1->rec.data.TSN_seq); } sctp_flight_size_decrease(tp1); @@ -4435,20 +4632,18 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, num_seg, num_nr_seg, &rto_ok)) { wake_him++; } - if (SCTP_BASE_SYSCTL(sctp_strict_sacks)) { + /* + * validate the biggest_tsn_acked in the gap acks if + * strict adherence is wanted. + */ + if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) { /* - * validate the biggest_tsn_acked in the gap acks if - * strict adherence is wanted. + * peer is either confused or we are under + * attack. We must abort. */ - if (SCTP_TSN_GE(biggest_tsn_acked, send_s)) { - /* - * peer is either confused or we are under - * attack. We must abort. - */ - SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n", - biggest_tsn_acked, send_s); - goto hopeless_peer; - } + SCTP_PRINTF("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n", + biggest_tsn_acked, send_s); + goto hopeless_peer; } } /*******************************************/ @@ -4459,14 +4654,14 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, if (net->new_pseudo_cumack) sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_29); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_27); } } else { if (accum_moved) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_28); } } } @@ -4521,7 +4716,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, } if (TAILQ_EMPTY(&asoc->sent_queue) && (asoc->total_flight > 0)) { #ifdef INVARIANTS - panic("Warning flight size is postive and should be 0"); + panic("Warning flight size is positive and should be 0"); #else SCTP_PRINTF("Warning flight size incorrect should be 0 is %d\n", asoc->total_flight); @@ -4616,7 +4811,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE, tp1->whoTo->flight_size, tp1->book_size, - (uintptr_t)tp1->whoTo, + (uint32_t)(uintptr_t)tp1->whoTo, tp1->rec.data.TSN_seq); } sctp_flight_size_increase(tp1); @@ -4671,7 +4866,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, net->dest_state &= ~SCTP_ADDR_PF; sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_31); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_29); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); /* Done with this net */ @@ -4696,7 +4891,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, /* stop all timers */ sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); net->flight_size = 0; net->partial_bytes_acked = 0; } @@ -4722,25 +4917,8 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, if ((asoc->stream_queue_cnt == 1) && ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) && - (asoc->locked_on_sending) - ) { - struct sctp_stream_queue_pending *sp; - /* I may be in a state where we got - * all across.. but cannot write more due - * to a shutdown... we abort since the - * user did not indicate EOR in this case. - */ - sp = TAILQ_LAST(&((asoc->locked_on_sending)->outqueue), - sctp_streamhead); - if ((sp) && (sp->length == 0)) { - asoc->locked_on_sending = NULL; - if (sp->msg_is_complete) { - asoc->stream_queue_cnt--; - } else { - asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; - asoc->stream_queue_cnt--; - } - } + ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc))) { + asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; } if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) && (asoc->stream_queue_cnt == 0)) { @@ -4752,7 +4930,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, *abort_now = 1; /* XXX */ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_33; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_31; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } else { @@ -4902,7 +5080,7 @@ again: } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_34); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); } } } @@ -4998,141 +5176,219 @@ sctp_update_acked(struct sctp_tcb *stcb, struct sctp_shutdown_chunk *cp, int *ab static void sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, - struct sctp_stream_in *strmin) + struct sctp_stream_in *strmin) { struct sctp_queued_to_read *ctl, *nctl; struct sctp_association *asoc; - uint16_t tt; + uint32_t tt; + int need_reasm_check = 0, old; asoc = &stcb->asoc; tt = strmin->last_sequence_delivered; + if (asoc->idata_supported) { + old = 0; + } else { + old = 1; + } /* * First deliver anything prior to and including the stream no that - * came in + * came in. */ - TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next, nctl) { - if (SCTP_SSN_GE(tt, ctl->sinfo_ssn)) { + TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next_instrm, nctl) { + if (SCTP_MSGID_GE(old, tt, ctl->sinfo_ssn)) { /* this is deliverable now */ - TAILQ_REMOVE(&strmin->inqueue, ctl, next); - /* subtract pending on streams */ - asoc->size_on_all_streams -= ctl->length; - sctp_ucount_decr(asoc->cnt_on_all_streams); - /* deliver it to at least the delivery-q */ - if (stcb->sctp_socket) { - sctp_mark_non_revokable(asoc, ctl->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - ctl, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED); + if (((ctl->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { + if (ctl->on_strm_q) { + if (ctl->on_strm_q == SCTP_ON_ORDERED) { + TAILQ_REMOVE(&strmin->inqueue, ctl, next_instrm); + } else if (ctl->on_strm_q == SCTP_ON_UNORDERED) { + TAILQ_REMOVE(&strmin->uno_inqueue, ctl, next_instrm); +#ifdef INVARIANTS + } else { + panic("strmin: %p ctl: %p unknown %d", + strmin, ctl, ctl->on_strm_q); +#endif + } + ctl->on_strm_q = 0; + } + /* subtract pending on streams */ + asoc->size_on_all_streams -= ctl->length; + sctp_ucount_decr(asoc->cnt_on_all_streams); + /* deliver it to at least the delivery-q */ + if (stcb->sctp_socket) { + sctp_mark_non_revokable(asoc, ctl->sinfo_tsn); + sctp_add_to_readq(stcb->sctp_ep, stcb, + ctl, + &stcb->sctp_socket->so_rcv, + 1, SCTP_READ_LOCK_HELD, + SCTP_SO_NOT_LOCKED); + } + } else { + /* Its a fragmented message */ + if (ctl->first_frag_seen) { + /* Make it so this is next to deliver, we restore later */ + strmin->last_sequence_delivered = ctl->sinfo_ssn - 1; + need_reasm_check = 1; + break; + } } } else { /* no more delivery now. */ break; } } + if (need_reasm_check) { + int ret; + ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD); + if (SCTP_MSGID_GT(old, tt, strmin->last_sequence_delivered)) { + /* Restore the next to deliver unless we are ahead */ + strmin->last_sequence_delivered = tt; + } + if (ret == 0) { + /* Left the front Partial one on */ + return; + } + need_reasm_check = 0; + } /* * now we must deliver things in queue the normal way if any are * now ready. */ tt = strmin->last_sequence_delivered + 1; - TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next, nctl) { + TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next_instrm, nctl) { if (tt == ctl->sinfo_ssn) { - /* this is deliverable now */ - TAILQ_REMOVE(&strmin->inqueue, ctl, next); - /* subtract pending on streams */ - asoc->size_on_all_streams -= ctl->length; - sctp_ucount_decr(asoc->cnt_on_all_streams); - /* deliver it to at least the delivery-q */ - strmin->last_sequence_delivered = ctl->sinfo_ssn; - if (stcb->sctp_socket) { - sctp_mark_non_revokable(asoc, ctl->sinfo_tsn); - sctp_add_to_readq(stcb->sctp_ep, stcb, - ctl, - &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED); + if (((ctl->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { + /* this is deliverable now */ + if (ctl->on_strm_q) { + if (ctl->on_strm_q == SCTP_ON_ORDERED) { + TAILQ_REMOVE(&strmin->inqueue, ctl, next_instrm); + } else if (ctl->on_strm_q == SCTP_ON_UNORDERED) { + TAILQ_REMOVE(&strmin->uno_inqueue, ctl, next_instrm); +#ifdef INVARIANTS + } else { + panic("strmin: %p ctl: %p unknown %d", + strmin, ctl, ctl->on_strm_q); +#endif + } + ctl->on_strm_q = 0; + } + /* subtract pending on streams */ + asoc->size_on_all_streams -= ctl->length; + sctp_ucount_decr(asoc->cnt_on_all_streams); + /* deliver it to at least the delivery-q */ + strmin->last_sequence_delivered = ctl->sinfo_ssn; + if (stcb->sctp_socket) { + sctp_mark_non_revokable(asoc, ctl->sinfo_tsn); + sctp_add_to_readq(stcb->sctp_ep, stcb, + ctl, + &stcb->sctp_socket->so_rcv, 1, + SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED); + } + tt = strmin->last_sequence_delivered + 1; + } else { + /* Its a fragmented message */ + if (ctl->first_frag_seen) { + /* Make it so this is next to deliver */ + strmin->last_sequence_delivered = ctl->sinfo_ssn - 1; + need_reasm_check = 1; + break; + } } - tt = strmin->last_sequence_delivered + 1; } else { break; } } + if (need_reasm_check) { + (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD); + } } + + static void sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb, struct sctp_association *asoc, - uint16_t stream, uint16_t seq) + uint16_t stream, uint32_t seq, int ordered, int old, uint32_t cumtsn) { + struct sctp_queued_to_read *control; + struct sctp_stream_in *strm; struct sctp_tmit_chunk *chk, *nchk; - - /* For each one on here see if we need to toss it */ + int cnt_removed=0; /* - * For now large messages held on the reasmqueue that are + * For now large messages held on the stream reasm that are * complete will be tossed too. We could in theory do more * work to spin through and stop after dumping one msg aka * seeing the start of a new msg at the head, and call the * delivery function... to see if it can be delivered... But * for now we just dump everything on the queue. */ - TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { - /* Do not toss it if on a different stream or - * marked for unordered delivery in which case - * the stream sequence number has no meaning. - */ - if ((chk->rec.data.stream_number != stream) || - ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED)) { - continue; - } - if (chk->rec.data.stream_seq == seq) { - /* It needs to be tossed */ - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - if (SCTP_TSN_GT(chk->rec.data.TSN_seq, asoc->tsn_last_delivered)) { - asoc->tsn_last_delivered = chk->rec.data.TSN_seq; - asoc->str_of_pdapi = chk->rec.data.stream_number; - asoc->ssn_of_pdapi = chk->rec.data.stream_seq; - asoc->fragment_flags = chk->rec.data.rcv_flags; - } - asoc->size_on_reasm_queue -= chk->send_size; - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - - /* Clear up any stream problem */ - if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != SCTP_DATA_UNORDERED && - SCTP_SSN_GT(chk->rec.data.stream_seq, asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered)) { - /* - * We must dump forward this streams - * sequence number if the chunk is - * not unordered that is being - * skipped. There is a chance that - * if the peer does not include the - * last fragment in its FWD-TSN we - * WILL have a problem here since - * you would have a partial chunk in - * queue that may not be - * deliverable. Also if a Partial - * delivery API as started the user - * may get a partial chunk. The next - * read returning a new chunk... - * really ugly but I see no way - * around it! Maybe a notify?? - */ - asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered = chk->rec.data.stream_seq; - } - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; + strm = &asoc->strmin[stream]; + control = sctp_find_reasm_entry(strm, (uint32_t)seq, ordered, old); + if (control == NULL) { + /* Not found */ + return; + } + TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) { + /* Purge hanging chunks */ + if (old && (ordered == 0)) { + if (SCTP_TSN_GT(chk->rec.data.TSN_seq, cumtsn)) { + break; } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } else if (SCTP_SSN_GT(chk->rec.data.stream_seq, seq)) { - /* If the stream_seq is > than the purging one, we are done */ - break; } + cnt_removed++; + TAILQ_REMOVE(&control->reasm, chk, sctp_next); + asoc->size_on_reasm_queue -= chk->send_size; + sctp_ucount_decr(asoc->cnt_on_reasm_queue); + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; + } + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); + } + if (!TAILQ_EMPTY(&control->reasm)) { + /* This has to be old data, unordered */ + if (control->data) { + sctp_m_freem(control->data); + control->data = NULL; + } + sctp_reset_a_control(control, stcb->sctp_ep, cumtsn); + chk = TAILQ_FIRST(&control->reasm); + if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { + TAILQ_REMOVE(&control->reasm, chk, sctp_next); + sctp_add_chk_to_control(control, strm, stcb, asoc, + chk, SCTP_READ_LOCK_HELD); + } + sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD); + return; + } + if (control->on_strm_q == SCTP_ON_ORDERED) { + TAILQ_REMOVE(&strm->inqueue, control, next_instrm); + control->on_strm_q = 0; + } else if (control->on_strm_q == SCTP_ON_UNORDERED) { + TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); + control->on_strm_q = 0; +#ifdef INVARIANTS + } else if (control->on_strm_q) { + panic("strm: %p ctl: %p unknown %d", + strm, control, control->on_strm_q); +#endif + } + control->on_strm_q = 0; + if (control->on_read_q == 0) { + sctp_free_remote_addr(control->whoFrom); + if (control->data) { + sctp_m_freem(control->data); + control->data = NULL; + } + sctp_free_a_readq(stcb, control); } } - void sctp_handle_forward_tsn(struct sctp_tcb *stcb, struct sctp_forward_tsn_chunk *fwd, - int *abort_flag, struct mbuf *m ,int offset) + int *abort_flag, struct mbuf *m , int offset) { /* The pr-sctp fwd tsn */ /* @@ -5141,17 +5397,17 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, * * Assume we get FwdTSN(x): * - * 1) update local cumTSN to x 2) try to further advance cumTSN to x + - * others we have 3) examine and update re-ordering queue on - * pr-in-streams 4) clean up re-assembly queue 5) Send a sack to - * report where we are. + * 1) update local cumTSN to x + * 2) try to further advance cumTSN to x + others we have + * 3) examine and update re-ordering queue on pr-in-streams + * 4) clean up re-assembly queue + * 5) Send a sack to report where we are. */ struct sctp_association *asoc; uint32_t new_cum_tsn, gap; unsigned int i, fwd_sz, m_size; uint32_t str_seq; struct sctp_stream_in *strm; - struct sctp_tmit_chunk *chk, *nchk; struct sctp_queued_to_read *ctl, *sv; asoc = &stcb->asoc; @@ -5190,7 +5446,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, "New cum ack %8.8x too high, highest TSN %8.8x", new_cum_tsn, asoc->highest_tsn_inside_map); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_35; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_33; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } @@ -5221,69 +5477,16 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, /*************************************************************/ /* 2. Clear up re-assembly queue */ /*************************************************************/ - /* - * First service it if pd-api is up, just in case we can progress it - * forward - */ - if (asoc->fragmented_delivery_inprogress) { - sctp_service_reassembly(stcb, asoc); - } - /* For each one on here see if we need to toss it */ - /* - * For now large messages held on the reasmqueue that are - * complete will be tossed too. We could in theory do more - * work to spin through and stop after dumping one msg aka - * seeing the start of a new msg at the head, and call the - * delivery function... to see if it can be delivered... But - * for now we just dump everything on the queue. - */ - TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { - if (SCTP_TSN_GE(new_cum_tsn, chk->rec.data.TSN_seq)) { - /* It needs to be tossed */ - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - if (SCTP_TSN_GT(chk->rec.data.TSN_seq, asoc->tsn_last_delivered)) { - asoc->tsn_last_delivered = chk->rec.data.TSN_seq; - asoc->str_of_pdapi = chk->rec.data.stream_number; - asoc->ssn_of_pdapi = chk->rec.data.stream_seq; - asoc->fragment_flags = chk->rec.data.rcv_flags; - } - asoc->size_on_reasm_queue -= chk->send_size; - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - - /* Clear up any stream problem */ - if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != SCTP_DATA_UNORDERED && - SCTP_SSN_GT(chk->rec.data.stream_seq, asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered)) { - /* - * We must dump forward this streams - * sequence number if the chunk is - * not unordered that is being - * skipped. There is a chance that - * if the peer does not include the - * last fragment in its FWD-TSN we - * WILL have a problem here since - * you would have a partial chunk in - * queue that may not be - * deliverable. Also if a Partial - * delivery API as started the user - * may get a partial chunk. The next - * read returning a new chunk... - * really ugly but I see no way - * around it! Maybe a notify?? - */ - asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered = chk->rec.data.stream_seq; - } - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } else { - /* - * Ok we have gone beyond the end of the - * fwd-tsn's mark. - */ - break; + + /* This is now done as part of clearing up the stream/seq */ + if (asoc->idata_supported == 0) { + uint16_t sid; + /* Flush all the un-ordered data based on cum-tsn */ + SCTP_INP_READ_LOCK(stcb->sctp_ep); + for (sid = 0 ; sid < asoc->streamincnt; sid++) { + sctp_flush_reassm_for_str_seq(stcb, asoc, sid, 0, 0, 1, new_cum_tsn); } + SCTP_INP_READ_UNLOCK(stcb->sctp_ep); } /*******************************************************/ /* 3. Update the PR-stream re-ordering queues and fix */ @@ -5293,25 +5496,52 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, if (m && fwd_sz) { /* New method. */ unsigned int num_str; + uint32_t sequence; + uint16_t stream; + uint16_t ordered, flags; + int old; struct sctp_strseq *stseq, strseqbuf; + struct sctp_strseq_mid *stseq_m, strseqbuf_m; offset += sizeof(*fwd); SCTP_INP_READ_LOCK(stcb->sctp_ep); - num_str = fwd_sz / sizeof(struct sctp_strseq); + if (asoc->idata_supported) { + num_str = fwd_sz / sizeof(struct sctp_strseq_mid); + old = 0; + } else { + num_str = fwd_sz / sizeof(struct sctp_strseq); + old = 1; + } for (i = 0; i < num_str; i++) { - uint16_t st; - stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset, - sizeof(struct sctp_strseq), - (uint8_t *)&strseqbuf); - offset += sizeof(struct sctp_strseq); - if (stseq == NULL) { - break; + if (asoc->idata_supported) { + stseq_m = (struct sctp_strseq_mid *)sctp_m_getptr(m, offset, + sizeof(struct sctp_strseq_mid), + (uint8_t *)&strseqbuf_m); + offset += sizeof(struct sctp_strseq_mid); + if (stseq_m == NULL) { + break; + } + stream = ntohs(stseq_m->stream); + sequence = ntohl(stseq_m->msg_id); + flags = ntohs(stseq_m->flags); + if (flags & PR_SCTP_UNORDERED_FLAG) { + ordered = 0; + } else { + ordered = 1; + } + } else { + stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset, + sizeof(struct sctp_strseq), + (uint8_t *)&strseqbuf); + offset += sizeof(struct sctp_strseq); + if (stseq == NULL) { + break; + } + stream = ntohs(stseq->stream); + sequence = (uint32_t)ntohs(stseq->sequence); + ordered = 1; } /* Convert */ - st = ntohs(stseq->stream); - stseq->stream = st; - st = ntohs(stseq->sequence); - stseq->sequence = st; /* now process */ @@ -5320,26 +5550,50 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, * where its not all delivered. If we find it we transmute the * read entry into a PDI_ABORTED. */ - if (stseq->stream >= asoc->streamincnt) { + if (stream >= asoc->streamincnt) { /* screwed up streams, stop! */ break; } - if ((asoc->str_of_pdapi == stseq->stream) && - (asoc->ssn_of_pdapi == stseq->sequence)) { + if ((asoc->str_of_pdapi == stream) && + (asoc->ssn_of_pdapi == sequence)) { /* If this is the one we were partially delivering * now then we no longer are. Note this will change * with the reassembly re-write. */ asoc->fragmented_delivery_inprogress = 0; } - sctp_flush_reassm_for_str_seq(stcb, asoc, stseq->stream, stseq->sequence); + strm = &asoc->strmin[stream]; + if (asoc->idata_supported == 0) { + uint16_t strm_at; + + for(strm_at = strm->last_sequence_delivered; SCTP_MSGID_GE(1, sequence, strm_at); strm_at++) { + sctp_flush_reassm_for_str_seq(stcb, asoc, stream, strm_at, ordered, old, new_cum_tsn); + } + } else { + uint32_t strm_at; + + for(strm_at = strm->last_sequence_delivered; SCTP_MSGID_GE(0, sequence, strm_at); strm_at++) { + sctp_flush_reassm_for_str_seq(stcb, asoc, stream, strm_at, ordered, old, new_cum_tsn); + } + } TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) { - if ((ctl->sinfo_stream == stseq->stream) && - (ctl->sinfo_ssn == stseq->sequence)) { - str_seq = (stseq->stream << 16) | stseq->sequence; - ctl->end_added = 1; + if ((ctl->sinfo_stream == stream) && + (ctl->sinfo_ssn == sequence)) { + str_seq = (stream << 16) | (0x0000ffff & sequence); ctl->pdapi_aborted = 1; sv = stcb->asoc.control_pdapi; + ctl->end_added = 1; + if (ctl->on_strm_q == SCTP_ON_ORDERED) { + TAILQ_REMOVE(&strm->inqueue, ctl, next_instrm); + } else if (ctl->on_strm_q == SCTP_ON_UNORDERED) { + TAILQ_REMOVE(&strm->uno_inqueue, ctl, next_instrm); +#ifdef INVARIANTS + } else if (ctl->on_strm_q) { + panic("strm: %p ctl: %p unknown %d", + strm, ctl, ctl->on_strm_q); +#endif + } + ctl->on_strm_q = 0; stcb->asoc.control_pdapi = ctl; sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, stcb, @@ -5348,19 +5602,18 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, SCTP_SO_NOT_LOCKED); stcb->asoc.control_pdapi = sv; break; - } else if ((ctl->sinfo_stream == stseq->stream) && - SCTP_SSN_GT(ctl->sinfo_ssn, stseq->sequence)) { + } else if ((ctl->sinfo_stream == stream) && + SCTP_MSGID_GT(old, ctl->sinfo_ssn, sequence)) { /* We are past our victim SSN */ break; } } - strm = &asoc->strmin[stseq->stream]; - if (SCTP_SSN_GT(stseq->sequence, strm->last_sequence_delivered)) { + if (SCTP_MSGID_GT(old, sequence, strm->last_sequence_delivered)) { /* Update the sequence number */ - strm->last_sequence_delivered = stseq->sequence; + strm->last_sequence_delivered = sequence; } /* now kick the stream the new way */ - /*sa_ignore NO_NULL_CHK*/ + /*sa_ignore NO_NULL_CHK*/ sctp_kick_prsctp_reorder_queue(stcb, strm); } SCTP_INP_READ_UNLOCK(stcb->sctp_ep); @@ -5369,10 +5622,4 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, * Now slide thing forward. */ sctp_slide_mapping_arrays(stcb); - - if (!TAILQ_EMPTY(&asoc->reasmqueue)) { - /* now lets kick out and check for more fragmented delivery */ - /*sa_ignore NO_NULL_CHK*/ - sctp_deliver_reasm_check(stcb, &stcb->asoc); - } } diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_indata.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_indata.h index ef04c421d78..b00dba1df7a 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_indata.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_indata.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.h 286206 2015-08-02 16:07:30Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.h 297663 2016-04-07 09:34:41Z rrs $"); #endif #ifndef _NETINET_SCTP_INDATA_H_ @@ -45,35 +45,31 @@ sctp_build_readq_entry(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t tsn, uint32_t ppid, uint32_t context, uint16_t stream_no, - uint16_t stream_seq, uint8_t flags, + uint32_t stream_seq, uint8_t flags, struct mbuf *dm); -#define sctp_build_readq_entry_mac(_ctl, in_it, context, net, tsn, ppid, stream_no, stream_seq, flags, dm) do { \ +#define sctp_build_readq_entry_mac(_ctl, in_it, context, net, tsn, ppid, stream_no, stream_seq, flags, dm, tfsn, msgid) do { \ if (_ctl) { \ atomic_add_int(&((net)->ref_count), 1); \ + memset(_ctl, 0, sizeof(struct sctp_queued_to_read)); \ (_ctl)->sinfo_stream = stream_no; \ (_ctl)->sinfo_ssn = stream_seq; \ + TAILQ_INIT(&_ctl->reasm); \ + (_ctl)->top_fsn = tfsn; \ + (_ctl)->msg_id = msgid; \ (_ctl)->sinfo_flags = (flags << 8); \ (_ctl)->sinfo_ppid = ppid; \ (_ctl)->sinfo_context = context; \ - (_ctl)->sinfo_timetolive = 0; \ + (_ctl)->fsn_included = 0xffffffff; \ + (_ctl)->top_fsn = 0xffffffff; \ (_ctl)->sinfo_tsn = tsn; \ (_ctl)->sinfo_cumtsn = tsn; \ (_ctl)->sinfo_assoc_id = sctp_get_associd((in_it)); \ - (_ctl)->length = 0; \ - (_ctl)->held_length = 0; \ (_ctl)->whoFrom = net; \ (_ctl)->data = dm; \ - (_ctl)->tail_mbuf = NULL; \ - (_ctl)->aux_data = NULL; \ (_ctl)->stcb = (in_it); \ (_ctl)->port_from = (in_it)->rport; \ - (_ctl)->spec_flags = 0; \ - (_ctl)->do_not_ref_stcb = 0; \ - (_ctl)->end_added = 0; \ - (_ctl)->pdapi_aborted = 0; \ - (_ctl)->some_taken = 0; \ } \ } while (0) diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c index 588548559fd..9bbf101e523 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 292060 2015-12-10 11:49:32Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 304837 2016-08-26 07:49:23Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -94,7 +94,7 @@ static void sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, struct sctp_init_chunk *cp, struct sctp_inpcb *inp, - struct sctp_tcb *stcb, int *abort_no_unlock, + struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_no_unlock, #if defined(__FreeBSD__) uint8_t mflowtype, uint32_t mflowid, #endif @@ -220,8 +220,8 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); } else { SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending INIT-ACK\n"); - sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, src, dst, - sh, cp, + sctp_send_initiate_ack(inp, stcb, net, m, iphlen, offset, + src, dst, sh, cp, #if defined(__FreeBSD__) mflowtype, mflowid, #endif @@ -245,17 +245,17 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked #endif ) { - int unsent_data = 0; + int unsent_data; unsigned int i; struct sctp_stream_queue_pending *sp; struct sctp_association *asoc; - /* This function returns the number of streams that have - * true unsent data on them. Note that as it looks through - * it will clean up any places that have old data that - * has been sent but left at top of stream queue. + /* This function returns if any stream has true unsent data on it. + * Note that as it looks through it will clean up any places that + * have old data that has been sent but left at top of stream queue. */ asoc = &stcb->asoc; + unsent_data = 0; SCTP_TCB_SEND_LOCK(stcb); if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { /* Check to see if some data queued */ @@ -282,6 +282,7 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked } atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1); TAILQ_REMOVE(&stcb->asoc.strmout[i].outqueue, sp, next); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, &asoc->strmout[i], sp, 1); if (sp->net) { sctp_free_remote_addr(sp->net); sp->net = NULL; @@ -291,8 +292,13 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked sp->data = NULL; } sctp_free_a_strmoq(stcb, sp, so_locked); + if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { + unsent_data++; + } } else { unsent_data++; + } + if (unsent_data > 0) { break; } } @@ -364,8 +370,9 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) for (i = newcnt; i < asoc->pre_open_streams; i++) { outs = &asoc->strmout[i]; TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { + atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1); TAILQ_REMOVE(&outs->outqueue, sp, next); - asoc->stream_queue_cnt--; + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1); sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, 0, sp, SCTP_SO_NOT_LOCKED); if (sp->data) { @@ -388,8 +395,10 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) } SCTP_TCB_SEND_UNLOCK(stcb); asoc->streamoutcnt = asoc->pre_open_streams; - for (i = 0; i < asoc->streamoutcnt; i++) { - asoc->strmout[i].state = SCTP_STREAM_OPEN; + if (asoc->strmout) { + for (i = 0; i < asoc->streamoutcnt; i++) { + asoc->strmout[i].state = SCTP_STREAM_OPEN; + } } /* EY - nr_sack: initialize highest tsn in nr_mapping_array */ asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map; @@ -407,17 +416,9 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) if (asoc->strmin != NULL) { /* Free the old ones */ - struct sctp_queued_to_read *ctl, *nctl; - for (i = 0; i < asoc->streamincnt; i++) { - TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[i].inqueue, next, nctl) { - TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next); - sctp_free_remote_addr(ctl->whoFrom); - ctl->whoFrom = NULL; - sctp_m_freem(ctl->data); - ctl->data = NULL; - sctp_free_a_readq(stcb, ctl); - } + sctp_clean_up_stream(stcb, &asoc->strmin[i].inqueue); + sctp_clean_up_stream(stcb, &asoc->strmin[i].uno_inqueue); } SCTP_FREE(asoc->strmin, SCTP_M_STRMI); } @@ -435,8 +436,10 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) } for (i = 0; i < asoc->streamincnt; i++) { asoc->strmin[i].stream_no = i; - asoc->strmin[i].last_sequence_delivered = 0xffff; + asoc->strmin[i].last_sequence_delivered = 0xffffffff; TAILQ_INIT(&asoc->strmin[i].inqueue); + TAILQ_INIT(&asoc->strmin[i].uno_inqueue); + asoc->strmin[i].pd_api_started = 0; asoc->strmin[i].delivery_started = 0; } /* @@ -494,7 +497,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, /* load all addresses */ if ((retval = sctp_load_addresses_from_init(stcb, m, (offset + sizeof(struct sctp_init_chunk)), initack_limit, - src, dst, NULL))) { + src, dst, NULL, stcb->asoc.port))) { op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), "Problem with address parameters"); SCTPDBG(SCTP_DEBUG_INPUT1, @@ -694,7 +697,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, f_net = TAILQ_FIRST(&stcb->asoc.nets); if (f_net != r_net) { /* first one on the list is NOT the primary - * sctp_cmpaddr() is much more efficent if + * sctp_cmpaddr() is much more efficient if * the primary is the first on the list, make it * so. */ @@ -958,6 +961,26 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, * we assume the end of last record. */ SCTP_INP_READ_LOCK(stcb->sctp_ep); + if (asoc->control_pdapi->on_strm_q) { + struct sctp_stream_in *strm; + + strm = &asoc->strmin[asoc->control_pdapi->sinfo_stream]; + if (asoc->control_pdapi->on_strm_q == SCTP_ON_UNORDERED) { + /* Unordered */ + TAILQ_REMOVE(&strm->uno_inqueue, asoc->control_pdapi, next_instrm); + asoc->control_pdapi->on_strm_q = 0; + } else if (asoc->control_pdapi->on_strm_q == SCTP_ON_ORDERED) { + /* Ordered */ + TAILQ_REMOVE(&strm->inqueue, asoc->control_pdapi, next_instrm); + asoc->control_pdapi->on_strm_q = 0; +#ifdef INVARIANTS + } else { + panic("Unknown state on ctrl:%p on_strm_q:%d", + asoc->control_pdapi, + asoc->control_pdapi->on_strm_q); +#endif + } + } asoc->control_pdapi->end_added = 1; asoc->control_pdapi->pdapi_aborted = 1; asoc->control_pdapi = NULL; @@ -975,7 +998,9 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, return; } #endif - sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); + if (stcb->sctp_socket) { + sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); + } #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -1091,7 +1116,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, #ifdef INVARIANTS if (!TAILQ_EMPTY(&asoc->send_queue) || !TAILQ_EMPTY(&asoc->sent_queue) || - !stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { + sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED)) { panic("Queues are not empty when handling SHUTDOWN-ACK"); } #endif @@ -1126,7 +1151,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, /* * Skip past the param header and then we will find the chunk that caused the - * problem. There are two possiblities ASCONF or FWD-TSN other than that and + * problem. There are two possibilities ASCONF or FWD-TSN other than that and * our peer must be broken. */ static void @@ -1141,6 +1166,7 @@ sctp_process_unrecog_chunk(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr, case SCTP_ASCONF: sctp_asconf_cleanup(stcb, net); break; + case SCTP_IFORWARD_CUM_TSN: case SCTP_FORWARD_CUM_TSN: stcb->asoc.prsctp_supported = 0; break; @@ -1297,7 +1323,7 @@ sctp_handle_error(struct sctp_chunkhdr *ch, * (or IPv4 for that matter) it does not matter. If * they don't support that type of address, they can * NOT possibly get that packet type... i.e. with no - * IPv6 you can't recieve a IPv6 packet. so we can + * IPv6 you can't receive a IPv6 packet. so we can * safely ignore this one. If we ever added support * for HOSTNAME Addresses, then we would need to do * something here. @@ -1730,7 +1756,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, */ if (sctp_load_addresses_from_init(stcb, m, init_offset + sizeof(struct sctp_init_chunk), - initack_offset, src, dst, init_src)) { + initack_offset, src, dst, init_src, stcb->asoc.port)) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 4; return (NULL); @@ -1855,7 +1881,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } if (sctp_load_addresses_from_init(stcb, m, init_offset + sizeof(struct sctp_init_chunk), - initack_offset, src, dst, init_src)) { + initack_offset, src, dst, init_src, stcb->asoc.port)) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 10; return (NULL); @@ -2023,7 +2049,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, asoc->strmout[i].abandoned_unsent[0] = 0; #endif stcb->asoc.strmout[i].stream_no = i; - stcb->asoc.strmout[i].next_sequence_send = 0; + stcb->asoc.strmout[i].next_mid_ordered = 0; + stcb->asoc.strmout[i].next_mid_unordered = 0; stcb->asoc.strmout[i].last_msg_incomplete = 0; } /* process the INIT-ACK info (my info) */ @@ -2065,7 +2092,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, if (sctp_load_addresses_from_init(stcb, m, init_offset + sizeof(struct sctp_init_chunk), - initack_offset, src, dst, init_src)) { + initack_offset, src, dst, init_src, stcb->asoc.port)) { if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 14; @@ -2169,23 +2196,24 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, * and popluate */ - /* + /* * Here we do a trick, we set in NULL for the proc/thread argument. We * do this since in effect we only use the p argument when * the socket is unbound and we must do an implicit bind. * Since we are getting a cookie, we cannot be unbound. */ stcb = sctp_aloc_assoc(inp, init_src, &error, - ntohl(initack_cp->init.initiate_tag), vrf_id, - ntohs(initack_cp->init.num_outbound_streams), + ntohl(initack_cp->init.initiate_tag), vrf_id, + ntohs(initack_cp->init.num_outbound_streams), + port, #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 - (struct thread *)NULL + (struct thread *)NULL #elif defined(__Windows__) - (PKTHREAD)NULL + (PKTHREAD)NULL #else - (struct proc *)NULL + (struct proc *)NULL #endif - ); + ); if (stcb == NULL) { struct mbuf *op_err; @@ -2283,7 +2311,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, /* load all addresses */ if (sctp_load_addresses_from_init(stcb, m, init_offset + sizeof(struct sctp_init_chunk), initack_offset, - src, dst, init_src)) { + src, dst, init_src, port)) { atomic_add_int(&stcb->asoc.refcnt, 1); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_TCB_UNLOCK(stcb); @@ -2457,12 +2485,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, (*netp)->RTO = sctp_calculate_rto(stcb, asoc, *netp, &cookie->time_entered, sctp_align_unsafe_makecopy, SCTP_RTT_FROM_NON_DATA); -#if defined(INET) || defined(INET6) - if (((*netp)->port == 0) && (port != 0)) { - sctp_pathmtu_adjustment(stcb, (*netp)->mtu - sizeof(struct udphdr)); - } - (*netp)->port = port; -#endif } /* respond with a COOKIE-ACK */ sctp_send_cookie_ack(stcb); @@ -2832,7 +2854,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, */ if (netl == NULL) { /* TSNH! Huh, why do I need to add this address here? */ - if (sctp_add_remote_addr(*stcb, to, NULL, SCTP_DONOT_SETSCOPE, SCTP_IN_COOKIE_PROC)) { + if (sctp_add_remote_addr(*stcb, to, NULL, port, + SCTP_DONOT_SETSCOPE, SCTP_IN_COOKIE_PROC)) { return (NULL); } netl = sctp_findnet(*stcb, to); @@ -3356,7 +3379,7 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSE #ifdef INVARIANTS if (!TAILQ_EMPTY(&asoc->send_queue) || !TAILQ_EMPTY(&asoc->sent_queue) || - !stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { + sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED)) { panic("Queues are not empty when handling SHUTDOWN-COMPLETE"); } #endif @@ -3494,7 +3517,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PDRP, tp1->whoTo->flight_size, tp1->book_size, - (uintptr_t)stcb, + (uint32_t)(uintptr_t)stcb, tp1->rec.data.TSN_seq); } if (tp1->sent < SCTP_DATAGRAM_RESEND) { @@ -3602,6 +3625,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, /* resend last asconf ack */ sctp_send_asconf_ack(stcb); break; + case SCTP_IFORWARD_CUM_TSN: case SCTP_FORWARD_CUM_TSN: send_forward_tsn(stcb, &stcb->asoc); break; @@ -3627,7 +3651,7 @@ sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *l uint16_t temp; /* - * We set things to 0xffff since this is the last delivered sequence + * We set things to 0xffffffff since this is the last delivered sequence * and we will be sending in 0 after the reset. */ @@ -3637,12 +3661,12 @@ sctp_reset_in_stream(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t *l if (temp >= stcb->asoc.streamincnt) { continue; } - stcb->asoc.strmin[temp].last_sequence_delivered = 0xffff; + stcb->asoc.strmin[temp].last_sequence_delivered = 0xffffffff; } } else { list = NULL; for (i = 0; i < stcb->asoc.streamincnt; i++) { - stcb->asoc.strmin[i].last_sequence_delivered = 0xffff; + stcb->asoc.strmin[i].last_sequence_delivered = 0xffffffff; } } sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_RECV, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED); @@ -3661,11 +3685,13 @@ sctp_reset_out_streams(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t /* no such stream */ continue; } - stcb->asoc.strmout[temp].next_sequence_send = 0; + stcb->asoc.strmout[temp].next_mid_ordered = 0; + stcb->asoc.strmout[temp].next_mid_unordered = 0; } } else { for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - stcb->asoc.strmout[i].next_sequence_send = 0; + stcb->asoc.strmout[i].next_mid_ordered = 0; + stcb->asoc.strmout[i].next_mid_unordered = 0; } } sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_SEND, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED); @@ -4180,20 +4206,28 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch /* copy off the old data */ for (i = 0; i < stcb->asoc.streamincnt; i++) { TAILQ_INIT(&stcb->asoc.strmin[i].inqueue); + TAILQ_INIT(&stcb->asoc.strmin[i].uno_inqueue); stcb->asoc.strmin[i].stream_no = i; stcb->asoc.strmin[i].last_sequence_delivered = oldstrm[i].last_sequence_delivered; stcb->asoc.strmin[i].delivery_started = oldstrm[i].delivery_started; + stcb->asoc.strmin[i].pd_api_started = oldstrm[i].pd_api_started; /* now anything on those queues? */ - TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].inqueue, next, nctl) { - TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next); - TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next); + TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].inqueue, next_instrm, nctl) { + TAILQ_REMOVE(&oldstrm[i].inqueue, ctl, next_instrm); + TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].inqueue, ctl, next_instrm); + } + TAILQ_FOREACH_SAFE(ctl, &oldstrm[i].uno_inqueue, next_instrm, nctl) { + TAILQ_REMOVE(&oldstrm[i].uno_inqueue, ctl, next_instrm); + TAILQ_INSERT_TAIL(&stcb->asoc.strmin[i].uno_inqueue, ctl, next_instrm); } } /* Init the new streams */ for (i = stcb->asoc.streamincnt; i < num_stream; i++) { TAILQ_INIT(&stcb->asoc.strmin[i].inqueue); + TAILQ_INIT(&stcb->asoc.strmin[i].uno_inqueue); stcb->asoc.strmin[i].stream_no = i; - stcb->asoc.strmin[i].last_sequence_delivered = 0xffff; + stcb->asoc.strmin[i].last_sequence_delivered = 0xffffffff; + stcb->asoc.strmin[i].pd_api_started = 0; stcb->asoc.strmin[i].delivery_started = 0; } SCTP_FREE(oldstrm, SCTP_M_STRMI); @@ -4602,7 +4636,7 @@ sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp, (stcb->asoc.sat_t3_loss_recovery == 0) && (stcb->asoc.sat_network)) { /* - * This is debateable but for sat networks it makes sense + * This is debatable but for sat networks it makes sense * Note if a T3 timer has went off, we will prohibit any * changes to cwnd until we exit the t3 loss recovery. */ @@ -5004,7 +5038,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, } sctp_handle_init(m, iphlen, *offset, src, dst, sh, (struct sctp_init_chunk *)ch, inp, - stcb, &abort_no_unlock, + stcb, *netp, &abort_no_unlock, #if defined(__FreeBSD__) mflowtype, mflowid, #endif @@ -5024,7 +5058,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, if ((stcb) && (stcb->asoc.total_output_queue_size)) { ; } else { - if (locked_tcb != stcb) { + if ((locked_tcb != NULL) && (locked_tcb != stcb)) { /* Very unlikely */ SCTP_TCB_UNLOCK(locked_tcb); } @@ -5602,6 +5636,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, } break; case SCTP_FORWARD_CUM_TSN: + case SCTP_IFORWARD_CUM_TSN: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_FWD-TSN\n"); if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) { /* Its not ours */ @@ -5646,6 +5681,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, *offset = length; return (NULL); } + /* + * For sending a SACK this looks like DATA + * chunks. + */ + stcb->asoc.last_data_chunk_from = stcb->asoc.last_control_chunk_from; sctp_handle_forward_tsn(stcb, (struct sctp_forward_tsn_chunk *)ch, &abort_flag, m, *offset); if (abort_flag) { @@ -5761,7 +5801,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length, len = min(SCTP_SIZE32(chk_length), (uint32_t)(length - *offset)); cause = mtod(op_err, struct sctp_gen_error_cause *); cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK); - cause->length = htons(len + sizeof(struct sctp_gen_error_cause)); + cause->length = htons((uint16_t)(len + sizeof(struct sctp_gen_error_cause))); SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause); SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT); if (SCTP_BUF_NEXT(op_err) != NULL) { @@ -5855,9 +5895,18 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt stcb = sctp_findassociation_addr(m, offset, src, dst, sh, ch, &inp, &net, vrf_id); #if defined(INET) || defined(INET6) - if ((net != NULL) && (port != 0)) { + if ((ch->chunk_type != SCTP_INITIATION) && + (net != NULL) && (net->port != port)) { if (net->port == 0) { - sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr)); + /* UDP encapsulation turned on. */ + net->mtu -= sizeof(struct udphdr); + if (stcb->asoc.smallest_mtu > net->mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu); + } + } else if (port == 0) { + /* UDP encapsulation turned off. */ + net->mtu += sizeof(struct udphdr); + /* XXX Update smallest_mtu */ } net->port = port; } @@ -5888,9 +5937,18 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt stcb = sctp_findassociation_addr(m, offset, src, dst, sh, ch, &inp, &net, vrf_id); #if defined(INET) || defined(INET6) - if ((net != NULL) && (port != 0)) { + if ((ch->chunk_type != SCTP_INITIATION) && + (net != NULL) && (net->port != port)) { if (net->port == 0) { - sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr)); + /* UDP encapsulation turned on. */ + net->mtu -= sizeof(struct udphdr); + if (stcb->asoc.smallest_mtu > net->mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu); + } + } else if (port == 0) { + /* UDP encapsulation turned off. */ + net->mtu += sizeof(struct udphdr); + /* XXX Update smallest_mtu */ } net->port = port; } @@ -6012,9 +6070,18 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt */ inp = stcb->sctp_ep; #if defined(INET) || defined(INET6) - if ((net != NULL) && (port != 0)) { + if ((ch->chunk_type != SCTP_INITIATION) && + (net != NULL) && (net->port != port)) { if (net->port == 0) { - sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr)); + /* UDP encapsulation turned on. */ + net->mtu -= sizeof(struct udphdr); + if (stcb->asoc.smallest_mtu > net->mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu); + } + } else if (port == 0) { + /* UDP encapsulation turned off. */ + net->mtu += sizeof(struct udphdr); + /* XXX Update smallest_mtu */ } net->port = port; } @@ -6194,7 +6261,9 @@ trigger_send: if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) { cnt_ctrl_ready = stcb->asoc.ctrl_queue_cnt - stcb->asoc.ecn_echo_cnt_onq; } - if (cnt_ctrl_ready || stcb->asoc.trigger_reset || + if (!TAILQ_EMPTY(&stcb->asoc.asconf_send_queue) || + cnt_ctrl_ready || + stcb->asoc.trigger_reset || ((un_sent) && (stcb->asoc.peers_rwnd > 0 || (stcb->asoc.peers_rwnd <= 0 && stcb->asoc.total_flight == 0)))) { @@ -6478,7 +6547,7 @@ sctp_input(struct mbuf *m, int off) tag = htonl(sh->v_tag); flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port); m->m_pkthdr.flowid = flowid; - M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); + M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE_HASH); } cpu_to_use = sctp_cpuarry[flowid % mp_ncpus]; sctp_queue_to_mcore(m, off, cpu_to_use); diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_os_userspace.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_os_userspace.h index a261deb01b8..fd3e0d7531f 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_os_userspace.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_os_userspace.h @@ -324,7 +324,7 @@ struct ip { u_char ip_ttl; u_char ip_p; u_short ip_sum; - struct in_addr ip_src, ip_dst; + struct in_addr ip_src, ip_dst; }; struct ifaddrs { @@ -345,7 +345,7 @@ struct udphdr { }; struct iovec { - unsigned long len; + size_t len; char *buf; }; @@ -762,14 +762,6 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT); umem_cache_destroy(zone); #endif -/* global struct ifaddrs used in sctp_init_ifns_for_vrf getifaddrs call - * but references to fields are needed to persist as the vrf is queried. - * getifaddrs allocates memory that needs to be freed with a freeifaddrs - * call; this global is used to call freeifaddrs upon in sctp_pcb_finish - */ -extern struct ifaddrs *g_interfaces; - - /* * __Userspace__ Defining sctp_hashinit_flags() and sctp_hashdestroy() for userland. */ @@ -1034,8 +1026,10 @@ int sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af); struct sockaddr_conn { #ifdef HAVE_SCONN_LEN uint8_t sconn_len; -#endif uint8_t sconn_family; +#else + uint16_t sconn_family; +#endif uint16_t sconn_port; void *sconn_addr; }; diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_output.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_output.c index 3a58970ae41..310dbc6f6cb 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_output.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_output.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 292060 2015-12-10 11:49:32Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.c 304579 2016-08-22 01:45:29Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -94,7 +94,7 @@ struct sack_track { struct sctp_gap_ack_block gaps[SCTP_MAX_GAPS_INARRAY]; }; -struct sack_track sack_array[256] = { +const struct sack_track sack_array[256] = { {0, 0, 0, 0, /* 0x00 */ {{0, 0}, {0, 0}, @@ -3151,7 +3151,7 @@ sctp_choose_boundall(struct sctp_inpcb *inp, ifn, num_preferred); if (num_preferred == 0) { /* None on this interface. */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefered -- skipping to next\n"); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "No preferred -- skipping to next\n"); continue; } SCTPDBG(SCTP_DEBUG_OUTPUT2, @@ -3238,7 +3238,7 @@ again_with_private_addresses_allowed: * It is restricted for some * reason.. probably not yet added. */ - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its resticted\n"); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its restricted\n"); sifa = NULL; continue; } @@ -3306,12 +3306,14 @@ again_with_private_addresses_allowed: } } #ifdef INET - 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; + 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: @@ -3405,10 +3407,11 @@ sctp_source_address_selection(struct sctp_inpcb *inp, #endif /** - * Rules: - Find the route if needed, cache if I can. - Look at - * interface address in route, Is it in the bound list. If so we - * have the best source. - If not we must rotate amongst the - * addresses. + * Rules: + * - Find the route if needed, cache if I can. + * - Look at interface address in route, Is it in the bound list. If so we + * have the best source. + * - If not we must rotate amongst the addresses. * * Cavets and issues * @@ -3600,7 +3603,7 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize) return (found); } /* It is exactly what we want. Copy it out. */ - m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), cpsize, (caddr_t)data); + m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), (int)cpsize, (caddr_t)data); return (1); } else { struct sctp_sndrcvinfo *sndrcvinfo; @@ -3733,7 +3736,8 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er for (i = 0; i < stcb->asoc.streamoutcnt; i++) { TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); stcb->asoc.strmout[i].chunks_on_queues = 0; - stcb->asoc.strmout[i].next_sequence_send = 0; + stcb->asoc.strmout[i].next_mid_ordered = 0; + stcb->asoc.strmout[i].next_mid_unordered = 0; #if defined(SCTP_DETAILED_STR_STATS) for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { stcb->asoc.strmout[i].abandoned_sent[j] = 0; @@ -3746,7 +3750,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er stcb->asoc.strmout[i].stream_no = i; stcb->asoc.strmout[i].last_msg_incomplete = 0; stcb->asoc.strmout[i].state = SCTP_STREAM_OPENING; - stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL); + stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); } } break; @@ -3769,7 +3773,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er *error = EINVAL; return (1); } - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); @@ -3803,14 +3807,14 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er *error = EINVAL; return (1); } - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); } } else #endif - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL, + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL, stcb->asoc.port, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); @@ -4339,7 +4343,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip)); udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); udp->uh_dport = port; - udp->uh_ulen = htons(packet_length - sizeof(struct ip)); + udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip))); #if !defined(__Windows__) && !defined(__Userspace__) #if defined(__FreeBSD__) && ((__FreeBSD_version > 803000 && __FreeBSD_version < 900000) || __FreeBSD_version > 900000) if (V_udp_cksum) { @@ -4625,7 +4629,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } else { ip6h->ip6_nxt = IPPROTO_SCTP; } - ip6h->ip6_plen = (packet_length - sizeof(struct ip6_hdr)); + ip6h->ip6_plen = (uint16_t)(packet_length - sizeof(struct ip6_hdr)); ip6h->ip6_dst = sin6->sin6_addr; /* @@ -4794,7 +4798,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); udp->uh_dport = port; - udp->uh_ulen = htons(packet_length - sizeof(struct ip6_hdr)); + udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr))); udp->uh_sum = 0; sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); } else { @@ -5155,6 +5159,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t) + chunk_len); if (stcb->asoc.prsctp_supported == 1) { pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; + if (stcb->asoc.idata_supported) { + pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN; + } } if (stcb->asoc.auth_supported == 1) { pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; @@ -5166,6 +5173,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked if (stcb->asoc.reconfig_supported == 1) { pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; } + if (stcb->asoc.idata_supported) { + pr_supported->chunk_types[num_ext++] = SCTP_IDATA; + } if (stcb->asoc.nrsack_supported == 1) { pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; } @@ -5669,12 +5679,16 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, uint16_t ptype, plen; uint8_t fnd; struct sctp_nets *net; + int check_src; #ifdef INET struct sockaddr_in sin4, *sa4; #endif #ifdef INET6 struct sockaddr_in6 sin6, *sa6; #endif +#if defined(__Userspace__) + struct sockaddr_conn *sac; +#endif #ifdef INET memset(&sin4, 0, sizeof(sin4)); @@ -5691,39 +5705,80 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, #endif #endif /* First what about the src address of the pkt ? */ - fnd = 0; - TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - sa = (struct sockaddr *)&net->ro._l_addr; - if (sa->sa_family == src->sa_family) { + check_src = 0; + switch (src->sa_family) { +#ifdef INET + case AF_INET: + if (asoc->scope.ipv4_addr_legal) { + check_src = 1; + } + break; +#endif +#ifdef INET6 + case AF_INET6: + if (asoc->scope.ipv6_addr_legal) { + check_src = 1; + } + break; +#endif +#if defined(__Userspace__) + case AF_CONN: + if (asoc->scope.conn_addr_legal) { + check_src = 1; + } + break; +#endif + default: + /* TSNH */ + break; + } + if (check_src) { + fnd = 0; + TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + sa = (struct sockaddr *)&net->ro._l_addr; + if (sa->sa_family == src->sa_family) { #ifdef INET - if (sa->sa_family == AF_INET) { - struct sockaddr_in *src4; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *src4; - sa4 = (struct sockaddr_in *)sa; - src4 = (struct sockaddr_in *)src; - if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) { - fnd = 1; - break; + sa4 = (struct sockaddr_in *)sa; + src4 = (struct sockaddr_in *)src; + if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) { + fnd = 1; + break; + } } - } #endif #ifdef INET6 - if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *src6; + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *src6; - sa6 = (struct sockaddr_in6 *)sa; - src6 = (struct sockaddr_in6 *)src; - if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) { - fnd = 1; - break; + sa6 = (struct sockaddr_in6 *)sa; + src6 = (struct sockaddr_in6 *)src; + if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) { + fnd = 1; + break; + } } - } #endif +#if defined(__Userspace__) + if (sa->sa_family == AF_CONN) { + struct sockaddr_conn *srcc; + + sac = (struct sockaddr_conn *)sa; + srcc = (struct sockaddr_conn *)src; + if (sac->sconn_addr == srcc->sconn_addr) { + fnd = 1; + break; + } + } +#endif + } + } + if (fnd == 0) { + /* New address added! no need to look further. */ + return (1); } - } - if (fnd == 0) { - /* New address added! no need to look futher. */ - return (1); } /* Ok so far lets munge through the rest of the packet */ offset += sizeof(struct sctp_init_chunk); @@ -5744,9 +5799,11 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, phdr == NULL) { return (1); } - p4 = (struct sctp_ipv4addr_param *)phdr; - sin4.sin_addr.s_addr = p4->addr; - sa_touse = (struct sockaddr *)&sin4; + if (asoc->scope.ipv4_addr_legal) { + p4 = (struct sctp_ipv4addr_param *)phdr; + sin4.sin_addr.s_addr = p4->addr; + sa_touse = (struct sockaddr *)&sin4; + } break; } #endif @@ -5761,10 +5818,12 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, phdr == NULL) { return (1); } - p6 = (struct sctp_ipv6addr_param *)phdr; - memcpy((caddr_t)&sin6.sin6_addr, p6->addr, - sizeof(p6->addr)); - sa_touse = (struct sockaddr *)&sin6; + if (asoc->scope.ipv6_addr_legal) { + p6 = (struct sctp_ipv6addr_param *)phdr; + memcpy((caddr_t)&sin6.sin6_addr, p6->addr, + sizeof(p6->addr)); + sa_touse = (struct sockaddr *)&sin6; + } break; } #endif @@ -5820,7 +5879,8 @@ sctp_are_there_new_addresses(struct sctp_association *asoc, */ void sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct mbuf *init_pkt, int iphlen, int offset, + struct sctp_nets *src_net, struct mbuf *init_pkt, + int iphlen, int offset, struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, struct sctp_init_chunk *init_chk, #if defined(__FreeBSD__) @@ -5868,22 +5928,42 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc = NULL; } if ((asoc != NULL) && - (SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) && - (sctp_are_there_new_addresses(asoc, init_pkt, offset, src))) { - /* new addresses, out of here in non-cookie-wait states */ - /* - * Send a ABORT, we don't add the new address error clause - * though we even set the T bit and copy in the 0 tag.. this - * looks no different than if no listener was present. - */ - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "Address added"); - sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err, + (SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT)) { + if (sctp_are_there_new_addresses(asoc, init_pkt, offset, src)) { + /* + * new addresses, out of here in non-cookie-wait states + * + * Send an ABORT, without the new address error cause. + * This looks no different than if no listener + * was present. + */ + op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), + "Address added"); + sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err, #if defined(__FreeBSD__) - mflowtype, mflowid, inp->fibnum, + mflowtype, mflowid, inp->fibnum, #endif - vrf_id, port); - return; + vrf_id, port); + return; + } + if (src_net != NULL && (src_net->port != port)) { + /* + * change of remote encapsulation port, out of here in + * non-cookie-wait states + * + * Send an ABORT, without an specific error cause. + * This looks no different than if no listener + * was present. + */ + op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), + "Remote encapsulation port changed"); + sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err, +#if defined(__FreeBSD__) + mflowtype, mflowid, inp->fibnum, +#endif + vrf_id, port); + return; + } } abort_flag = 0; op_err = sctp_arethere_unrecognized_parameters(init_pkt, @@ -5946,7 +6026,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, stc.peerport = sh->src_port; /* - * If we wanted to honor cookie life extentions, we would add to + * If we wanted to honor cookie life extensions, we would add to * stc.cookie_life. For now we should NOT honor any extension */ stc.site_scope = stc.local_scope = stc.loopback_scope = 0; @@ -6015,7 +6095,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, stc.addr_type = SCTP_IPV6_ADDRESS; memcpy(&stc.address, &src6->sin6_addr, sizeof(struct in6_addr)); #if defined(__FreeBSD__) && (((__FreeBSD_version < 900000) && (__FreeBSD_version >= 804000)) || (__FreeBSD_version > 900000)) - stc.scope_id = in6_getscope(&src6->sin6_addr); + stc.scope_id = ntohs(in6_getscope(&src6->sin6_addr)); #else stc.scope_id = 0; #endif @@ -6198,7 +6278,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* Now lets put the SCTP header in place */ initack = mtod(m, struct sctp_init_ack_chunk *); /* Save it off for quick ref */ - stc.peers_vtag = init_chk->init.initiate_tag; + stc.peers_vtag = ntohl(init_chk->init.initiate_tag); /* who are we */ memcpy(stc.identification, SCTP_VERSION_STRING, min(strlen(SCTP_VERSION_STRING), sizeof(stc.identification))); @@ -6330,6 +6410,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, if (((asoc != NULL) && (asoc->prsctp_supported == 1)) || ((asoc == NULL) && (inp->prsctp_supported == 1))) { pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; + if (((asoc != NULL) && (asoc->idata_supported == 1)) || + ((asoc == NULL) && (inp->idata_supported == 1))) { + pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN; + } } if (((asoc != NULL) && (asoc->auth_supported == 1)) || ((asoc == NULL) && (inp->auth_supported == 1))) { @@ -6344,6 +6428,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, ((asoc == NULL) && (inp->reconfig_supported == 1))) { pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; } + if (((asoc != NULL) && (asoc->idata_supported == 1)) || + ((asoc == NULL) && (inp->idata_supported == 1))) { + pr_supported->chunk_types[num_ext++] = SCTP_IDATA; + } if (((asoc != NULL) && (asoc->nrsack_supported == 1)) || ((asoc == NULL) && (inp->nrsack_supported == 1))) { pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; @@ -6575,7 +6663,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb, return; } } /* if chunk was present */ - } /* if of sufficent priority */ + } /* if of sufficient priority */ } /* if chunk has enabled */ } /* tailqforeach */ @@ -6616,11 +6704,15 @@ sctp_get_frag_point(struct sctp_tcb *stcb, * we use a larger frag point. */ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MED_OVERHEAD; + ovh = SCTP_MIN_OVERHEAD; } else { - ovh = SCTP_MED_V4_OVERHEAD; + ovh = SCTP_MIN_V4_OVERHEAD; + } + if (stcb->asoc.idata_supported) { + ovh += sizeof(struct sctp_idata_chunk); + } else { + ovh += sizeof(struct sctp_data_chunk); } - if (stcb->asoc.sctp_frag_point > asoc->smallest_mtu) siz = asoc->smallest_mtu - ovh; else @@ -6748,6 +6840,7 @@ sctp_msg_append(struct sctp_tcb *stcb, sp->timetolive = srcv->sinfo_timetolive; sp->ppid = srcv->sinfo_ppid; sp->context = srcv->sinfo_context; + sp->fsn = 0; if (sp->sinfo_flags & SCTP_ADDR_OVER) { sp->net = net; atomic_add_int(&sp->net->ref_count, 1); @@ -6863,10 +6956,10 @@ sctp_copy_mbufchain(struct mbuf *clonechain, } } /* get the new end of length */ - len = M_TRAILINGSPACE(*endofchain); + len = (int)M_TRAILINGSPACE(*endofchain); } else { /* how much is left at the end? */ - len = M_TRAILINGSPACE(*endofchain); + len = (int)M_TRAILINGSPACE(*endofchain); } /* Find the end of the data, for appending */ cp = (mtod((*endofchain), caddr_t) + SCTP_BUF_LEN((*endofchain))); @@ -6928,7 +7021,7 @@ sctp_copy_mbufchain(struct mbuf *clonechain, } /* * save off the end and update the end-chain - * postion + * position */ m = appendchain; while (m) { @@ -6940,7 +7033,7 @@ sctp_copy_mbufchain(struct mbuf *clonechain, } return (outchain); } else { - /* save off the end and update the end-chain postion */ + /* save off the end and update the end-chain position */ m = appendchain; while (m) { if (SCTP_BUF_NEXT(m) == NULL) { @@ -7021,7 +7114,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, ph = mtod(m, struct sctp_paramhdr *); ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); - ph->param_length = htons(sizeof(struct sctp_paramhdr) + ca->sndlen); + ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + ca->sndlen)); } /* We add one here to keep the assoc from * dis-appearing on us. @@ -7050,13 +7143,10 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, asoc = &stcb->asoc; if (ca->sndrcv.sinfo_flags & SCTP_EOF) { /* shutdown this assoc */ - int cnt; - cnt = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED); - if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && - (cnt == 0)) { - if (asoc->locked_on_sending) { + sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED) == 0) { + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { goto abort_anyway; } /* there is nothing queued to send, so I'm done... */ @@ -7092,14 +7182,8 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { - if (asoc->locked_on_sending) { - /* Locked to send out the data */ - struct sctp_stream_queue_pending *sp; - sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); - if (sp) { - if ((sp->length == 0) && (sp->msg_is_complete == 0)) - asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; - } + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { + asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; } asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; if (TAILQ_EMPTY(&asoc->send_queue) && @@ -7162,7 +7246,7 @@ sctp_sendall_completes(void *ptr, uint32_t val SCTP_UNUSED) /* * Do a notify here? Kacheong suggests that the notify be done at * the send time.. so you would push up a notification if any send - * failed. Don't know if this is feasable since the only failures we + * failed. Don't know if this is feasible since the only failures we * have is "memory" related and if you cannot get an mbuf to send * the data you surely can't get an mbuf to send up to notify the * user you can't send the data :-> @@ -7187,7 +7271,7 @@ sctp_copy_out_all(struct uio *uio, int len) left = len; SCTP_BUF_LEN(ret) = 0; /* save space for the data chunk header */ - cancpy = M_TRAILINGSPACE(ret); + cancpy = (int)M_TRAILINGSPACE(ret); willcpy = min(cancpy, left); at = ret; while (left > 0) { @@ -7208,7 +7292,7 @@ sctp_copy_out_all(struct uio *uio, int len) } at = SCTP_BUF_NEXT(at); SCTP_BUF_LEN(at) = 0; - cancpy = M_TRAILINGSPACE(at); + cancpy = (int)M_TRAILINGSPACE(at); willcpy = min(cancpy, left); } } @@ -7249,7 +7333,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, ca->sndlen = uio_resid(uio); #endif #else - ca->sndlen = uio->uio_resid; + ca->sndlen = (int)uio->uio_resid; #endif #if defined(__APPLE__) SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 0); @@ -7406,7 +7490,7 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb, sctp_misc_ints(SCTP_FLIGHT_LOG_UP, data_list[i]->whoTo->flight_size, data_list[i]->book_size, - (uintptr_t)data_list[i]->whoTo, + (uint32_t)(uintptr_t)data_list[i]->whoTo, data_list[i]->rec.data.TSN_seq); } sctp_flight_size_increase(data_list[i]); @@ -7535,7 +7619,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_stream_out *strq, uint32_t goal_mtu, uint32_t frag_point, - int *locked, int *giveup, int eeor_mode, int *bail, @@ -7549,8 +7632,10 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_association *asoc; struct sctp_stream_queue_pending *sp; struct sctp_tmit_chunk *chk; - struct sctp_data_chunk *dchkh; + struct sctp_data_chunk *dchkh=NULL; + struct sctp_idata_chunk *ndchkh=NULL; uint32_t to_move, length; + int leading; uint8_t rcv_flags = 0; uint8_t some_taken; uint8_t send_lock_up = 0; @@ -7561,7 +7646,6 @@ one_more_time: /*sa_ignore FREED_MEMORY*/ sp = TAILQ_FIRST(&strq->outqueue); if (sp == NULL) { - *locked = 0; if (send_lock_up == 0) { SCTP_TCB_SEND_LOCK(stcb); send_lock_up = 1; @@ -7570,7 +7654,9 @@ one_more_time: if (sp) { goto one_more_time; } - if (strq->last_msg_incomplete) { + if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_EXPLICIT_EOR) == 0) && + (stcb->asoc.idata_supported == 0) && + (strq->last_msg_incomplete)) { SCTP_PRINTF("Huh? Stream:%d lm_in_c=%d but queue is NULL\n", strq->stream_no, strq->last_msg_incomplete); @@ -7604,12 +7690,12 @@ one_more_time: } atomic_subtract_int(&asoc->stream_queue_cnt, 1); TAILQ_REMOVE(&strq->outqueue, sp, next); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up); if ((strq->state == SCTP_STREAM_RESET_PENDING) && (strq->chunks_on_queues == 0) && TAILQ_EMPTY(&strq->outqueue)) { stcb->asoc.trigger_reset = 1; } - stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up); if (sp->net) { sctp_free_remote_addr(sp->net); sp->net = NULL; @@ -7620,8 +7706,6 @@ one_more_time: } sctp_free_a_strmoq(stcb, sp, so_locked); /* we can't be locked to it */ - *locked = 0; - stcb->asoc.locked_on_sending = NULL; if (send_lock_up) { SCTP_TCB_SEND_UNLOCK(stcb); send_lock_up = 0; @@ -7632,7 +7716,6 @@ one_more_time: /* sender just finished this but * still holds a reference */ - *locked = 1; *giveup = 1; to_move = 0; goto out_of; @@ -7641,7 +7724,6 @@ one_more_time: /* is there some to get */ if (sp->length == 0) { /* no */ - *locked = 1; *giveup = 1; to_move = 0; goto out_of; @@ -7652,7 +7734,7 @@ one_more_time: } /* Whack down the size */ atomic_subtract_int(&stcb->asoc.total_output_queue_size, sp->length); - if ((stcb->sctp_socket != NULL) && \ + if ((stcb->sctp_socket != NULL) && ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_cc, sp->length); @@ -7664,16 +7746,12 @@ one_more_time: } sp->length = 0; sp->some_taken = 1; - *locked = 1; *giveup = 1; to_move = 0; goto out_of; } } some_taken = sp->some_taken; - if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { - sp->msg_is_complete = 1; - } re_look: length = sp->length; if (sp->msg_is_complete) { @@ -7683,10 +7761,12 @@ re_look: /* All of it fits in the MTU */ if (sp->some_taken) { rcv_flags |= SCTP_DATA_LAST_FRAG; - sp->put_last_out = 1; } else { rcv_flags |= SCTP_DATA_NOT_FRAG; - sp->put_last_out = 1; + } + sp->put_last_out = 1; + if (sp->sinfo_flags & SCTP_SACK_IMMEDIATELY) { + rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY; } } else { /* Not all of it fits, we fragment */ @@ -7726,9 +7806,6 @@ re_look: } } else { /* Nothing to take. */ - if (sp->some_taken) { - *locked = 1; - } *giveup = 1; to_move = 0; goto out_of; @@ -7749,8 +7826,8 @@ re_look: if (sp->sinfo_flags & SCTP_UNORDERED) { rcv_flags |= SCTP_DATA_UNORDERED; } - if ((SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) && ((sp->sinfo_flags & SCTP_EOF) == SCTP_EOF)) || - ((sp->sinfo_flags & SCTP_SACK_IMMEDIATELY) == SCTP_SACK_IMMEDIATELY)) { + if (SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) && + (sp->sinfo_flags & SCTP_EOF) == SCTP_EOF) { rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY; } /* clear out the chunk before setting up */ @@ -7819,7 +7896,7 @@ re_look: } else { chk->copy_by_ref = 0; } - /* get last_mbuf and counts of mb useage + /* get last_mbuf and counts of mb usage * This is ugly but hopefully its only one mbuf. */ if (chk->last_mbuf == NULL) { @@ -7843,7 +7920,12 @@ re_look: } else { atomic_subtract_int(&sp->length, to_move); } - if (M_LEADINGSPACE(chk->data) < (int)sizeof(struct sctp_data_chunk)) { + if (stcb->asoc.idata_supported == 0) { + leading = sizeof(struct sctp_data_chunk); + } else { + leading = sizeof(struct sctp_idata_chunk); + } + if (M_LEADINGSPACE(chk->data) < leading) { /* Not enough room for a chunk header, get some */ struct mbuf *m; @@ -7883,7 +7965,11 @@ re_look: M_ALIGN(chk->data, 4); } } - SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_NOWAIT); + if (stcb->asoc.idata_supported == 0) { + SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_NOWAIT); + } else { + SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_idata_chunk), M_NOWAIT); + } if (chk->data == NULL) { /* HELP, TSNH since we assured it would not above? */ #ifdef INVARIANTS @@ -7896,8 +7982,13 @@ re_look: to_move = 0; goto out_of; } - sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk)); - chk->book_size = chk->send_size = (to_move + sizeof(struct sctp_data_chunk)); + if (stcb->asoc.idata_supported == 0) { + sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk)); + chk->book_size = chk->send_size = (uint16_t)(to_move + sizeof(struct sctp_data_chunk)); + } else { + sctp_snd_sb_alloc(stcb, sizeof(struct sctp_idata_chunk)); + chk->book_size = chk->send_size = (uint16_t)(to_move + sizeof(struct sctp_idata_chunk)); + } chk->book_size_scale = 0; chk->sent = SCTP_DATAGRAM_UNSENT; @@ -7905,10 +7996,28 @@ re_look: chk->asoc = &stcb->asoc; chk->pad_inplace = 0; chk->no_fr_allowed = 0; - chk->rec.data.stream_seq = strq->next_sequence_send; - if ((rcv_flags & SCTP_DATA_LAST_FRAG) && - !(rcv_flags & SCTP_DATA_UNORDERED)) { - strq->next_sequence_send++; + if (stcb->asoc.idata_supported == 0) { + if (rcv_flags & SCTP_DATA_UNORDERED) { + /* Just use 0. The receiver ignores the values. */ + chk->rec.data.stream_seq = 0; + } else { + chk->rec.data.stream_seq = strq->next_mid_ordered; + if (rcv_flags & SCTP_DATA_LAST_FRAG) { + strq->next_mid_ordered++; + } + } + } else { + if (rcv_flags & SCTP_DATA_UNORDERED) { + chk->rec.data.stream_seq = strq->next_mid_unordered; + if (rcv_flags & SCTP_DATA_LAST_FRAG) { + strq->next_mid_unordered++; + } + } else { + chk->rec.data.stream_seq = strq->next_mid_ordered; + if (rcv_flags & SCTP_DATA_LAST_FRAG) { + strq->next_mid_ordered++; + } + } } chk->rec.data.stream_number = sp->stream; chk->rec.data.payloadtype = sp->ppid; @@ -7936,11 +8045,15 @@ re_look: #endif if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_AT_SEND_2_OUTQ) { sctp_misc_ints(SCTP_STRMOUT_LOG_SEND, - (uintptr_t)stcb, sp->length, + (uint32_t)(uintptr_t)stcb, sp->length, (uint32_t)((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq), chk->rec.data.TSN_seq); } - dchkh = mtod(chk->data, struct sctp_data_chunk *); + if (stcb->asoc.idata_supported == 0) { + dchkh = mtod(chk->data, struct sctp_data_chunk *); + } else { + ndchkh = mtod(chk->data, struct sctp_idata_chunk *); + } /* * Put the rest of the things in place now. Size was done * earlier in previous loop prior to padding. @@ -7962,14 +8075,28 @@ re_look: asoc->out_tsnlog[asoc->tsn_out_at].in_out = 2; asoc->tsn_out_at++; #endif - - dchkh->ch.chunk_type = SCTP_DATA; - dchkh->ch.chunk_flags = chk->rec.data.rcv_flags; - dchkh->dp.tsn = htonl(chk->rec.data.TSN_seq); - dchkh->dp.stream_id = htons(strq->stream_no); - dchkh->dp.stream_sequence = htons(chk->rec.data.stream_seq); - dchkh->dp.protocol_id = chk->rec.data.payloadtype; - dchkh->ch.chunk_length = htons(chk->send_size); + if (stcb->asoc.idata_supported == 0) { + dchkh->ch.chunk_type = SCTP_DATA; + dchkh->ch.chunk_flags = chk->rec.data.rcv_flags; + dchkh->dp.tsn = htonl(chk->rec.data.TSN_seq); + dchkh->dp.stream_id = htons((strq->stream_no & 0x0000ffff)); + dchkh->dp.stream_sequence = htons((uint16_t)chk->rec.data.stream_seq); + dchkh->dp.protocol_id = chk->rec.data.payloadtype; + dchkh->ch.chunk_length = htons(chk->send_size); + } else { + ndchkh->ch.chunk_type = SCTP_IDATA; + ndchkh->ch.chunk_flags = chk->rec.data.rcv_flags; + ndchkh->dp.tsn = htonl(chk->rec.data.TSN_seq); + ndchkh->dp.stream_id = htons(strq->stream_no); + ndchkh->dp.reserved = htons(0); + ndchkh->dp.msg_id = htonl(chk->rec.data.stream_seq); + if (sp->fsn == 0) + ndchkh->dp.ppid_fsn.protocol_id = chk->rec.data.payloadtype; + else + ndchkh->dp.ppid_fsn.fsn = htonl(sp->fsn); + sp->fsn++; + ndchkh->ch.chunk_length = htons(chk->send_size); + } /* Now advance the chk->send_size by the actual pad needed. */ if (chk->send_size < SCTP_SIZE32(chk->book_size)) { /* need a pad */ @@ -7989,7 +8116,6 @@ re_look: } if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) { /* All done pull and kill the message */ - atomic_subtract_int(&asoc->stream_queue_cnt, 1); if (sp->put_last_out == 0) { SCTP_PRINTF("Gak, put out entire msg with NO end!-2\n"); SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n", @@ -8003,13 +8129,14 @@ re_look: SCTP_TCB_SEND_LOCK(stcb); send_lock_up = 1; } + atomic_subtract_int(&asoc->stream_queue_cnt, 1); TAILQ_REMOVE(&strq->outqueue, sp, next); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up); if ((strq->state == SCTP_STREAM_RESET_PENDING) && (strq->chunks_on_queues == 0) && TAILQ_EMPTY(&strq->outqueue)) { stcb->asoc.trigger_reset = 1; } - stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up); if (sp->net) { sctp_free_remote_addr(sp->net); sp->net = NULL; @@ -8019,13 +8146,6 @@ re_look: sp->data = NULL; } sctp_free_a_strmoq(stcb, sp, so_locked); - - /* we can't be locked to it */ - *locked = 0; - stcb->asoc.locked_on_sending = NULL; - } else { - /* more to go, we are locked */ - *locked = 1; } asoc->chunks_on_out_queue++; strq->chunks_on_queues++; @@ -8050,7 +8170,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb, struct sctp_association *asoc; struct sctp_stream_out *strq; int goal_mtu, moved_how_much, total_moved = 0, bail = 0; - int locked, giveup; + int giveup; SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; @@ -8076,40 +8196,28 @@ sctp_fill_outqueue(struct sctp_tcb *stcb, break; } /* Need an allowance for the data chunk header too */ - goal_mtu -= sizeof(struct sctp_data_chunk); + if (stcb->asoc.idata_supported == 0) { + goal_mtu -= sizeof(struct sctp_data_chunk); + } else { + goal_mtu -= sizeof(struct sctp_idata_chunk); + } /* must make even word boundary */ goal_mtu &= 0xfffffffc; - if (asoc->locked_on_sending) { - /* We are stuck on one stream until the message completes. */ - strq = asoc->locked_on_sending; - locked = 1; - } else { - strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc); - locked = 0; - } + strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc); while ((goal_mtu > 0) && strq) { giveup = 0; bail = 0; - moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point, &locked, + moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point, &giveup, eeor_mode, &bail, so_locked); - if (moved_how_much) - stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved_how_much); + stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved_how_much); - if (locked) { - asoc->locked_on_sending = strq; - if ((moved_how_much == 0) || (giveup) || bail) - /* no more to move for now */ - break; - } else { - asoc->locked_on_sending = NULL; - if ((giveup) || bail) { - break; - } - strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc); - if (strq == NULL) { - break; - } + if ((giveup) || bail) { + break; + } + strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc); + if (strq == NULL) { + break; } total_moved += moved_how_much; goal_mtu -= (moved_how_much + sizeof(struct sctp_data_chunk)); @@ -8187,12 +8295,15 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, { /** * Ok this is the generic chunk service queue. we must do the - * following: - Service the stream queue that is next, moving any - * message (note I must get a complete message i.e. FIRST/MIDDLE and - * LAST to the out queue in one pass) and assigning TSN's - Check to - * see if the cwnd/rwnd allows any output, if so we go ahead and - * fomulate and send the low level chunks. Making sure to combine - * any control in the control chunk queue also. + * following: + * - Service the stream queue that is next, moving any + * message (note I must get a complete message i.e. FIRST/MIDDLE and + * LAST to the out queue in one pass) and assigning TSN's. This + * only applys though if the peer does not support NDATA. For NDATA + * chunks its ok to not send the entire message ;-) + * - Check to see if the cwnd/rwnd allows any output, if so we go ahead and + * fomulate and send the low level chunks. Making sure to combine + * any control in the control chunk queue also. */ struct sctp_nets *net, *start_at, *sack_goes_to = NULL, *old_start_at = NULL; struct mbuf *outchain, *endoutchain; @@ -8255,7 +8366,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, (asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) && TAILQ_EMPTY(&asoc->asconf_send_queue) && TAILQ_EMPTY(&asoc->send_queue) && - stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { + sctp_is_there_unsent_data(stcb, so_locked) == 0) { nothing_to_send: *reason_code = 9; return (0); @@ -9341,6 +9452,8 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) chk->asoc = &stcb->asoc; chk->data = op_err; chk->whoTo = NULL; + chk->rec.chunk_id.id = SCTP_OPERATION_ERROR; + chk->rec.chunk_id.can_take_data = 0; hdr = mtod(op_err, struct sctp_chunkhdr *); hdr->chunk_type = SCTP_OPERATION_ERROR; hdr->chunk_flags = 0; @@ -9873,7 +9986,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, cnt_thru = 0; /* do we have control chunks to retransmit? */ if (m != NULL) { - /* Start a timer no matter if we suceed or fail */ + /* Start a timer no matter if we succeed or fail */ if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) { sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo); } else if (chk->rec.chunk_id.id == SCTP_ASCONF) @@ -10142,7 +10255,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, /* Is there something to send for this destination? */ if (m) { /* - * No matter if we fail/or suceed we should start a + * No matter if we fail/or succeed we should start a * timer. A failure is like a lost IP packet :-) */ if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { @@ -10240,7 +10353,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, sctp_misc_ints(SCTP_FLIGHT_LOG_UP_RSND, data_list[i]->whoTo->flight_size, data_list[i]->book_size, - (uintptr_t)data_list[i]->whoTo, + (uint32_t)(uintptr_t)data_list[i]->whoTo, data_list[i]->rec.data.TSN_seq); } sctp_flight_size_increase(data_list[i]); @@ -10547,15 +10660,14 @@ do_it_again: un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); if ((un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) && - (stcb->asoc.total_flight > 0) && - ((stcb->asoc.locked_on_sending == NULL) || - sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) { + (stcb->asoc.total_flight > 0)) { +/* && sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/ break; } } if (TAILQ_EMPTY(&asoc->control_send_queue) && TAILQ_EMPTY(&asoc->send_queue) && - stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { + sctp_is_there_unsent_data(stcb, so_locked) == 0) { /* Nothing left to send */ break; } @@ -10655,11 +10767,22 @@ void send_forward_tsn(struct sctp_tcb *stcb, struct sctp_association *asoc) { - struct sctp_tmit_chunk *chk; + struct sctp_tmit_chunk *chk, *at, *tp1, *last; struct sctp_forward_tsn_chunk *fwdtsn; + struct sctp_strseq *strseq; + struct sctp_strseq_mid *strseq_m; uint32_t advance_peer_ack_point; + unsigned int cnt_of_space, i, ovh; + unsigned int space_needed; + unsigned int cnt_of_skipped = 0; + int old; - SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->idata_supported) { + old = 0; + } else { + old = 1; + } + SCTP_TCB_LOCK_ASSERT(stcb); TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) { /* mark it to unsent */ @@ -10680,6 +10803,13 @@ send_forward_tsn(struct sctp_tcb *stcb, } asoc->fwd_tsn_cnt++; chk->copy_by_ref = 0; + /* + * We don't do the old thing here since + * this is used not for on-wire but to + * tell if we are sending a fwd-tsn by + * the stack during output. And if its + * a IFORWARD or a FORWARD it is a fwd-tsn. + */ chk->rec.chunk_id.id = SCTP_FORWARD_CUM_TSN; chk->rec.chunk_id.can_take_data = 0; chk->flags = 0; @@ -10701,132 +10831,155 @@ sctp_fill_in_rest: * stream/seq of the ones we skip. */ SCTP_BUF_LEN(chk->data) = 0; - { - struct sctp_tmit_chunk *at, *tp1, *last; - struct sctp_strseq *strseq; - unsigned int cnt_of_space, i, ovh; - unsigned int space_needed; - unsigned int cnt_of_skipped = 0; - - TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) { - if ((at->sent != SCTP_FORWARD_TSN_SKIP) && - (at->sent != SCTP_DATAGRAM_NR_ACKED)) { - /* no more to look at */ - break; - } - if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { - /* We don't report these */ - continue; - } - cnt_of_skipped++; + TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) { + if ((at->sent != SCTP_FORWARD_TSN_SKIP) && + (at->sent != SCTP_DATAGRAM_NR_ACKED)) { + /* no more to look at */ + break; } + if (old && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) { + /* We don't report these */ + continue; + } + cnt_of_skipped++; + } + if (old) { space_needed = (sizeof(struct sctp_forward_tsn_chunk) + - (cnt_of_skipped * sizeof(struct sctp_strseq))); - - cnt_of_space = M_TRAILINGSPACE(chk->data); + (cnt_of_skipped * sizeof(struct sctp_strseq))); + } else { + space_needed = (sizeof(struct sctp_forward_tsn_chunk) + + (cnt_of_skipped * sizeof(struct sctp_strseq_mid))); + } + cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data); - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MIN_OVERHEAD; - } else { - ovh = SCTP_MIN_V4_OVERHEAD; - } - if (cnt_of_space > (asoc->smallest_mtu - ovh)) { - /* trim to a mtu size */ - cnt_of_space = asoc->smallest_mtu - ovh; - } + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { + ovh = SCTP_MIN_OVERHEAD; + } else { + ovh = SCTP_MIN_V4_OVERHEAD; + } + if (cnt_of_space > (asoc->smallest_mtu - ovh)) { + /* trim to a mtu size */ + cnt_of_space = asoc->smallest_mtu - ovh; + } + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { + sctp_misc_ints(SCTP_FWD_TSN_CHECK, + 0xff, 0, cnt_of_skipped, + asoc->advanced_peer_ack_point); + } + advance_peer_ack_point = asoc->advanced_peer_ack_point; + if (cnt_of_space < space_needed) { + /*- + * ok we must trim down the chunk by lowering the + * advance peer ack point. + */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { sctp_misc_ints(SCTP_FWD_TSN_CHECK, - 0xff, 0, cnt_of_skipped, - asoc->advanced_peer_ack_point); - + 0xff, 0xff, cnt_of_space, + space_needed); } - advance_peer_ack_point = asoc->advanced_peer_ack_point; - if (cnt_of_space < space_needed) { - /*- - * ok we must trim down the chunk by lowering the - * advance peer ack point. - */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { - sctp_misc_ints(SCTP_FWD_TSN_CHECK, - 0xff, 0xff, cnt_of_space, - space_needed); - } + if (old) { cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk); cnt_of_skipped /= sizeof(struct sctp_strseq); - /*- - * Go through and find the TSN that will be the one - * we report. - */ - at = TAILQ_FIRST(&asoc->sent_queue); - if (at != NULL) { - for (i = 0; i < cnt_of_skipped; i++) { - tp1 = TAILQ_NEXT(at, sctp_next); - if (tp1 == NULL) { - break; - } - at = tp1; + } else { + cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk); + cnt_of_skipped /= sizeof(struct sctp_strseq_mid); + } + /*- + * Go through and find the TSN that will be the one + * we report. + */ + at = TAILQ_FIRST(&asoc->sent_queue); + if (at != NULL) { + for (i = 0; i < cnt_of_skipped; i++) { + tp1 = TAILQ_NEXT(at, sctp_next); + if (tp1 == NULL) { + break; } + at = tp1; } - if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { - sctp_misc_ints(SCTP_FWD_TSN_CHECK, - 0xff, cnt_of_skipped, at->rec.data.TSN_seq, - asoc->advanced_peer_ack_point); - } - last = at; - /*- - * last now points to last one I can report, update - * peer ack point - */ - if (last) - advance_peer_ack_point = last->rec.data.TSN_seq; + } + if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { + sctp_misc_ints(SCTP_FWD_TSN_CHECK, + 0xff, cnt_of_skipped, at->rec.data.TSN_seq, + asoc->advanced_peer_ack_point); + } + last = at; + /*- + * last now points to last one I can report, update + * peer ack point + */ + if (last) { + advance_peer_ack_point = last->rec.data.TSN_seq; + } + if (old) { space_needed = sizeof(struct sctp_forward_tsn_chunk) + cnt_of_skipped * sizeof(struct sctp_strseq); + } else { + space_needed = sizeof(struct sctp_forward_tsn_chunk) + + cnt_of_skipped * sizeof(struct sctp_strseq_mid); } - chk->send_size = space_needed; - /* Setup the chunk */ - fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *); - fwdtsn->ch.chunk_length = htons(chk->send_size); - fwdtsn->ch.chunk_flags = 0; + } + chk->send_size = space_needed; + /* Setup the chunk */ + fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *); + fwdtsn->ch.chunk_length = htons(chk->send_size); + fwdtsn->ch.chunk_flags = 0; + if (old) { fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN; - fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point); - SCTP_BUF_LEN(chk->data) = chk->send_size; - fwdtsn++; - /*- - * Move pointer to after the fwdtsn and transfer to the - * strseq pointer. - */ + } else { + fwdtsn->ch.chunk_type = SCTP_IFORWARD_CUM_TSN; + } + fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point); + SCTP_BUF_LEN(chk->data) = chk->send_size; + fwdtsn++; + /*- + * Move pointer to after the fwdtsn and transfer to the + * strseq pointer. + */ + if (old) { strseq = (struct sctp_strseq *)fwdtsn; - /*- - * Now populate the strseq list. This is done blindly - * without pulling out duplicate stream info. This is - * inefficent but won't harm the process since the peer will - * look at these in sequence and will thus release anything. - * It could mean we exceed the PMTU and chop off some that - * we could have included.. but this is unlikely (aka 1432/4 - * would mean 300+ stream seq's would have to be reported in - * one FWD-TSN. With a bit of work we can later FIX this to - * optimize and pull out duplcates.. but it does add more - * overhead. So for now... not! - */ - at = TAILQ_FIRST(&asoc->sent_queue); - for (i = 0; i < cnt_of_skipped; i++) { - tp1 = TAILQ_NEXT(at, sctp_next); - if (tp1 == NULL) - break; + } else { + strseq_m = (struct sctp_strseq_mid *)fwdtsn; + } + /*- + * Now populate the strseq list. This is done blindly + * without pulling out duplicate stream info. This is + * inefficent but won't harm the process since the peer will + * look at these in sequence and will thus release anything. + * It could mean we exceed the PMTU and chop off some that + * we could have included.. but this is unlikely (aka 1432/4 + * would mean 300+ stream seq's would have to be reported in + * one FWD-TSN. With a bit of work we can later FIX this to + * optimize and pull out duplicates.. but it does add more + * overhead. So for now... not! + */ + i = 0; + TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) { + if (i >= cnt_of_skipped) { + break; + } + if (old && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) { + /* We don't report these */ + continue; + } + if (at->rec.data.TSN_seq == advance_peer_ack_point) { + at->rec.data.fwd_tsn_cnt = 0; + } + if (old) { + strseq->stream = htons(at->rec.data.stream_number); + strseq->sequence = htons((uint16_t)at->rec.data.stream_seq); + strseq++; + } else { + strseq_m->stream = htons(at->rec.data.stream_number); if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { - /* We don't report these */ - i--; - at = tp1; - continue; - } - if (at->rec.data.TSN_seq == advance_peer_ack_point) { - at->rec.data.fwd_tsn_cnt = 0; + strseq_m->flags = htons(PR_SCTP_UNORDERED_FLAG); + } else { + strseq_m->flags = 0; } - strseq->stream = ntohs(at->rec.data.stream_number); - strseq->sequence = ntohs(at->rec.data.stream_seq); - strseq++; - at = tp1; + strseq_m->msg_id = htonl(at->rec.data.stream_seq); + strseq_m++; } + i++; } return; } @@ -10849,7 +11002,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked struct sctp_sack_chunk *sack; struct sctp_nr_sack_chunk *nr_sack; struct sctp_gap_ack_block *gap_descriptor; - struct sack_track *selector; + const struct sack_track *selector; int mergeable = 0; int offset; caddr_t limit; @@ -10981,7 +11134,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked } /* ok, lets go through and fill it in */ SCTP_BUF_RESV_UF(a_chk->data, SCTP_MIN_OVERHEAD); - space = M_TRAILINGSPACE(a_chk->data); + space = (unsigned int)M_TRAILINGSPACE(a_chk->data); if (space > (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD)) { space = (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD); } @@ -11050,7 +11203,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked * Clear all bits corresponding to TSNs * smaller or equal to the cumulative TSN. */ - tsn_map &= (~0 << (1 - offset)); + tsn_map &= (~0U << (1 - offset)); } selector = &sack_array[tsn_map]; if (mergeable && selector->right_edge) { @@ -11124,7 +11277,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked * Clear all bits corresponding to TSNs * smaller or equal to the cumulative TSN. */ - tsn_map &= (~0 << (1 - offset)); + tsn_map &= (~0U << (1 - offset)); } selector = &sack_array[tsn_map]; if (mergeable && selector->right_edge) { @@ -11193,9 +11346,9 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked * queue. */ if (type == SCTP_SELECTIVE_ACK) { - a_chk->send_size = sizeof(struct sctp_sack_chunk) + - (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) + - num_dups * sizeof(int32_t); + a_chk->send_size = (uint16_t)(sizeof(struct sctp_sack_chunk) + + (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) + + num_dups * sizeof(int32_t)); SCTP_BUF_LEN(a_chk->data) = a_chk->send_size; sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn); sack->sack.a_rwnd = htonl(asoc->my_rwnd); @@ -11205,9 +11358,9 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked sack->ch.chunk_flags = flags; sack->ch.chunk_length = htons(a_chk->send_size); } else { - a_chk->send_size = sizeof(struct sctp_nr_sack_chunk) + - (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) + - num_dups * sizeof(int32_t); + a_chk->send_size = (uint16_t)(sizeof(struct sctp_nr_sack_chunk) + + (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) + + num_dups * sizeof(int32_t)); SCTP_BUF_LEN(a_chk->data) = a_chk->send_size; nr_sack->nr_sack.cum_tsn_ack = htonl(asoc->cumulative_tsn); nr_sack->nr_sack.a_rwnd = htonl(asoc->my_rwnd); @@ -11513,7 +11666,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, ip->ip_id = htons(ip_id++); #endif #elif defined(__Userspace__) - ip->ip_id = htons(ip_id++); + ip->ip_id = htons(ip_id++); #else ip->ip_id = ip_id++; #endif @@ -11572,10 +11725,10 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); udp->uh_dport = port; udp->uh_sum = 0; - udp->uh_ulen = htons(sizeof(struct udphdr) + - sizeof(struct sctphdr) + - sizeof(struct sctp_chunkhdr) + - cause_len + padding_len); + udp->uh_ulen = htons((uint16_t)(sizeof(struct udphdr) + + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr) + + cause_len + padding_len)); len += sizeof(struct udphdr); shout = (struct sctphdr *)((caddr_t)shout + sizeof(struct udphdr)); } else { @@ -11598,7 +11751,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, } else { ch->chunk_flags = SCTP_HAD_NO_TCB; } - ch->chunk_length = htons(sizeof(struct sctp_chunkhdr) + cause_len); + ch->chunk_length = htons((uint16_t)(sizeof(struct sctp_chunkhdr) + cause_len)); len += sizeof(struct sctp_chunkhdr); len += cause_len + padding_len; @@ -11692,7 +11845,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, #endif #ifdef INET6 case AF_INET6: - ip6->ip6_plen = len - sizeof(struct ip6_hdr); + ip6->ip6_plen = (uint16_t)(len - sizeof(struct ip6_hdr)); if (port) { #if defined(SCTP_WITH_NO_CSUM) SCTP_STAT_INCR(sctps_sendnocrc); @@ -12097,7 +12250,7 @@ jump_out: /* Len is already adjusted to size minus overhead above * take out the pkt_drop chunk itself from it. */ - chk->send_size = len - sizeof(struct sctp_pktdrop_chunk); + chk->send_size = (uint16_t)(len - sizeof(struct sctp_pktdrop_chunk)); len = chk->send_size; } else { /* no truncation needed */ @@ -12233,7 +12386,7 @@ sctp_add_stream_reset_out(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk, if (number_entries > SCTP_MAX_STREAMS_AT_ONCE_RESET) { number_entries = SCTP_MAX_STREAMS_AT_ONCE_RESET; } - len = (sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries)); + len = (uint16_t)(sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries)); req_out->ph.param_type = htons(SCTP_STR_RESET_OUT_REQUEST); req_out->ph.param_length = htons(len); req_out->request_seq = htonl(seq); @@ -12290,7 +12443,7 @@ sctp_add_stream_reset_in(struct sctp_tmit_chunk *chk, /* get to new offset for the param. */ req_in = (struct sctp_stream_reset_in_request *)((caddr_t)ch + len); /* now how long will this param be? */ - len = (sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries)); + len = (uint16_t)(sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries)); req_in->ph.param_type = htons(SCTP_STR_RESET_IN_REQUEST); req_in->ph.param_length = htons(len); req_in->request_seq = htonl(seq); @@ -12413,7 +12566,6 @@ sctp_send_deferred_reset_response(struct sctp_tcb *stcb, return; } SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); - sctp_add_stream_reset_result(chk, ent->seq, response); /* setup chunk parameters */ chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; @@ -12428,6 +12580,7 @@ sctp_send_deferred_reset_response(struct sctp_tcb *stcb, ch->chunk_length = htons(chk->book_size); atomic_add_int(&chk->whoTo->ref_count, 1); SCTP_BUF_LEN(chk->data) = chk->send_size; + sctp_add_stream_reset_result(chk, ent->seq, response); /* insert the chunk for sending */ TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, @@ -12725,23 +12878,20 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, for (i = 0; i < stcb->asoc.streamoutcnt; i++) { TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); stcb->asoc.strmout[i].chunks_on_queues = oldstream[i].chunks_on_queues; - stcb->asoc.strmout[i].next_sequence_send = oldstream[i].next_sequence_send; + stcb->asoc.strmout[i].next_mid_ordered = oldstream[i].next_mid_ordered; + stcb->asoc.strmout[i].next_mid_unordered = oldstream[i].next_mid_unordered; stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete; stcb->asoc.strmout[i].stream_no = i; stcb->asoc.strmout[i].state = oldstream[i].state; - stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]); + /* FIX ME FIX ME */ + /* This should be a SS_COPY operation FIX ME STREAM SCHEDULER EXPERT */ + stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], &oldstream[i]); /* now anything on those queues? */ TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) { TAILQ_REMOVE(&oldstream[i].outqueue, sp, next); TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next); } - /* Now move assoc pointers too */ - if (stcb->asoc.last_out_stream == &oldstream[i]) { - stcb->asoc.last_out_stream = &stcb->asoc.strmout[i]; - } - if (stcb->asoc.locked_on_sending == &oldstream[i]) { - stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i]; - } + } /* now the new streams */ stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); @@ -12757,10 +12907,11 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, stcb->asoc.strmout[i].abandoned_sent[0] = 0; stcb->asoc.strmout[i].abandoned_unsent[0] = 0; #endif - stcb->asoc.strmout[i].next_sequence_send = 0x0; + stcb->asoc.strmout[i].next_mid_ordered = 0; + stcb->asoc.strmout[i].next_mid_unordered = 0; stcb->asoc.strmout[i].stream_no = i; stcb->asoc.strmout[i].last_msg_incomplete = 0; - stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL); + stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); stcb->asoc.strmout[i].state = SCTP_STREAM_CLOSED; } stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o; @@ -12882,12 +13033,12 @@ sctp_copy_resume(struct uio *uio, #if defined(__APPLE__) #if defined(APPLE_LEOPARD) - left = min(uio->uio_resid, max_send_len); + left = (int)min(uio->uio_resid, max_send_len); #else - left = min(uio_resid(uio), max_send_len); + left = (int)min(uio_resid(uio), max_send_len); #endif #else - left = min(uio->uio_resid, max_send_len); + left = (int)min(uio->uio_resid, max_send_len); #endif /* Always get a header just in case */ head = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 0, MT_DATA); @@ -12896,7 +13047,7 @@ sctp_copy_resume(struct uio *uio, *error = ENOBUFS; return (NULL); } - cancpy = M_TRAILINGSPACE(head); + cancpy = (int)M_TRAILINGSPACE(head); willcpy = min(cancpy, left); *error = uiomove(mtod(head, caddr_t), willcpy, uio); if (*error) { @@ -12919,7 +13070,7 @@ sctp_copy_resume(struct uio *uio, return (NULL); } m = SCTP_BUF_NEXT(m); - cancpy = M_TRAILINGSPACE(m); + cancpy = (int)M_TRAILINGSPACE(m); willcpy = min(cancpy, left); *error = uiomove(mtod(m, caddr_t), willcpy, uio); if (*error) { @@ -12984,7 +13135,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp, * have a bad cnt. */ SCTP_BUF_RESV_UF(m, resv_upfront); - cancpy = M_TRAILINGSPACE(m); + cancpy = (int)M_TRAILINGSPACE(m); willcpy = min(cancpy, left); while (left > 0) { /* move in user data */ @@ -13008,7 +13159,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp, return (ENOBUFS); } m = SCTP_BUF_NEXT(m); - cancpy = M_TRAILINGSPACE(m); + cancpy = (int)M_TRAILINGSPACE(m); willcpy = min(cancpy, left); } else { sp->tail_mbuf = m; @@ -13067,17 +13218,18 @@ sctp_copy_it_in(struct sctp_tcb *stcb, sp->timetolive = srcv->sinfo_timetolive; sp->ppid = srcv->sinfo_ppid; sp->context = srcv->sinfo_context; + sp->fsn = 0; (void)SCTP_GETTIME_TIMEVAL(&sp->ts); sp->stream = srcv->sinfo_stream; #if defined(__APPLE__) #if defined(APPLE_LEOPARD) - sp->length = min(uio->uio_resid, max_send_len); + sp->length = (uint32_t)min(uio->uio_resid, max_send_len); #else - sp->length = min(uio_resid(uio), max_send_len); + sp->length = (uint32_t)min(uio_resid(uio), max_send_len); #endif #else - sp->length = min(uio->uio_resid, max_send_len); + sp->length = (uint32_t)min(uio->uio_resid, max_send_len); #endif #if defined(__APPLE__) #if defined(APPLE_LEOPARD) @@ -13320,12 +13472,12 @@ sctp_lower_sosend(struct socket *so, } #if defined(__APPLE__) #if defined(APPLE_LEOPARD) - sndlen = uio->uio_resid; + sndlen = (unsigned int)uio->uio_resid; #else - sndlen = uio_resid(uio); + sndlen = (unsigned int)uio_resid(uio); #endif #else - sndlen = uio->uio_resid; + sndlen = (unsigned int)uio->uio_resid; #endif } else { top = SCTP_HEADER_TO_CHAIN(i_pak); @@ -13457,7 +13609,10 @@ sctp_lower_sosend(struct socket *so, } SCTP_INP_RUNLOCK(inp); } else if (sinfo_assoc_id) { - stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 0); + stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 1); + if (stcb != NULL) { + hold_tcblock = 1; + } } else if (addr) { /*- * Since we did not use findep we must @@ -13546,12 +13701,12 @@ sctp_lower_sosend(struct socket *so, #endif stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, + inp->sctp_ep.port, #if !(defined( __Panda__) || defined(__Userspace__)) - p + p); #else - (struct proc *)NULL + (struct proc *)NULL); #endif - ); if (stcb == NULL) { /* Error is setup for us in the call */ goto out_unlocked; @@ -13781,7 +13936,7 @@ sctp_lower_sosend(struct socket *so, /* now move forward the data pointer */ ph = mtod(mm, struct sctp_paramhdr *); ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); - ph->param_length = htons(sizeof(struct sctp_paramhdr) + tot_out); + ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out)); ph++; SCTP_BUF_LEN(mm) = tot_out + sizeof(struct sctp_paramhdr); if (top == NULL) { @@ -13922,6 +14077,7 @@ sctp_lower_sosend(struct socket *so, asoc, stcb->asoc.total_output_queue_size); } if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { + SOCKBUF_UNLOCK(&so->so_snd); goto out_unlocked; } inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk)); @@ -13986,8 +14142,10 @@ skip_preblock: * case of an interrupt. */ strm->last_msg_incomplete = 1; - asoc->stream_locked = 1; - asoc->stream_locked_on = srcv->sinfo_stream; + if (stcb->asoc.idata_supported == 0) { + asoc->stream_locked = 1; + asoc->stream_locked_on = srcv->sinfo_stream; + } sp->sender_all_done = 0; } sctp_snd_sb_alloc(stcb, sp->length); @@ -14089,8 +14247,11 @@ skip_preblock: sp->tail_mbuf = new_tail; } sctp_snd_sb_alloc(stcb, sndout); - atomic_add_int(&sp->length,sndout); + atomic_add_int(&sp->length, sndout); len += sndout; + if (srcv->sinfo_flags & SCTP_SACK_IMMEDIATELY) { + sp->sinfo_flags |= SCTP_SACK_IMMEDIATELY; + } /* Did we reach EOR? */ #if defined(__APPLE__) @@ -14261,7 +14422,7 @@ skip_preblock: #endif #else sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, - asoc, uio->uio_resid); + asoc, (size_t)uio->uio_resid); #endif } be.error = 0; @@ -14300,11 +14461,17 @@ skip_preblock: } } SCTP_TCB_SEND_LOCK(stcb); + if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { + SCTP_TCB_SEND_UNLOCK(stcb); + goto out_unlocked; + } if (sp) { if (sp->msg_is_complete == 0) { strm->last_msg_incomplete = 1; - asoc->stream_locked = 1; - asoc->stream_locked_on = srcv->sinfo_stream; + if (stcb->asoc.idata_supported == 0) { + asoc->stream_locked = 1; + asoc->stream_locked_on = srcv->sinfo_stream; + } } else { sp->sender_all_done = 1; strm->last_msg_incomplete = 0; @@ -14348,18 +14515,16 @@ dataless_eof: /* EOF thing ? */ if ((srcv->sinfo_flags & SCTP_EOF) && (got_all_of_the_send == 1)) { - int cnt; SCTP_STAT_INCR(sctps_sends_with_eof); error = 0; if (hold_tcblock == 0) { SCTP_TCB_LOCK(stcb); hold_tcblock = 1; } - cnt = sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED); if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && - (cnt == 0)) { - if (asoc->locked_on_sending) { + sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED) == 0) { + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { goto abort_anyway; } /* there is nothing queued to send, so I'm done... */ @@ -14404,14 +14569,8 @@ dataless_eof: SCTP_TCB_LOCK(stcb); hold_tcblock = 1; } - if (asoc->locked_on_sending) { - /* Locked to send out the data */ - struct sctp_stream_queue_pending *sp; - sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); - if (sp) { - if ((sp->length == 0) && (sp->msg_is_complete == 0)) - asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; - } + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { + asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; } asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; if (TAILQ_EMPTY(&asoc->send_queue) && diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_output.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_output.h index f2d4248335a..dc7b68f6c87 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_output.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_output.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.h 285837 2015-07-24 14:09:03Z rrs $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_output.h 295072 2016-01-30 12:58:38Z tuexen $"); #endif #ifndef _NETINET_SCTP_OUTPUT_H_ @@ -83,7 +83,8 @@ void sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *, int ); void -sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *, struct mbuf *, +sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *, + struct sctp_nets *, struct mbuf *, int, int, struct sockaddr *, struct sockaddr *, struct sctphdr *, struct sctp_init_chunk *, diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_pcb.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_pcb.c index f623b512364..1541a0cd5c4 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_pcb.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_pcb.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 291904 2015-12-06 16:17:57Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 303813 2016-08-07 12:51:13Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -49,7 +49,7 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 291904 2015-12-06 16:17:57Z tuex #include <netinet/sctp_output.h> #include <netinet/sctp_timer.h> #include <netinet/sctp_bsd_addr.h> -#if defined(__FreeBSD__) && __FreeBSD_version >= 803000 +#if defined(__FreeBSD__) && __FreeBSD_version >= 1000000 #include <netinet/sctp_dtrace_define.h> #endif #if defined(INET) || defined(INET6) @@ -86,11 +86,6 @@ VNET_DEFINE(struct sctp_base_info, system_base_info); struct sctp_base_info system_base_info; #endif -#if defined(__Userspace__) -#if defined(INET) || defined(INET6) -struct ifaddrs *g_interfaces; -#endif -#endif /* FIX: we don't handle multiple link local scopes */ /* "scopeless" replacement IN6_ARE_ADDR_EQUAL */ #ifdef INET6 @@ -399,7 +394,7 @@ sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, goto out; } if (sctp_ifap->ifn_p == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unuseable\n"); + SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unusable\n"); goto out; } if (if_name) { @@ -443,7 +438,7 @@ sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, goto out; } if (sctp_ifap->ifn_p == NULL) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unuseable\n"); + SCTPDBG(SCTP_DEBUG_PCB4, "IFA has no IFN - can't mark unusable\n"); goto out; } if (if_name) { @@ -2608,7 +2603,6 @@ sctp_findassociation_addr(struct mbuf *m, int offset, struct sctphdr *sh, struct sctp_chunkhdr *ch, struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id) { - int find_tcp_pool; struct sctp_tcb *stcb; struct sctp_inpcb *inp; @@ -2621,21 +2615,13 @@ sctp_findassociation_addr(struct mbuf *m, int offset, } } - find_tcp_pool = 0; - if ((ch->chunk_type != SCTP_INITIATION) && - (ch->chunk_type != SCTP_INITIATION_ACK) && - (ch->chunk_type != SCTP_COOKIE_ACK) && - (ch->chunk_type != SCTP_COOKIE_ECHO)) { - /* Other chunk types go to the tcp pool. */ - find_tcp_pool = 1; - } if (inp_p) { stcb = sctp_findassociation_addr_sa(src, dst, inp_p, netp, - find_tcp_pool, vrf_id); + 1, vrf_id); inp = *inp_p; } else { stcb = sctp_findassociation_addr_sa(src, dst, &inp, netp, - find_tcp_pool, vrf_id); + 1, vrf_id); } SCTPDBG(SCTP_DEBUG_PCB1, "stcb:%p inp:%p\n", (void *)stcb, (void *)inp); if (stcb == NULL && inp) { @@ -2846,6 +2832,8 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) inp->reconfig_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_reconfig_enable); inp->nrsack_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_nrsack_enable); inp->pktdrop_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_pktdrop_enable); + inp->idata_supported = 0; + #if defined(__FreeBSD__) inp->fibnum = so->so_fibnum; #else @@ -3244,6 +3232,45 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, SCTP_INP_WUNLOCK(old_inp); } +/* + * insert an laddr entry with the given ifa for the desired list + */ +static int +sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act) +{ + struct sctp_laddr *laddr; + + laddr = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); + if (laddr == NULL) { + /* out of memory? */ + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); + return (EINVAL); + } + SCTP_INCR_LADDR_COUNT(); + bzero(laddr, sizeof(*laddr)); + (void)SCTP_GETTIME_TIMEVAL(&laddr->start_time); + laddr->ifa = ifa; + laddr->action = act; + atomic_add_int(&ifa->refcount, 1); + /* insert it */ + LIST_INSERT_HEAD(list, laddr, sctp_nxt_addr); + + return (0); +} + +/* + * Remove an laddr entry from the local address list (on an assoc) + */ +static void +sctp_remove_laddr(struct sctp_laddr *laddr) +{ + + /* remove from the list */ + LIST_REMOVE(laddr, sctp_nxt_addr); + sctp_free_ifa(laddr->ifa); + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), laddr); + SCTP_DECR_LADDR_COUNT(); +} #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)) /* @@ -4010,7 +4037,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) } else if (TAILQ_EMPTY(&asoc->asoc.send_queue) && TAILQ_EMPTY(&asoc->asoc.sent_queue) && (asoc->asoc.stream_queue_cnt == 0)) { - if (asoc->asoc.locked_on_sending) { + if ((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete)(asoc, &asoc->asoc)) { goto abort_anyway; } if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) && @@ -4042,22 +4069,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) } } else { /* mark into shutdown pending */ - struct sctp_stream_queue_pending *sp; - asoc->asoc.state |= SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc, asoc->asoc.primary_destination); - if (asoc->asoc.locked_on_sending) { - sp = TAILQ_LAST(&((asoc->asoc.locked_on_sending)->outqueue), - sctp_streamhead); - if (sp == NULL) { - SCTP_PRINTF("Error, sp is NULL, locked on sending is %p strm:%d\n", - (void *)asoc->asoc.locked_on_sending, - asoc->asoc.locked_on_sending->stream_no); - } else { - if ((sp->length == 0) && (sp->msg_is_complete == 0)) - asoc->asoc.state |= SCTP_STATE_PARTIAL_MSG_LEFT; - } + if ((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete)(asoc, &asoc->asoc)) { + asoc->asoc.state |= SCTP_STATE_PARTIAL_MSG_LEFT; } if (TAILQ_EMPTY(&asoc->asoc.send_queue) && TAILQ_EMPTY(&asoc->asoc.sent_queue) && @@ -4247,8 +4263,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * no need to free the net count, since at this point all * assoc's are gone. */ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), sq); - SCTP_DECR_READQ_COUNT(); + sctp_free_a_readq(NULL, sq); } /* Now the sctp_pcb things */ /* @@ -4404,7 +4419,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id) */ int sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, - struct sctp_nets **netp, int set_scope, int from) + struct sctp_nets **netp, uint16_t port, int set_scope, int from) { /* * The following is redundant to the same lines in the @@ -4614,7 +4629,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, stcb->asoc.numnets++; net->ref_count = 1; net->cwr_window_tsn = net->last_cwr_tsn = stcb->asoc.sending_seq - 1; - net->port = stcb->asoc.port; + net->port = port; net->dscp = stcb->asoc.default_dscp; #ifdef INET6 net->flowlabel = stcb->asoc.default_flowlabel; @@ -4734,7 +4749,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, stcb->asoc.smallest_mtu = net->mtu; } if (stcb->asoc.smallest_mtu > net->mtu) { - stcb->asoc.smallest_mtu = net->mtu; + sctp_pathmtu_adjustment(stcb, net->mtu); } #ifdef INET6 #ifdef SCTP_EMBEDDED_V6_SCOPE @@ -4766,7 +4781,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, net->flowid = stcb->asoc.my_vtag ^ ntohs(stcb->rport) ^ ntohs(stcb->sctp_ep->sctp_lport); - net->flowtype = M_HASHTYPE_OPAQUE; + net->flowtype = M_HASHTYPE_OPAQUE_HASH; #endif if (netp) { *netp = net; @@ -4898,7 +4913,7 @@ sctp_aloc_a_assoc_id(struct sctp_inpcb *inp, struct sctp_tcb *stcb) struct sctp_tcb * sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, int *error, uint32_t override_tag, uint32_t vrf_id, - uint16_t o_streams, + uint16_t o_streams, uint16_t port, #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 struct thread *p #elif defined(__Windows__) @@ -5128,7 +5143,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, LIST_INSERT_HEAD(head, stcb, sctp_asocs); SCTP_INP_INFO_WUNLOCK(); - if ((err = sctp_add_remote_addr(stcb, firstaddr, NULL, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) { + if ((err = sctp_add_remote_addr(stcb, firstaddr, NULL, port, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) { /* failure.. memory error? */ if (asoc->strmout) { SCTP_FREE(asoc->strmout, SCTP_M_STRMO); @@ -5394,6 +5409,45 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t } } +void +sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh) +{ + struct sctp_tmit_chunk *chk, *nchk; + struct sctp_queued_to_read *ctl, *nctl; + TAILQ_FOREACH_SAFE(ctl, rh, next_instrm, nctl) { + TAILQ_REMOVE(rh, ctl, next_instrm); + ctl->on_strm_q = 0; + if (ctl->on_read_q == 0) { + sctp_free_remote_addr(ctl->whoFrom); + if (ctl->data) { + sctp_m_freem(ctl->data); + ctl->data = NULL; + } + } + /* Reassembly free? */ + TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) { + TAILQ_REMOVE(&ctl->reasm, chk, sctp_next); + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; + } + if (chk->holds_key_ref) + sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); + sctp_free_remote_addr(chk->whoTo); + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); + SCTP_DECR_CHK_COUNT(); + /*sa_ignore FREED_MEMORY*/ + } + /* + * We don't free the address here + * since all the net's were freed + * above. + */ + if (ctl->on_read_q == 0) { + sctp_free_a_readq(stcb, ctl); + } + } +} #ifdef __Panda__ void panda_wakeup_socket(struct socket *so); @@ -5705,7 +5759,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre outs = &asoc->strmout[i]; /* now clean up any chunks here */ TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { + atomic_subtract_int(&asoc->stream_queue_cnt, 1); TAILQ_REMOVE(&outs->outqueue, sp, next); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 0); sctp_free_spbufspace(stcb, asoc, sp); if (sp->data) { if (so) { @@ -5742,8 +5798,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre sq->whoFrom = NULL; sq->stcb = NULL; /* Free the ctl entry */ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), sq); - SCTP_DECR_READQ_COUNT(); + sctp_free_a_readq(stcb, sq); /*sa_ignore FREED_MEMORY*/ } TAILQ_FOREACH_SAFE(chk, &asoc->free_chunks, sctp_next, nchk) { @@ -5856,20 +5911,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre SCTP_DECR_CHK_COUNT(); /*sa_ignore FREED_MEMORY*/ } - TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /*sa_ignore FREED_MEMORY*/ - } - if (asoc->mapping_array) { SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); asoc->mapping_array = NULL; @@ -5885,24 +5926,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } asoc->strm_realoutsize = asoc->streamoutcnt = 0; if (asoc->strmin) { - struct sctp_queued_to_read *ctl, *nctl; - for (i = 0; i < asoc->streamincnt; i++) { - TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[i].inqueue, next, nctl) { - TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next); - sctp_free_remote_addr(ctl->whoFrom); - if (ctl->data) { - sctp_m_freem(ctl->data); - ctl->data = NULL; - } - /* - * We don't free the address here - * since all the net's were freed - * above. - */ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl); - SCTP_DECR_READQ_COUNT(); - } + sctp_clean_up_stream(stcb, &asoc->strmin[i].inqueue); + sctp_clean_up_stream(stcb, &asoc->strmin[i].uno_inqueue); } SCTP_FREE(asoc->strmin, SCTP_M_STRMI); asoc->strmin = NULL; @@ -6148,6 +6174,7 @@ void sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t action) { struct sctp_laddr *laddr; + struct sctp_tcb *stcb; int fnd, error = 0; fnd = 0; @@ -6206,6 +6233,9 @@ sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t ac default: break; } + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + sctp_add_local_addr_restricted(stcb, ifa); + } } return; } @@ -6236,7 +6266,7 @@ sctp_select_primary_destination(struct sctp_tcb *stcb) /* - * Delete the address from the endpoint local address list There is nothing + * Delete the address from the endpoint local address list. There is nothing * to be done if we are bound to all addresses */ void @@ -6277,14 +6307,14 @@ sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa) /* clean up "last_used_address" */ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { struct sctp_nets *net; + SCTP_TCB_LOCK(stcb); if (stcb->asoc.last_used_address == laddr) /* delete this address */ stcb->asoc.last_used_address = NULL; /* Now spin through all the nets and purge any ref to laddr */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if (net->ro._s_addr && - (net->ro._s_addr->ifa == laddr->ifa)) { + if (net->ro._s_addr == laddr->ifa) { /* Yep, purge src address selected */ sctp_rtentry_t *rt; @@ -6348,46 +6378,6 @@ sctp_add_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa) } /* - * insert an laddr entry with the given ifa for the desired list - */ -int -sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act) -{ - struct sctp_laddr *laddr; - - laddr = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); - if (laddr == NULL) { - /* out of memory? */ - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - return (EINVAL); - } - SCTP_INCR_LADDR_COUNT(); - bzero(laddr, sizeof(*laddr)); - (void)SCTP_GETTIME_TIMEVAL(&laddr->start_time); - laddr->ifa = ifa; - laddr->action = act; - atomic_add_int(&ifa->refcount, 1); - /* insert it */ - LIST_INSERT_HEAD(list, laddr, sctp_nxt_addr); - - return (0); -} - -/* - * Remove an laddr entry from the local address list (on an assoc) - */ -void -sctp_remove_laddr(struct sctp_laddr *laddr) -{ - - /* remove from the list */ - LIST_REMOVE(laddr, sctp_nxt_addr); - sctp_free_ifa(laddr->ifa); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), laddr); - SCTP_DECR_LADDR_COUNT(); -} - -/* * Remove a local address from the TCB local address restricted list */ void @@ -6609,7 +6599,7 @@ sctp_startup_mcore_threads(void) } } #endif -#if defined(__FreeBSD__) && __FreeBSD_cc_version >= 1200000 +#if defined(__FreeBSD__) && __FreeBSD_cc_version >= 1300000 static struct mbuf * sctp_netisr_hdlr(struct mbuf *m, uintptr_t source) { @@ -6635,6 +6625,7 @@ sctp_netisr_hdlr(struct mbuf *m, uintptr_t source) tag = htonl(sh->v_tag); flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port); m->m_pkthdr.flowid = flowid; +/* FIX ME */ m->m_flags |= M_FLOWID; return (m); } @@ -6645,7 +6636,7 @@ sctp_pcb_init() { /* * SCTP initialization for the PCB structures should be called by - * the sctp_init() funciton. + * the sctp_init() function. */ int i; struct timeval tv; @@ -6842,7 +6833,7 @@ sctp_pcb_init() */ sctp_init_vrf_list(SCTP_DEFAULT_VRF); #endif -#if defined(__FreeBSD__) && __FreeBSD_cc_version >= 1200000 +#if defined(__FreeBSD__) && __FreeBSD_cc_version >= 1300000 if (ip_register_flow_handler(sctp_netisr_hdlr, IPPROTO_SCTP)) { SCTP_PRINTF("***SCTP- Error can't register netisr handler***\n"); } @@ -6877,6 +6868,11 @@ sctp_pcb_finish(void) int i; struct sctp_iterator *it, *nit; + if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { + SCTP_PRINTF("%s: race condition on teardown.\n", __func__); + return; + } + SCTP_BASE_VAR(sctp_pcb_initialized) = 0; #if !defined(__FreeBSD__) /* Notify the iterator to exit. */ SCTP_IPI_ITERATOR_WQ_LOCK(); @@ -6935,7 +6931,26 @@ sctp_pcb_finish(void) * The only way FreeBSD reaches here is if we have VRF's * but we still add the ifdef to make it compile on old versions. */ +#if defined(__FreeBSD__) +retry: +#endif SCTP_IPI_ITERATOR_WQ_LOCK(); +#if defined(__FreeBSD__) + /* + * sctp_iterator_worker() might be working on an it entry without + * holding the lock. We won't find it on the list either and + * continue and free/destroy it. While holding the lock, spin, to + * avoid the race condition as sctp_iterator_worker() will have to + * wait to re-aquire the lock. + */ + if (sctp_it_ctl.iterator_running != 0 || sctp_it_ctl.cur_it != NULL) { + SCTP_IPI_ITERATOR_WQ_UNLOCK(); + SCTP_PRINTF("%s: Iterator running while we held the lock. Retry. " + "cur_it=%p\n", __func__, sctp_it_ctl.cur_it); + DELAY(10); + goto retry; + } +#endif TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { #if defined(__FreeBSD__) && __FreeBSD_version >= 801000 if (it->vn != curvnet) { @@ -6961,7 +6976,7 @@ sctp_pcb_finish(void) SCTP_IPI_ITERATOR_WQ_DESTROY(); SCTP_ITERATOR_LOCK_DESTROY(); #endif - SCTP_OS_TIMER_STOP(&SCTP_BASE_INFO(addr_wq_timer.timer)); + SCTP_OS_TIMER_STOP_DRAIN(&SCTP_BASE_INFO(addr_wq_timer.timer)); SCTP_WQ_ADDR_LOCK(); LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { LIST_REMOVE(wi, sctp_nxt_addr); @@ -6999,12 +7014,6 @@ sctp_pcb_finish(void) /* free the vrf hashes */ SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_vrfhash), SCTP_BASE_INFO(hashvrfmark)); SCTP_HASH_FREE(SCTP_BASE_INFO(vrf_ifn_hash), SCTP_BASE_INFO(vrf_ifn_hashmark)); -#if defined(__Userspace__) && !defined(__Userspace_os_Windows) - /* free memory allocated by getifaddrs call */ -#if defined(INET) || defined(INET6) - freeifaddrs(g_interfaces); -#endif -#endif /* free the TIMEWAIT list elements malloc'd in the function * sctp_add_vtag_to_timewait()... @@ -7056,6 +7065,14 @@ sctp_pcb_finish(void) SCTP_ZONE_DESTROY(zone_clust); SCTP_ZONE_DESTROY(zone_ext_refcnt); #endif + /* Get rid of other stuff too. */ + if (SCTP_BASE_INFO(sctp_asochash) != NULL) + SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_asochash), SCTP_BASE_INFO(hashasocmark)); + if (SCTP_BASE_INFO(sctp_ephash) != NULL) + SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark)); + if (SCTP_BASE_INFO(sctp_tcpephash) != NULL) + SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark)); + #if defined(__Windows__) || defined(__FreeBSD__) || defined(__Userspace__) SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_ep)); SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asoc)); @@ -7067,13 +7084,6 @@ sctp_pcb_finish(void) SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asconf)); SCTP_ZONE_DESTROY(SCTP_BASE_INFO(ipi_zone_asconf_ack)); #endif - /* Get rid of other stuff to */ - if (SCTP_BASE_INFO(sctp_asochash) != NULL) - SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_asochash), SCTP_BASE_INFO(hashasocmark)); - if (SCTP_BASE_INFO(sctp_ephash) != NULL) - SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark)); - if (SCTP_BASE_INFO(sctp_tcpephash) != NULL) - SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark)); #if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT) SCTP_FREE(SCTP_BASE_STATS, SCTP_M_MCORE); #endif @@ -7084,7 +7094,7 @@ int sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, int offset, int limit, struct sockaddr *src, struct sockaddr *dst, - struct sockaddr *altsa) + struct sockaddr *altsa, uint16_t port) { /* * grub through the INIT pulling addresses and loading them to the @@ -7121,6 +7131,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, uint8_t peer_supports_reconfig; uint8_t peer_supports_nrsack; uint8_t peer_supports_pktdrop; + uint8_t peer_supports_idata; #ifdef INET struct sockaddr_in sin; #endif @@ -7150,6 +7161,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } else { sa = src; } + peer_supports_idata = 0; peer_supports_ecn = 0; peer_supports_prsctp = 0; peer_supports_auth = 0; @@ -7174,7 +7186,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, #ifdef INET case AF_INET: if (stcb->asoc.scope.ipv4_addr_legal) { - if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) { + if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) { return (-1); } } @@ -7183,7 +7195,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, #ifdef INET6 case AF_INET6: if (stcb->asoc.scope.ipv6_addr_legal) { - if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { + if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { return (-2); } } @@ -7192,7 +7204,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, #if defined(__Userspace__) case AF_CONN: if (stcb->asoc.scope.conn_addr_legal) { - if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { + if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { return (-2); } } @@ -7277,7 +7289,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* the assoc was freed? */ return (-7); } - if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) { + if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) { return (-8); } } else if (stcb_tmp == stcb) { @@ -7367,7 +7379,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, * we must add the address, no scope * set */ - if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) { + if (sctp_add_remote_addr(stcb, sa, NULL, port, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) { return (-17); } } else if (stcb_tmp == stcb) { @@ -7528,6 +7540,9 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, case SCTP_AUTHENTICATION: peer_supports_auth = 1; break; + case SCTP_IDATA: + peer_supports_idata = 1; + break; default: /* one I have not learned yet */ break; @@ -7686,6 +7701,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, (peer_supports_reconfig == 0)) { stcb->asoc.reconfig_supported = 0; } + if ((stcb->asoc.idata_supported == 1) && + (peer_supports_idata == 0)) { + stcb->asoc.idata_supported = 0; + } if ((stcb->asoc.nrsack_supported == 1) && (peer_supports_nrsack == 0)) { stcb->asoc.nrsack_supported = 0; @@ -7877,26 +7896,57 @@ sctp_drain_mbufs(struct sctp_tcb *stcb) SCTP_STAT_INCR(sctps_protocol_drains_done); cumulative_tsn_p1 = asoc->cumulative_tsn + 1; cnt = 0; - /* First look in the re-assembly queue */ - TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { - if (SCTP_TSN_GT(chk->rec.data.TSN_seq, cumulative_tsn_p1)) { - /* Yep it is above cum-ack */ - cnt++; - SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn); - asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size); - sctp_ucount_decr(asoc->cnt_on_reasm_queue); - SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - } - } /* Ok that was fun, now we will drain all the inbound streams? */ for (strmat = 0; strmat < asoc->streamincnt; strmat++) { - TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, next, nctl) { + TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, next_instrm, nctl) { +#ifdef INVARIANTS + if (ctl->on_strm_q != SCTP_ON_ORDERED ) { + panic("Huh control: %p on_q: %d -- not ordered?", + ctl, ctl->on_strm_q); + } +#endif + if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) { + /* Yep it is above cum-ack */ + cnt++; + SCTP_CALC_TSN_TO_GAP(gap, ctl->sinfo_tsn, asoc->mapping_array_base_tsn); + asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length); + sctp_ucount_decr(asoc->cnt_on_all_streams); + SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); + if (ctl->on_read_q) { + TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next); + ctl->on_read_q = 0; + } + TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next_instrm); + ctl->on_strm_q = 0; + if (ctl->data) { + sctp_m_freem(ctl->data); + ctl->data = NULL; + } + sctp_free_remote_addr(ctl->whoFrom); + /* Now its reasm? */ + TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) { + cnt++; + SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn); + asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size); + sctp_ucount_decr(asoc->cnt_on_reasm_queue); + SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); + TAILQ_REMOVE(&ctl->reasm, chk, sctp_next); + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; + } + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); + } + sctp_free_a_readq(stcb, ctl); + } + } + TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].uno_inqueue, next_instrm, nctl) { +#ifdef INVARIANTS + if (ctl->on_strm_q != SCTP_ON_UNORDERED ) { + panic("Huh control: %p on_q: %d -- not unordered?", + ctl, ctl->on_strm_q); + } +#endif if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) { /* Yep it is above cum-ack */ cnt++; @@ -7904,14 +7954,32 @@ sctp_drain_mbufs(struct sctp_tcb *stcb) asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length); sctp_ucount_decr(asoc->cnt_on_all_streams); SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); - TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next); + if (ctl->on_read_q) { + TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next); + ctl->on_read_q = 0; + } + TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, ctl, next_instrm); + ctl->on_strm_q = 0; if (ctl->data) { sctp_m_freem(ctl->data); ctl->data = NULL; } sctp_free_remote_addr(ctl->whoFrom); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl); - SCTP_DECR_READQ_COUNT(); + /* Now its reasm? */ + TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) { + cnt++; + SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn); + asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size); + sctp_ucount_decr(asoc->cnt_on_reasm_queue); + SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap); + TAILQ_REMOVE(&ctl->reasm, chk, sctp_next); + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; + } + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); + } + sctp_free_a_readq(stcb, ctl); } } } @@ -8051,6 +8119,11 @@ sctp_initiate_iterator(inp_func inpf, if (af == NULL) { return (-1); } + if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { + SCTP_PRINTF("%s: abort on initialize being %d\n", __func__, + SCTP_BASE_VAR(sctp_pcb_initialized)); + return (-1); + } SCTP_MALLOC(it, struct sctp_iterator *, sizeof(struct sctp_iterator), SCTP_M_ITER); if (it == NULL) { @@ -8091,7 +8164,13 @@ sctp_initiate_iterator(inp_func inpf, } SCTP_IPI_ITERATOR_WQ_LOCK(); - + if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { + SCTP_IPI_ITERATOR_WQ_UNLOCK(); + SCTP_PRINTF("%s: rollback on initialize being %d it=%p\n", __func__, + SCTP_BASE_VAR(sctp_pcb_initialized), it); + SCTP_FREE(it, SCTP_M_ITER); + return (-1); + } TAILQ_INSERT_TAIL(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); if (sctp_it_ctl.iterator_running == 0) { sctp_wakeup_iterator(); diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_pcb.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_pcb.h index 3620bd526a8..7843758705e 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_pcb.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_pcb.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.h 292060 2015-12-10 11:49:32Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.h 298942 2016-05-02 20:56:11Z pfg $"); #endif #ifndef _NETINET_SCTP_PCB_H_ @@ -109,7 +109,7 @@ struct sctp_ifa { * appropriate locks. This is for V6. */ union sctp_sockstore address; - uint32_t refcount; /* number of folks refering to this */ + uint32_t refcount; /* number of folks referring to this */ uint32_t flags; uint32_t localifa_flags; uint32_t vrf_id; /* vrf_id of this addr (for deleting) */ @@ -318,14 +318,24 @@ struct sctp_base_info { #endif #endif #ifdef INET +#if defined(__Userspace_os_Windows) + SOCKET userspace_rawsctp; + SOCKET userspace_udpsctp; +#else int userspace_rawsctp; int userspace_udpsctp; +#endif userland_thread_t recvthreadraw; userland_thread_t recvthreadudp; #endif #ifdef INET6 +#if defined(__Userspace_os_Windows) + SOCKET userspace_rawsctp6; + SOCKET userspace_udpsctp6; +#else int userspace_rawsctp6; int userspace_udpsctp6; +#endif userland_thread_t recvthreadraw6; userland_thread_t recvthreadudp6; #endif @@ -434,7 +444,7 @@ struct sctp_pcbtsn_rlog { struct sctp_inpcb { /*- * put an inpcb in front of it all, kind of a waste but we need to - * for compatability with all the other stuff. + * for compatibility with all the other stuff. */ union { struct inpcb inp; @@ -485,6 +495,7 @@ struct sctp_inpcb { uint8_t ecn_supported; uint8_t prsctp_supported; uint8_t auth_supported; + uint8_t idata_supported; uint8_t asconf_supported; uint8_t reconfig_supported; uint8_t nrsack_supported; @@ -795,16 +806,16 @@ void sctp_inpcb_free(struct sctp_inpcb *, int, int); #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 struct sctp_tcb * sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, - int *, uint32_t, uint32_t, uint16_t, struct thread *); + int *, uint32_t, uint32_t, uint16_t, uint16_t, struct thread *); #elif defined(__Windows__) struct sctp_tcb * sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, - int *, uint32_t, uint32_t, uint16_t, PKTHREAD); + int *, uint32_t, uint32_t, uint16_t, uint16_t, PKTHREAD); #else /* proc will be NULL for __Userspace__ */ struct sctp_tcb * sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, - int *, uint32_t, uint32_t, uint16_t, struct proc *); + int *, uint32_t, uint32_t, uint16_t, uint16_t, struct proc *); #endif int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int); @@ -819,13 +830,9 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t); -int sctp_insert_laddr(struct sctpladdr *, struct sctp_ifa *, uint32_t); - -void sctp_remove_laddr(struct sctp_laddr *); - void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *); -int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, int, int); +int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, uint16_t, int, int); void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *); @@ -840,7 +847,7 @@ void sctp_del_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *); int sctp_load_addresses_from_init(struct sctp_tcb *, struct mbuf *, int, int, - struct sockaddr *, struct sockaddr *, struct sockaddr *); + struct sockaddr *, struct sockaddr *, struct sockaddr *, uint16_t); int sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *, @@ -854,6 +861,8 @@ int sctp_destination_is_reachable(struct sctp_tcb *, struct sockaddr *); int sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp); +void sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh); + /*- * Null in last arg inpcb indicate run on ALL ep's. Specific inp in last arg * indicates run on ONLY assoc's of the specified endpoint. diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_process_lock.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_process_lock.h index 22580183f9b..1d109857a22 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_process_lock.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_process_lock.h @@ -266,62 +266,39 @@ #else /* all Userspaces except Windows */ #define SCTP_WQ_ADDR_INIT() \ - (void)pthread_mutex_init(&SCTP_BASE_INFO(wq_addr_mtx), &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&SCTP_BASE_INFO(wq_addr_mtx), NULL) #define SCTP_WQ_ADDR_DESTROY() \ (void)pthread_mutex_destroy(&SCTP_BASE_INFO(wq_addr_mtx)) -#ifdef INVARIANTS -#define SCTP_WQ_ADDR_LOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s: wq_addr_mtx already locked", __func__)) -#define SCTP_WQ_ADDR_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx)) == 0, ("%s: wq_addr_mtx not locked", __func__)) -#else #define SCTP_WQ_ADDR_LOCK() \ (void)pthread_mutex_lock(&SCTP_BASE_INFO(wq_addr_mtx)) #define SCTP_WQ_ADDR_UNLOCK() \ (void)pthread_mutex_unlock(&SCTP_BASE_INFO(wq_addr_mtx)) -#endif + #define SCTP_INP_INFO_LOCK_INIT() \ - (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_ep_mtx), &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_ep_mtx), NULL) #define SCTP_INP_INFO_LOCK_DESTROY() \ (void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_TRYLOCK() \ - (!(pthread_mutex_trylock(&SCTP_BASE_INFO(ipi_ep_mtx)))) -#ifdef INVARIANTS -#define SCTP_INP_INFO_RLOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx already locked", __func__)) -#define SCTP_INP_INFO_WLOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx already locked", __func__)) -#define SCTP_INP_INFO_RUNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx not locked", __func__)) -#define SCTP_INP_INFO_WUNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) == 0, ("%s: ipi_ep_mtx not locked", __func__)) -#else #define SCTP_INP_INFO_RLOCK() \ (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_TRYLOCK() \ + (!(pthread_mutex_trylock(&SCTP_BASE_INFO(ipi_ep_mtx)))) #define SCTP_INP_INFO_WLOCK() \ (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_RUNLOCK() \ (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_WUNLOCK() \ (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_ep_mtx)) -#endif #define SCTP_IP_PKTLOG_INIT() \ - (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_pktlog_mtx), &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_pktlog_mtx), NULL) #define SCTP_IP_PKTLOG_DESTROY() \ (void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_pktlog_mtx)) -#ifdef INVARIANTS -#define SCTP_IP_PKTLOG_LOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s: ipi_pktlog_mtx already locked", __func__)) -#define SCTP_IP_PKTLOG_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) == 0, ("%s: ipi_pktlog_mtx not locked", __func__)) -#else #define SCTP_IP_PKTLOG_LOCK() \ (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) #define SCTP_IP_PKTLOG_UNLOCK() \ (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx)) -#endif + /* @@ -330,129 +307,87 @@ * or cookie secrets we lock the INP level. */ #define SCTP_INP_READ_INIT(_inp) \ - (void)pthread_mutex_init(&(_inp)->inp_rdata_mtx, &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&(_inp)->inp_rdata_mtx, NULL) + #define SCTP_INP_READ_DESTROY(_inp) \ (void)pthread_mutex_destroy(&(_inp)->inp_rdata_mtx) -#ifdef INVARIANTS -#define SCTP_INP_READ_LOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_rdata_mtx) == 0, ("%s: inp_rdata_mtx already locked", __func__)) -#define SCTP_INP_READ_UNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_rdata_mtx) == 0, ("%s: inp_rdata_mtx not locked", __func__)) -#else -#define SCTP_INP_READ_LOCK(_inp) \ - (void)pthread_mutex_lock(&(_inp)->inp_rdata_mtx); + +#define SCTP_INP_READ_LOCK(_inp) do { \ + (void)pthread_mutex_lock(&(_inp)->inp_rdata_mtx); \ +} while (0) + + #define SCTP_INP_READ_UNLOCK(_inp) \ (void)pthread_mutex_unlock(&(_inp)->inp_rdata_mtx) -#endif #define SCTP_INP_LOCK_INIT(_inp) \ - (void)pthread_mutex_init(&(_inp)->inp_mtx, &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&(_inp)->inp_mtx, NULL) + +#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \ + (void)pthread_mutex_init(&(_inp)->inp_create_mtx, NULL) + #define SCTP_INP_LOCK_DESTROY(_inp) \ (void)pthread_mutex_destroy(&(_inp)->inp_mtx) + +#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \ + (void)pthread_mutex_destroy(&(_inp)->inp_create_mtx) + #ifdef SCTP_LOCK_LOGGING -#ifdef INVARIANTS -#define SCTP_INP_RLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__)) +#define SCTP_INP_RLOCK(_inp) do { \ + if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\ + (void)pthread_mutex_lock(&(_inp)->inp_mtx); \ } while (0) -#define SCTP_INP_WLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__)) +#define SCTP_INP_WLOCK(_inp) do { \ + sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\ + (void)pthread_mutex_lock(&(_inp)->inp_mtx); \ } while (0) + #else -#define SCTP_INP_RLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\ - (void)pthread_mutex_lock(&(_inp)->inp_mtx); \ + +#define SCTP_INP_RLOCK(_inp) do { \ + (void)pthread_mutex_lock(&(_inp)->inp_mtx); \ } while (0) -#define SCTP_INP_WLOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\ - (void)pthread_mutex_lock(&(_inp)->inp_mtx); \ +#define SCTP_INP_WLOCK(_inp) do { \ + (void)pthread_mutex_lock(&(_inp)->inp_mtx); \ } while (0) #endif -#else -#ifdef INVARIANTS -#define SCTP_INP_RLOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__)) -#define SCTP_INP_WLOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx already locked", __func__)) -#else -#define SCTP_INP_RLOCK(_inp) \ - (void)pthread_mutex_lock(&(_inp)->inp_mtx) -#define SCTP_INP_WLOCK(_inp) \ - (void)pthread_mutex_lock(&(_inp)->inp_mtx) -#endif -#endif -#ifdef INVARIANTS -#define SCTP_INP_RUNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx not locked", __func__)) -#define SCTP_INP_WUNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_mtx) == 0, ("%s: inp_mtx not locked", __func__)) -#else -#define SCTP_INP_RUNLOCK(_inp) \ - (void)pthread_mutex_unlock(&(_inp)->inp_mtx) -#define SCTP_INP_WUNLOCK(_inp) \ - (void)pthread_mutex_unlock(&(_inp)->inp_mtx) -#endif + #define SCTP_TCB_SEND_LOCK_INIT(_tcb) \ - (void)pthread_mutex_init(&(_tcb)->tcb_send_mtx, &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&(_tcb)->tcb_send_mtx, NULL) + #define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) \ (void)pthread_mutex_destroy(&(_tcb)->tcb_send_mtx) -#ifdef INVARIANTS -#define SCTP_TCB_SEND_LOCK(_tcb) \ - KASSERT(pthread_mutex_lock(&(_tcb)->tcb_send_mtx) == 0, ("%s: tcb_send_mtx already locked", __func__)) -#define SCTP_TCB_SEND_UNLOCK(_tcb) \ - KASSERT(pthread_mutex_unlock(&(_tcb)->tcb_send_mtx) == 0, ("%s: tcb_send_mtx not locked", __func__)) -#else -#define SCTP_TCB_SEND_LOCK(_tcb) \ - (void)pthread_mutex_lock(&(_tcb)->tcb_send_mtx); + +#define SCTP_TCB_SEND_LOCK(_tcb) do { \ + (void)pthread_mutex_lock(&(_tcb)->tcb_send_mtx); \ +} while (0) + #define SCTP_TCB_SEND_UNLOCK(_tcb) \ (void)pthread_mutex_unlock(&(_tcb)->tcb_send_mtx) -#endif #define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1) #define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1) -#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \ - (void)pthread_mutex_init(&(_inp)->inp_create_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \ - (void)pthread_mutex_destroy(&(_inp)->inp_create_mtx) #ifdef SCTP_LOCK_LOGGING -#ifdef INVARIANTS -#define SCTP_ASOC_CREATE_LOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_CREATE); \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx already locked", __func__)) \ +#define SCTP_ASOC_CREATE_LOCK(_inp) do { \ + if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_CREATE); \ + (void)pthread_mutex_lock(&(_inp)->inp_create_mtx); \ } while (0) #else -#define SCTP_ASOC_CREATE_LOCK(_inp) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_CREATE); \ - (void)pthread_mutex_lock(&(_inp)->inp_create_mtx); \ +#define SCTP_ASOC_CREATE_LOCK(_inp) do { \ + (void)pthread_mutex_lock(&(_inp)->inp_create_mtx); \ } while (0) #endif -#else -#ifdef INVARIANTS -#define SCTP_ASOC_CREATE_LOCK(_inp) \ - KASSERT(pthread_mutex_lock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx already locked", __func__)) -#else -#define SCTP_ASOC_CREATE_LOCK(_inp) \ - (void)pthread_mutex_lock(&(_inp)->inp_create_mtx) -#endif -#endif -#ifdef INVARIANTS -#define SCTP_ASOC_CREATE_UNLOCK(_inp) \ - KASSERT(pthread_mutex_unlock(&(_inp)->inp_create_mtx) == 0, ("%s: inp_create_mtx not locked", __func__)) -#else + +#define SCTP_INP_RUNLOCK(_inp) \ + (void)pthread_mutex_unlock(&(_inp)->inp_mtx) +#define SCTP_INP_WUNLOCK(_inp) \ + (void)pthread_mutex_unlock(&(_inp)->inp_mtx) #define SCTP_ASOC_CREATE_UNLOCK(_inp) \ (void)pthread_mutex_unlock(&(_inp)->inp_create_mtx) -#endif /* * For the majority of things (once we have found the association) we will @@ -463,40 +398,27 @@ */ #define SCTP_TCB_LOCK_INIT(_tcb) \ - (void)pthread_mutex_init(&(_tcb)->tcb_mtx, &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&(_tcb)->tcb_mtx, NULL) + #define SCTP_TCB_LOCK_DESTROY(_tcb) \ (void)pthread_mutex_destroy(&(_tcb)->tcb_mtx) + #ifdef SCTP_LOCK_LOGGING -#ifdef INVARIANTS -#define SCTP_TCB_LOCK(_tcb) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB); \ - KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx already locked", __func__)) \ +#define SCTP_TCB_LOCK(_tcb) do { \ + if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB); \ + (void)pthread_mutex_lock(&(_tcb)->tcb_mtx); \ } while (0) + #else -#define SCTP_TCB_LOCK(_tcb) do { \ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) \ - sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB); \ - (void)pthread_mutex_lock(&(_tcb)->tcb_mtx); \ +#define SCTP_TCB_LOCK(_tcb) do { \ + (void)pthread_mutex_lock(&(_tcb)->tcb_mtx); \ } while (0) #endif -#else -#ifdef INVARIANTS -#define SCTP_TCB_LOCK(_tcb) \ - KASSERT(pthread_mutex_lock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx already locked", __func__)) -#else -#define SCTP_TCB_LOCK(_tcb) \ - (void)pthread_mutex_lock(&(_tcb)->tcb_mtx) -#endif -#endif -#ifdef INVARIANTS -#define SCTP_TCB_UNLOCK(_tcb) \ - KASSERT(pthread_mutex_unlock(&(_tcb)->tcb_mtx) == 0, ("%s: tcb_mtx not locked", __func__)) -#else -#define SCTP_TCB_UNLOCK(_tcb) \ - (void)pthread_mutex_unlock(&(_tcb)->tcb_mtx) -#endif + #define SCTP_TCB_TRYLOCK(_tcb) (!(pthread_mutex_trylock(&(_tcb)->tcb_mtx))) + +#define SCTP_TCB_UNLOCK(_tcb) (void)pthread_mutex_unlock(&(_tcb)->tcb_mtx) + #define SCTP_TCB_LOCK_ASSERT(_tcb) #endif @@ -523,19 +445,9 @@ #define SOCK_LOCK(_so) SOCKBUF_LOCK(&(_so)->so_rcv) #define SOCK_UNLOCK(_so) SOCKBUF_UNLOCK(&(_so)->so_rcv) #else -#define SOCKBUF_LOCK_ASSERT(_so_buf) \ - KASSERT(pthread_mutex_trylock(SOCKBUF_MTX(_so_buf)) == EBUSY, ("%s: socket buffer not locked", __func__)) -#ifdef INVARIANTS -#define SOCKBUF_LOCK(_so_buf) \ - KASSERT(pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) == 0, ("%s: so_buf already locked", __func__)) -#define SOCKBUF_UNLOCK(_so_buf) \ - KASSERT(pthread_mutex_unlock(SOCKBUF_MTX(_so_buf)) == 0, ("%s: so_buf not locked", __func__)) -#else -#define SOCKBUF_LOCK(_so_buf) \ - pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) -#define SOCKBUF_UNLOCK(_so_buf) \ - pthread_mutex_unlock(SOCKBUF_MTX(_so_buf)) -#endif +#define SOCKBUF_LOCK_ASSERT(_so_buf) KASSERT(pthread_mutex_trylock(SOCKBUF_MTX(_so_buf)) == EBUSY, ("%s: socket buffer not locked", __func__)) +#define SOCKBUF_LOCK(_so_buf) pthread_mutex_lock(SOCKBUF_MTX(_so_buf)) +#define SOCKBUF_UNLOCK(_so_buf) pthread_mutex_unlock(SOCKBUF_MTX(_so_buf)) #define SOCK_LOCK(_so) SOCKBUF_LOCK(&(_so)->so_rcv) #define SOCK_UNLOCK(_so) SOCKBUF_UNLOCK(&(_so)->so_rcv) #endif @@ -605,65 +517,57 @@ LeaveCriticalSection(&sctp_it_ctl.ipi_iterator_wq_mtx) #else /* end of __Userspace_os_Windows */ - /* address list locks */ #define SCTP_IPI_ADDR_INIT() \ - (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_addr_mtx), &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&SCTP_BASE_INFO(ipi_addr_mtx), NULL) #define SCTP_IPI_ADDR_DESTROY() \ (void)pthread_mutex_destroy(&SCTP_BASE_INFO(ipi_addr_mtx)) -#ifdef INVARIANTS -#define SCTP_IPI_ADDR_RLOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx already locked", __func__)) -#define SCTP_IPI_ADDR_RUNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx not locked", __func__)) -#define SCTP_IPI_ADDR_WLOCK() \ - KASSERT(pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx already locked", __func__)) -#define SCTP_IPI_ADDR_WUNLOCK() \ - KASSERT(pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) == 0, ("%s: ipi_addr_mtx not locked", __func__)) -#else -#define SCTP_IPI_ADDR_RLOCK() \ - (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)) + +#define SCTP_IPI_ADDR_RLOCK() \ + do { \ + (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)); \ + } while (0) #define SCTP_IPI_ADDR_RUNLOCK() \ (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_WLOCK() \ - (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)); + +#define SCTP_IPI_ADDR_WLOCK() \ + do { \ + (void)pthread_mutex_lock(&SCTP_BASE_INFO(ipi_addr_mtx)); \ + } while (0) #define SCTP_IPI_ADDR_WUNLOCK() \ (void)pthread_mutex_unlock(&SCTP_BASE_INFO(ipi_addr_mtx)) -#endif + /* iterator locks */ #define SCTP_ITERATOR_LOCK_INIT() \ - (void)pthread_mutex_init(&sctp_it_ctl.it_mtx, &SCTP_BASE_VAR(mtx_attr)) -#define SCTP_ITERATOR_LOCK_DESTROY() \ - (void)pthread_mutex_destroy(&sctp_it_ctl.it_mtx) -#ifdef INVARIANTS -#define SCTP_ITERATOR_LOCK() \ - KASSERT(pthread_mutex_lock(&sctp_it_ctl.it_mtx) == 0, ("%s: it_mtx already locked", __func__)) -#define SCTP_ITERATOR_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&sctp_it_ctl.it_mtx) == 0, ("%s: it_mtx not locked", __func__)) -#else -#define SCTP_ITERATOR_LOCK() \ - (void)pthread_mutex_lock(&sctp_it_ctl.it_mtx); + (void)pthread_mutex_init(&sctp_it_ctl.it_mtx, NULL) + +#define SCTP_ITERATOR_LOCK() \ + do { \ + (void)pthread_mutex_lock(&sctp_it_ctl.it_mtx); \ + } while (0) + #define SCTP_ITERATOR_UNLOCK() \ (void)pthread_mutex_unlock(&sctp_it_ctl.it_mtx) -#endif + +#define SCTP_ITERATOR_LOCK_DESTROY() \ + (void)pthread_mutex_destroy(&sctp_it_ctl.it_mtx) + #define SCTP_IPI_ITERATOR_WQ_INIT() \ - (void)pthread_mutex_init(&sctp_it_ctl.ipi_iterator_wq_mtx, &SCTP_BASE_VAR(mtx_attr)) + (void)pthread_mutex_init(&sctp_it_ctl.ipi_iterator_wq_mtx, NULL) + #define SCTP_IPI_ITERATOR_WQ_DESTROY() \ (void)pthread_mutex_destroy(&sctp_it_ctl.ipi_iterator_wq_mtx) -#ifdef INVARIANTS -#define SCTP_IPI_ITERATOR_WQ_LOCK() \ - KASSERT(pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s: ipi_iterator_wq_mtx already locked", __func__)) -#define SCTP_IPI_ITERATOR_WQ_UNLOCK() \ - KASSERT(pthread_mutex_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx) == 0, ("%s: ipi_iterator_wq_mtx not locked", __func__)) -#else + #define SCTP_IPI_ITERATOR_WQ_LOCK() \ - (void)pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx); + do { \ + (void)pthread_mutex_lock(&sctp_it_ctl.ipi_iterator_wq_mtx); \ + } while (0) + #define SCTP_IPI_ITERATOR_WQ_UNLOCK() \ (void)pthread_mutex_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx) #endif -#endif #define SCTP_INCR_EP_COUNT() \ do { \ diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_ss_functions.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_ss_functions.c index d6ccd933a93..03ead7971d9 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_ss_functions.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_ss_functions.c @@ -28,7 +28,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 235828 2012-05-23 11:26:28Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 303793 2016-08-06 12:51:07Z tuexen $"); #endif #include <netinet/sctp_pcb.h> @@ -57,7 +57,9 @@ sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc, { uint16_t i; - TAILQ_INIT(&asoc->ss_data.out_wheel); + asoc->ss_data.locked_on_sending = NULL; + asoc->ss_data.last_out_stream = NULL; + TAILQ_INIT(&asoc->ss_data.out.wheel); /* * If there is data in the stream queues already, * the scheduler of an existing association has @@ -79,13 +81,13 @@ sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { - struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); - TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.rr.next_spoke); + while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { + struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.rr.next_spoke); strq->ss_params.rr.next_spoke.tqe_next = NULL; strq->ss_params.rr.next_spoke.tqe_prev = NULL; } - asoc->last_out_stream = NULL; + asoc->ss_data.last_out_stream = NULL; if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); } @@ -93,8 +95,16 @@ sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, } static void -sctp_ss_default_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq SCTP_UNUSED) +sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + if (with_strq != NULL) { + if (stcb->asoc.ss_data.locked_on_sending == with_strq) { + stcb->asoc.ss_data.locked_on_sending = strq; + } + if (stcb->asoc.ss_data.last_out_stream == with_strq) { + stcb->asoc.ss_data.last_out_stream = strq; + } + } strq->ss_params.rr.next_spoke.tqe_next = NULL; strq->ss_params.rr.next_spoke.tqe_prev = NULL; return; @@ -112,7 +122,7 @@ sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, if (!TAILQ_EMPTY(&strq->outqueue) && (strq->ss_params.rr.next_spoke.tqe_next == NULL) && (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { - TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, + TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke); } if (holds_lock == 0) { @@ -124,7 +134,7 @@ sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, static int sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) { - if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { + if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { return (1); } else { return (0); @@ -143,19 +153,19 @@ sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, if (TAILQ_EMPTY(&strq->outqueue) && (strq->ss_params.rr.next_spoke.tqe_next != NULL || strq->ss_params.rr.next_spoke.tqe_prev != NULL)) { - if (asoc->last_out_stream == strq) { - asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, + if (asoc->ss_data.last_out_stream == strq) { + asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead, ss_params.rr.next_spoke); - if (asoc->last_out_stream == NULL) { - asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel, + if (asoc->ss_data.last_out_stream == NULL) { + asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead); } - if (asoc->last_out_stream == strq) { - asoc->last_out_stream = NULL; + if (asoc->ss_data.last_out_stream == strq) { + asoc->ss_data.last_out_stream = NULL; } } - TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke); strq->ss_params.rr.next_spoke.tqe_next = NULL; strq->ss_params.rr.next_spoke.tqe_prev = NULL; } @@ -172,15 +182,18 @@ sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq, *strqt; - strqt = asoc->last_out_stream; + if (asoc->ss_data.locked_on_sending) { + return (asoc->ss_data.locked_on_sending); + } + strqt = asoc->ss_data.last_out_stream; default_again: /* Find the next stream to use */ if (strqt == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } else { strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); if (strq == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } } @@ -200,7 +213,7 @@ default_again: if (TAILQ_FIRST(&strq->outqueue) && TAILQ_FIRST(&strq->outqueue)->net != NULL && TAILQ_FIRST(&strq->outqueue)->net != net) { - if (strq == asoc->last_out_stream) { + if (strq == asoc->ss_data.last_out_stream) { return (NULL); } else { strqt = strq; @@ -212,11 +225,25 @@ default_again: } static void -sctp_ss_default_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, - struct sctp_association *asoc SCTP_UNUSED, - struct sctp_stream_out *strq, int moved_how_much SCTP_UNUSED) +sctp_ss_default_scheduled(struct sctp_tcb *stcb, + struct sctp_nets *net SCTP_UNUSED, + struct sctp_association *asoc, + struct sctp_stream_out *strq, + int moved_how_much SCTP_UNUSED) { - asoc->last_out_stream = strq; + struct sctp_stream_queue_pending *sp; + + asoc->ss_data.last_out_stream = strq; + if (stcb->asoc.idata_supported == 0) { + sp = TAILQ_FIRST(&strq->outqueue); + if ((sp != NULL) && (sp->some_taken == 1)) { + stcb->asoc.ss_data.locked_on_sending = strq; + } else { + stcb->asoc.ss_data.locked_on_sending = NULL; + } + } else { + stcb->asoc.ss_data.locked_on_sending = NULL; + } return; } @@ -244,6 +271,12 @@ sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_associa return (-1); } +static int +sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED) +{ + return (0); +} + /* * Real round-robin algorithm. * Always interates the streams in ascending order. @@ -261,17 +294,17 @@ sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc, if (!TAILQ_EMPTY(&strq->outqueue) && (strq->ss_params.rr.next_spoke.tqe_next == NULL) && (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { - if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { - TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); + if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { + TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke); } else { - strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); while (strqt != NULL && (strqt->stream_no < strq->stream_no)) { strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); } if (strqt != NULL) { TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke); } else { - TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); + TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke); } } } @@ -290,7 +323,7 @@ static struct sctp_stream_out * sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, struct sctp_association *asoc) { - return (asoc->last_out_stream); + return (asoc->ss_data.last_out_stream); } static void @@ -299,15 +332,15 @@ sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net { struct sctp_stream_out *strq, *strqt; - strqt = asoc->last_out_stream; + strqt = asoc->ss_data.last_out_stream; rrp_again: /* Find the next stream to use */ if (strqt == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } else { strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); if (strq == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } } @@ -327,7 +360,7 @@ rrp_again: if (TAILQ_FIRST(&strq->outqueue) && TAILQ_FIRST(&strq->outqueue)->net != NULL && TAILQ_FIRST(&strq->outqueue)->net != net) { - if (strq == asoc->last_out_stream) { + if (strq == asoc->ss_data.last_out_stream) { strq = NULL; } else { strqt = strq; @@ -335,7 +368,7 @@ rrp_again: } } } - asoc->last_out_stream = strq; + asoc->ss_data.last_out_stream = strq; return; } @@ -351,17 +384,17 @@ sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { - struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { + struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); if (clear_values) { strq->ss_params.prio.priority = 0; } - TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.prio.next_spoke); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.prio.next_spoke); strq->ss_params.prio.next_spoke.tqe_next = NULL; strq->ss_params.prio.next_spoke.tqe_prev = NULL; } - asoc->last_out_stream = NULL; + asoc->ss_data.last_out_stream = NULL; if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); } @@ -369,8 +402,16 @@ sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, } static void -sctp_ss_prio_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) +sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + if (with_strq != NULL) { + if (stcb->asoc.ss_data.locked_on_sending == with_strq) { + stcb->asoc.ss_data.locked_on_sending = strq; + } + if (stcb->asoc.ss_data.last_out_stream == with_strq) { + stcb->asoc.ss_data.last_out_stream = strq; + } + } strq->ss_params.prio.next_spoke.tqe_next = NULL; strq->ss_params.prio.next_spoke.tqe_prev = NULL; if (with_strq != NULL) { @@ -395,17 +436,17 @@ sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc, if (!TAILQ_EMPTY(&strq->outqueue) && (strq->ss_params.prio.next_spoke.tqe_next == NULL) && (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) { - if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { - TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke); + if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { + TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke); } else { - strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) { strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke); } if (strqt != NULL) { TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke); } else { - TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke); + TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke); } } } @@ -427,18 +468,18 @@ sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, if (TAILQ_EMPTY(&strq->outqueue) && (strq->ss_params.prio.next_spoke.tqe_next != NULL || strq->ss_params.prio.next_spoke.tqe_prev != NULL)) { - if (asoc->last_out_stream == strq) { - asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead, + if (asoc->ss_data.last_out_stream == strq) { + asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead, ss_params.prio.next_spoke); - if (asoc->last_out_stream == NULL) { - asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel, + if (asoc->ss_data.last_out_stream == NULL) { + asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead); } - if (asoc->last_out_stream == strq) { - asoc->last_out_stream = NULL; + if (asoc->ss_data.last_out_stream == strq) { + asoc->ss_data.last_out_stream = NULL; } } - TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke); strq->ss_params.prio.next_spoke.tqe_next = NULL; strq->ss_params.prio.next_spoke.tqe_prev = NULL; } @@ -454,18 +495,18 @@ sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq, *strqt, *strqn; - strqt = asoc->last_out_stream; + strqt = asoc->ss_data.last_out_stream; prio_again: /* Find the next stream to use */ if (strqt == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } else { strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke); if (strqn != NULL && strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) { strq = strqn; } else { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } } @@ -485,7 +526,7 @@ prio_again: if (TAILQ_FIRST(&strq->outqueue) && TAILQ_FIRST(&strq->outqueue)->net != NULL && TAILQ_FIRST(&strq->outqueue)->net != net) { - if (strq == asoc->last_out_stream) { + if (strq == asoc->ss_data.last_out_stream) { return (NULL); } else { strqt = strq; @@ -531,16 +572,16 @@ sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { - struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { + struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); if (clear_values) { strq->ss_params.fb.rounds = -1; } - TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.fb.next_spoke); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.fb.next_spoke); strq->ss_params.fb.next_spoke.tqe_next = NULL; strq->ss_params.fb.next_spoke.tqe_prev = NULL; } - asoc->last_out_stream = NULL; + asoc->ss_data.last_out_stream = NULL; if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); } @@ -548,8 +589,16 @@ sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, } static void -sctp_ss_fb_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) +sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + if (with_strq != NULL) { + if (stcb->asoc.ss_data.locked_on_sending == with_strq) { + stcb->asoc.ss_data.locked_on_sending = strq; + } + if (stcb->asoc.ss_data.last_out_stream == with_strq) { + stcb->asoc.ss_data.last_out_stream = strq; + } + } strq->ss_params.fb.next_spoke.tqe_next = NULL; strq->ss_params.fb.next_spoke.tqe_prev = NULL; if (with_strq != NULL) { @@ -573,7 +622,7 @@ sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc, (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) { if (strq->ss_params.fb.rounds < 0) strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; - TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke); + TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke); } if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); @@ -593,18 +642,18 @@ sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, if (TAILQ_EMPTY(&strq->outqueue) && (strq->ss_params.fb.next_spoke.tqe_next != NULL || strq->ss_params.fb.next_spoke.tqe_prev != NULL)) { - if (asoc->last_out_stream == strq) { - asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead, + if (asoc->ss_data.last_out_stream == strq) { + asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead, ss_params.fb.next_spoke); - if (asoc->last_out_stream == NULL) { - asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel, + if (asoc->ss_data.last_out_stream == NULL) { + asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead); } - if (asoc->last_out_stream == strq) { - asoc->last_out_stream = NULL; + if (asoc->ss_data.last_out_stream == strq) { + asoc->ss_data.last_out_stream = NULL; } } - TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke); strq->ss_params.fb.next_spoke.tqe_next = NULL; strq->ss_params.fb.next_spoke.tqe_prev = NULL; } @@ -620,11 +669,11 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq = NULL, *strqt; - if (asoc->last_out_stream == NULL || - TAILQ_FIRST(&asoc->ss_data.out_wheel) == TAILQ_LAST(&asoc->ss_data.out_wheel, sctpwheel_listhead)) { - strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); + if (asoc->ss_data.last_out_stream == NULL || + TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) { + strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); } else { - strqt = TAILQ_NEXT(asoc->last_out_stream, ss_params.fb.next_spoke); + strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke); } do { if ((strqt != NULL) && @@ -641,22 +690,33 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, if (strqt != NULL) { strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke); } else { - strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); } } while (strqt != strq); return (strq); } static void -sctp_ss_fb_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, +sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED, struct sctp_association *asoc, struct sctp_stream_out *strq, int moved_how_much SCTP_UNUSED) { + struct sctp_stream_queue_pending *sp; struct sctp_stream_out *strqt; int subtract; + if (stcb->asoc.idata_supported == 0) { + sp = TAILQ_FIRST(&strq->outqueue); + if ((sp != NULL) && (sp->some_taken == 1)) { + stcb->asoc.ss_data.locked_on_sending = strq; + } else { + stcb->asoc.ss_data.locked_on_sending = NULL; + } + } else { + stcb->asoc.ss_data.locked_on_sending = NULL; + } subtract = strq->ss_params.fb.rounds; - TAILQ_FOREACH(strqt, &asoc->ss_data.out_wheel, ss_params.fb.next_spoke) { + TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) { strqt->ss_params.fb.rounds -= subtract; if (strqt->ss_params.fb.rounds < 0) strqt->ss_params.fb.rounds = 0; @@ -666,7 +726,7 @@ sctp_ss_fb_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SC } else { strq->ss_params.fb.rounds = -1; } - asoc->last_out_stream = strq; + asoc->ss_data.last_out_stream = strq; return; } @@ -687,7 +747,7 @@ sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_queue_pending *sp; uint16_t i; - TAILQ_INIT(&asoc->ss_data.out_list); + TAILQ_INIT(&asoc->ss_data.out.list); /* * If there is data in the stream queues already, * the scheduler of an existing association has @@ -723,8 +783,8 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - while (!TAILQ_EMPTY(&asoc->ss_data.out_list)) { - TAILQ_REMOVE(&asoc->ss_data.out_list, TAILQ_FIRST(&asoc->ss_data.out_list), ss_next); + while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) { + TAILQ_REMOVE(&asoc->ss_data.out.list, TAILQ_FIRST(&asoc->ss_data.out.list), ss_next); } if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); @@ -734,9 +794,16 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, } static void -sctp_ss_fcfs_init_stream(struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_out *with_strq SCTP_UNUSED) +sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { - /* Nothing to be done here */ + if (with_strq != NULL) { + if (stcb->asoc.ss_data.locked_on_sending == with_strq) { + stcb->asoc.ss_data.locked_on_sending = strq; + } + if (stcb->asoc.ss_data.last_out_stream == with_strq) { + stcb->asoc.ss_data.last_out_stream = strq; + } + } return; } @@ -750,7 +817,7 @@ sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, } if (sp && (sp->ss_next.tqe_next == NULL) && (sp->ss_next.tqe_prev == NULL)) { - TAILQ_INSERT_TAIL(&asoc->ss_data.out_list, sp, ss_next); + TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next); } if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); @@ -761,7 +828,7 @@ sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, static int sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) { - if (TAILQ_EMPTY(&asoc->ss_data.out_list)) { + if (TAILQ_EMPTY(&asoc->ss_data.out.list)) { return (1); } else { return (0); @@ -779,7 +846,7 @@ sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, if (sp && ((sp->ss_next.tqe_next != NULL) || (sp->ss_next.tqe_prev != NULL))) { - TAILQ_REMOVE(&asoc->ss_data.out_list, sp, ss_next); + TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next); } if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); @@ -795,7 +862,7 @@ sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, struct sctp_stream_out *strq; struct sctp_stream_queue_pending *sp; - sp = TAILQ_FIRST(&asoc->ss_data.out_list); + sp = TAILQ_FIRST(&asoc->ss_data.out.list); default_again: if (sp != NULL) { strq = &asoc->strmout[sp->stream]; @@ -827,7 +894,7 @@ default_again: return (strq); } -struct sctp_ss_functions sctp_ss_functions[] = { +const struct sctp_ss_functions sctp_ss_functions[] = { /* SCTP_SS_DEFAULT */ { #if defined(__Windows__) || defined(__Userspace_os_Windows) @@ -841,7 +908,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { sctp_ss_default_scheduled, sctp_ss_default_packet_done, sctp_ss_default_get_value, - sctp_ss_default_set_value + sctp_ss_default_set_value, + sctp_ss_default_is_user_msgs_incomplete #else .sctp_ss_init = sctp_ss_default_init, .sctp_ss_clear = sctp_ss_default_clear, @@ -853,7 +921,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_scheduled = sctp_ss_default_scheduled, .sctp_ss_packet_done = sctp_ss_default_packet_done, .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value + .sctp_ss_set_value = sctp_ss_default_set_value, + .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, /* SCTP_SS_ROUND_ROBIN */ @@ -869,7 +938,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { sctp_ss_default_scheduled, sctp_ss_default_packet_done, sctp_ss_default_get_value, - sctp_ss_default_set_value + sctp_ss_default_set_value, + sctp_ss_default_is_user_msgs_incomplete #else .sctp_ss_init = sctp_ss_default_init, .sctp_ss_clear = sctp_ss_default_clear, @@ -881,7 +951,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_scheduled = sctp_ss_default_scheduled, .sctp_ss_packet_done = sctp_ss_default_packet_done, .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value + .sctp_ss_set_value = sctp_ss_default_set_value, + .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, /* SCTP_SS_ROUND_ROBIN_PACKET */ @@ -897,7 +968,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { sctp_ss_default_scheduled, sctp_ss_rrp_packet_done, sctp_ss_default_get_value, - sctp_ss_default_set_value + sctp_ss_default_set_value, + sctp_ss_default_is_user_msgs_incomplete #else .sctp_ss_init = sctp_ss_default_init, .sctp_ss_clear = sctp_ss_default_clear, @@ -909,7 +981,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_scheduled = sctp_ss_default_scheduled, .sctp_ss_packet_done = sctp_ss_rrp_packet_done, .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value + .sctp_ss_set_value = sctp_ss_default_set_value, + .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, /* SCTP_SS_PRIORITY */ @@ -925,7 +998,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { sctp_ss_default_scheduled, sctp_ss_default_packet_done, sctp_ss_prio_get_value, - sctp_ss_prio_set_value + sctp_ss_prio_set_value, + sctp_ss_default_is_user_msgs_incomplete #else .sctp_ss_init = sctp_ss_default_init, .sctp_ss_clear = sctp_ss_prio_clear, @@ -937,7 +1011,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_scheduled = sctp_ss_default_scheduled, .sctp_ss_packet_done = sctp_ss_default_packet_done, .sctp_ss_get_value = sctp_ss_prio_get_value, - .sctp_ss_set_value = sctp_ss_prio_set_value + .sctp_ss_set_value = sctp_ss_prio_set_value, + .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, /* SCTP_SS_FAIR_BANDWITH */ @@ -953,7 +1028,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { sctp_ss_fb_scheduled, sctp_ss_default_packet_done, sctp_ss_default_get_value, - sctp_ss_default_set_value + sctp_ss_default_set_value, + sctp_ss_default_is_user_msgs_incomplete #else .sctp_ss_init = sctp_ss_default_init, .sctp_ss_clear = sctp_ss_fb_clear, @@ -965,7 +1041,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_scheduled = sctp_ss_fb_scheduled, .sctp_ss_packet_done = sctp_ss_default_packet_done, .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value + .sctp_ss_set_value = sctp_ss_default_set_value, + .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif }, /* SCTP_SS_FIRST_COME */ @@ -981,7 +1058,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { sctp_ss_default_scheduled, sctp_ss_default_packet_done, sctp_ss_default_get_value, - sctp_ss_default_set_value + sctp_ss_default_set_value, + sctp_ss_default_is_user_msgs_incomplete #else .sctp_ss_init = sctp_ss_fcfs_init, .sctp_ss_clear = sctp_ss_fcfs_clear, @@ -993,7 +1071,8 @@ struct sctp_ss_functions sctp_ss_functions[] = { .sctp_ss_scheduled = sctp_ss_default_scheduled, .sctp_ss_packet_done = sctp_ss_default_packet_done, .sctp_ss_get_value = sctp_ss_default_get_value, - .sctp_ss_set_value = sctp_ss_default_set_value + .sctp_ss_set_value = sctp_ss_default_set_value, + .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete #endif } }; diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_structs.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_structs.h index ef8ba6a2c85..483b821d91e 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_structs.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_structs.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_structs.h 285792 2015-07-22 11:30:37Z rrs $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_structs.h 303792 2016-08-06 12:33:15Z tuexen $"); #endif #ifndef _NETINET_SCTP_STRUCTS_H_ @@ -228,6 +228,7 @@ struct iterator_control { struct sctp_net_route { sctp_rtentry_t *ro_rt; #if defined(__FreeBSD__) +#if __FreeBSD_version < 1100093 #if __FreeBSD_version >= 800000 void *ro_lle; #endif @@ -235,6 +236,16 @@ struct sctp_net_route { void *ro_ia; int ro_flags; #endif +#else +#if __FreeBSD_version >= 1100116 + struct llentry *ro_lle; +#endif + char *ro_prepend; + uint16_t ro_plen; + uint16_t ro_flags; + uint16_t ro_mtu; + uint16_t spare; +#endif #endif #if defined(__APPLE__) #if !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) @@ -436,7 +447,7 @@ struct sctp_nets { struct sctp_data_chunkrec { uint32_t TSN_seq; /* the TSN of this transmit */ - uint16_t stream_seq; /* the stream sequence number of this transmit */ + uint32_t stream_seq; /* the stream sequence number of this transmit */ uint16_t stream_number; /* the stream number of this guy */ uint32_t payloadtype; uint32_t context; /* from send */ @@ -447,6 +458,7 @@ struct sctp_data_chunkrec { */ uint32_t fast_retran_tsn; /* sending_seq at the time of FR */ struct timeval timetodrop; /* time we drop it from queue */ + uint32_t fsn_num; /* Fragment Sequence Number */ uint8_t doing_fast_retransmit; uint8_t rcv_flags; /* flags pulled from data chunk on inbound for * outbound holds sending flags for PR-SCTP. @@ -499,14 +511,9 @@ struct sctp_tmit_chunk { uint8_t window_probe; }; -/* - * The first part of this structure MUST be the entire sinfo structure. Maybe - * I should have made it a sub structure... we can circle back later and do - * that if we want. - */ struct sctp_queued_to_read { /* sinfo structure Pluse more */ uint16_t sinfo_stream; /* off the wire */ - uint16_t sinfo_ssn; /* off the wire */ + uint32_t sinfo_ssn; /* off the wire */ uint16_t sinfo_flags; /* SCTP_UNORDERED from wire use SCTP_EOF for * EOR */ uint32_t sinfo_ppid; /* off the wire */ @@ -516,8 +523,11 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */ uint32_t sinfo_cumtsn; /* Use this in reassembly as last TSN */ sctp_assoc_t sinfo_assoc_id; /* our assoc id */ /* Non sinfo stuff */ + uint32_t msg_id; /* Fragment Index */ uint32_t length; /* length of data */ uint32_t held_length; /* length held in sb */ + uint32_t top_fsn; /* Highest FSN in queue */ + uint32_t fsn_included; /* Highest FSN in *data portion */ struct sctp_nets *whoFrom; /* where it came from */ struct mbuf *data; /* front of the mbuf chain of data with * PKT_HDR */ @@ -525,14 +535,24 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */ struct mbuf *aux_data; /* used to hold/cache control if o/s does not take it from us */ struct sctp_tcb *stcb; /* assoc, used for window update */ TAILQ_ENTRY(sctp_queued_to_read) next; + TAILQ_ENTRY(sctp_queued_to_read) next_instrm; + struct sctpchunk_listhead reasm; uint16_t port_from; uint16_t spec_flags; /* Flags to hold the notification field */ uint8_t do_not_ref_stcb; uint8_t end_added; uint8_t pdapi_aborted; + uint8_t pdapi_started; uint8_t some_taken; + uint8_t last_frag_seen; + uint8_t first_frag_seen; + uint8_t on_read_q; + uint8_t on_strm_q; }; +#define SCTP_ON_ORDERED 1 +#define SCTP_ON_UNORDERED 2 + /* This data structure will be on the outbound * stream queues. Data will be pulled off from * the front of the mbuf data and chunk-ified @@ -558,6 +578,7 @@ struct sctp_stream_queue_pending { struct sctp_nets *net; TAILQ_ENTRY (sctp_stream_queue_pending) next; TAILQ_ENTRY (sctp_stream_queue_pending) ss_next; + uint32_t fsn; uint32_t length; uint32_t timetolive; uint32_t ppid; @@ -581,14 +602,17 @@ struct sctp_stream_queue_pending { TAILQ_HEAD(sctpwheelunrel_listhead, sctp_stream_in); struct sctp_stream_in { struct sctp_readhead inqueue; + struct sctp_readhead uno_inqueue; + uint32_t last_sequence_delivered; /* used for re-order */ uint16_t stream_no; - uint16_t last_sequence_delivered; /* used for re-order */ uint8_t delivery_started; + uint8_t pd_api_started; }; TAILQ_HEAD(sctpwheel_listhead, sctp_stream_out); TAILQ_HEAD(sctplist_listhead, sctp_stream_queue_pending); + /* Round-robin schedulers */ struct ss_rr { /* next link in wheel */ @@ -615,9 +639,14 @@ struct ss_fb { * This union holds all data necessary for * different stream schedulers. */ -union scheduling_data { - struct sctpwheel_listhead out_wheel; - struct sctplist_listhead out_list; +struct scheduling_data { + struct sctp_stream_out *locked_on_sending; + /* circular looking for output selection */ + struct sctp_stream_out *last_out_stream; + union { + struct sctpwheel_listhead wheel; + struct sctplist_listhead list; + } out; }; /* @@ -652,8 +681,12 @@ struct sctp_stream_out { uint32_t abandoned_unsent[1]; uint32_t abandoned_sent[1]; #endif + /* For associations using DATA chunks, the lower 16-bit of + * next_mid_ordered are used as the next SSN. + */ + uint32_t next_mid_ordered; + uint32_t next_mid_unordered; uint16_t stream_no; - uint16_t next_sequence_send; /* next one I expect to send out */ uint8_t last_msg_incomplete; uint8_t state; }; @@ -685,12 +718,13 @@ struct sctp_scoping { struct sctp_tsn_log { void *stcb; uint32_t tsn; + uint32_t seq; uint16_t strm; - uint16_t seq; uint16_t sz; uint16_t flgs; uint16_t in_pos; uint16_t in_out; + uint16_t resv; }; #define SCTP_FS_SPEC_LOG_SIZE 200 @@ -766,7 +800,7 @@ struct sctp_ss_functions { int holds_lock); void (*sctp_ss_clear)(struct sctp_tcb *stcb, struct sctp_association *asoc, int clear_values, int holds_lock); - void (*sctp_ss_init_stream)(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq); + void (*sctp_ss_init_stream)(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq); void (*sctp_ss_add_to_stream)(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, int holds_lock); int (*sctp_ss_is_empty)(struct sctp_tcb *stcb, struct sctp_association *asoc); @@ -782,6 +816,7 @@ struct sctp_ss_functions { struct sctp_stream_out *strq, uint16_t *value); int (*sctp_ss_set_value)(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, uint16_t value); + int (*sctp_ss_is_user_msgs_incomplete)(struct sctp_tcb *stcb, struct sctp_association *asoc); }; /* used to save ASCONF chunks for retransmission */ @@ -861,20 +896,8 @@ struct sctp_association { struct sctpchunk_listhead sent_queue; struct sctpchunk_listhead send_queue; - /* re-assembly queue for fragmented chunks on the inbound path */ - struct sctpchunk_listhead reasmqueue; - /* Scheduling queues */ - union scheduling_data ss_data; - - /* This pointer will be set to NULL - * most of the time. But when we have - * a fragmented message, where we could - * not get out all of the message at - * the last send then this will point - * to the stream to go get data from. - */ - struct sctp_stream_out *locked_on_sending; + struct scheduling_data ss_data; /* If an iterator is looking at me, this is it */ struct sctp_iterator *stcb_starting_point_for_iterator; @@ -907,8 +930,6 @@ struct sctp_association { /* last place I got a control from */ struct sctp_nets *last_control_chunk_from; - /* circular looking for output selection */ - struct sctp_stream_out *last_out_stream; /* * wait to the point the cum-ack passes req->send_reset_at_tsn for @@ -929,7 +950,6 @@ struct sctp_association { uint32_t stream_scheduling_module; uint32_t vrf_id; - uint32_t cookie_preserve_req; /* ASCONF next seq I am sending out, inits at init-tsn */ uint32_t asconf_seq_out; @@ -1003,7 +1023,7 @@ struct sctp_association { uint32_t sat_t3_recovery_tsn; uint32_t tsn_last_delivered; /* - * For the pd-api we should re-write this a bit more efficent. We + * For the pd-api we should re-write this a bit more efficient. We * could have multiple sctp_queued_to_read's that we are building at * once. Now we only do this when we get ready to deliver to the * socket buffer. Note that we depend on the fact that the struct is @@ -1225,12 +1245,12 @@ struct sctp_association { uint8_t reconfig_supported; uint8_t nrsack_supported; uint8_t pktdrop_supported; + uint8_t idata_supported; /* Did the peer make the stream config (add out) request */ uint8_t peer_req_out; uint8_t local_strreset_support; - uint8_t peer_supports_nat; struct sctp_scoping scope; diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_sysctl.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_sysctl.c index e92776a74b8..68b6da06541 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_sysctl.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_sysctl.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.c 287282 2015-08-29 09:14:32Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.c 303024 2016-07-19 09:48:08Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -72,7 +72,6 @@ sctp_init_sysctls() SCTP_BASE_SYSCTL(sctp_reconfig_enable) = SCTPCTL_RECONFIG_ENABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_nrsack_enable) = SCTPCTL_NRSACK_ENABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_pktdrop_enable) = SCTPCTL_PKTDROP_ENABLE_DEFAULT; - SCTP_BASE_SYSCTL(sctp_strict_sacks) = SCTPCTL_STRICT_SACKS_DEFAULT; #if !(defined(__FreeBSD__) && __FreeBSD_version >= 800000) #if !defined(SCTP_WITH_NO_CSUM) SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) = SCTPCTL_LOOPBACK_NOCSUM_DEFAULT; @@ -115,7 +114,6 @@ sctp_init_sysctls() SCTP_BASE_SYSCTL(sctp_do_drain) = SCTPCTL_DO_SCTP_DRAIN_DEFAULT; SCTP_BASE_SYSCTL(sctp_hb_maxburst) = SCTPCTL_HB_MAX_BURST_DEFAULT; SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit) = SCTPCTL_ABORT_AT_LIMIT_DEFAULT; - SCTP_BASE_SYSCTL(sctp_strict_data_order) = SCTPCTL_STRICT_DATA_ORDER_DEFAULT; SCTP_BASE_SYSCTL(sctp_min_residual) = SCTPCTL_MIN_RESIDUAL_DEFAULT; SCTP_BASE_SYSCTL(sctp_max_retran_chunk) = SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT; SCTP_BASE_SYSCTL(sctp_logging_level) = SCTPCTL_LOGGING_LEVEL_DEFAULT; @@ -330,9 +328,6 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st if (ipv6_addr_legal) { struct sockaddr_in6 *sin6; -#if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME) - struct sockaddr_in6 lsa6; -#endif sin6 = &sctp_ifa->address.sin6; if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) continue; @@ -345,21 +340,6 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { if (local_scope == 0) continue; -#if defined(SCTP_EMBEDDED_V6_SCOPE) - if (sin6->sin6_scope_id == 0) { -#ifdef SCTP_KAME - /* bad link local address */ - if (sa6_recoverscope(sin6) != 0) - continue; -#else - lsa6 = *sin6; - /* bad link local address */ - if (in6_recoverscope(&lsa6, &lsa6.sin6_addr, NULL)) - continue; - sin6 = &lsa6; -#endif /* SCTP_KAME */ - } -#endif /* SCTP_EMBEDDED_V6_SCOPE */ } if ((site_scope == 0) && (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) continue; @@ -528,7 +508,15 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS) xinpcb.maxqlen = 0; } else { xinpcb.qlen = so->so_qlen; +#if defined(__FreeBSD__) && __FreeBSD_version > 1100096 + xinpcb.qlen_old = so->so_qlen > USHRT_MAX ? + USHRT_MAX : (uint16_t) so->so_qlen; +#endif xinpcb.maxqlen = so->so_qlimit; +#if defined(__FreeBSD__) && __FreeBSD_version > 1100096 + xinpcb.maxqlen_old = so->so_qlimit > USHRT_MAX ? + USHRT_MAX : (uint16_t) so->so_qlimit; +#endif } SCTP_INP_INCR_REF(inp); SCTP_INP_RUNLOCK(inp); @@ -1213,7 +1201,6 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asconf_enable, CTLFLAG_VNET|CTLTYPE_UINT|C SCTP_UINT_SYSCTL(reconfig_enable, sctp_reconfig_enable, SCTPCTL_RECONFIG_ENABLE) SCTP_UINT_SYSCTL(nrsack_enable, sctp_nrsack_enable, SCTPCTL_NRSACK_ENABLE) SCTP_UINT_SYSCTL(pktdrop_enable, sctp_pktdrop_enable, SCTPCTL_PKTDROP_ENABLE) -SCTP_UINT_SYSCTL(strict_sacks, sctp_strict_sacks, SCTPCTL_STRICT_SACKS) #if defined(__APPLE__) #if !defined(SCTP_WITH_NO_CSUM) SCTP_UINT_SYSCTL(loopback_nocsum, sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM) @@ -1256,7 +1243,6 @@ SCTP_UINT_SYSCTL(max_chained_mbufs, sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAIN SCTP_UINT_SYSCTL(do_sctp_drain, sctp_do_drain, SCTPCTL_DO_SCTP_DRAIN) SCTP_UINT_SYSCTL(hb_max_burst, sctp_hb_maxburst, SCTPCTL_HB_MAX_BURST) SCTP_UINT_SYSCTL(abort_at_limit, sctp_abort_if_one_2_one_hits_limit, SCTPCTL_ABORT_AT_LIMIT) -SCTP_UINT_SYSCTL(strict_data_order, sctp_strict_data_order, SCTPCTL_STRICT_DATA_ORDER) SCTP_UINT_SYSCTL(min_residual, sctp_min_residual, SCTPCTL_MIN_RESIDUAL) SCTP_UINT_SYSCTL(max_retran_chunk, sctp_max_retran_chunk, SCTPCTL_MAX_RETRAN_CHUNK) SCTP_UINT_SYSCTL(log_level, sctp_logging_level, SCTPCTL_LOGGING_LEVEL) @@ -1325,7 +1311,6 @@ sctp_sysctl_handle_int(SYSCTL_HANDLER_ARGS) RANGECHK(SCTP_BASE_SYSCTL(sctp_reconfig_enable), SCTPCTL_RECONFIG_ENABLE_MIN, SCTPCTL_RECONFIG_ENABLE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_nrsack_enable), SCTPCTL_NRSACK_ENABLE_MIN, SCTPCTL_NRSACK_ENABLE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_pktdrop_enable), SCTPCTL_PKTDROP_ENABLE_MIN, SCTPCTL_PKTDROP_ENABLE_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_strict_sacks), SCTPCTL_STRICT_SACKS_MIN, SCTPCTL_STRICT_SACKS_MAX); #if !defined(SCTP_WITH_NO_CSUM) RANGECHK(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), SCTPCTL_LOOPBACK_NOCSUM_MIN, SCTPCTL_LOOPBACK_NOCSUM_MAX); #endif @@ -1366,7 +1351,6 @@ sctp_sysctl_handle_int(SYSCTL_HANDLER_ARGS) RANGECHK(SCTP_BASE_SYSCTL(sctp_do_drain), SCTPCTL_DO_SCTP_DRAIN_MIN, SCTPCTL_DO_SCTP_DRAIN_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_hb_maxburst), SCTPCTL_HB_MAX_BURST_MIN, SCTPCTL_HB_MAX_BURST_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit), SCTPCTL_ABORT_AT_LIMIT_MIN, SCTPCTL_ABORT_AT_LIMIT_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_strict_data_order), SCTPCTL_STRICT_DATA_ORDER_MIN, SCTPCTL_STRICT_DATA_ORDER_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_min_residual), SCTPCTL_MIN_RESIDUAL_MIN, SCTPCTL_MIN_RESIDUAL_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_max_retran_chunk), SCTPCTL_MAX_RETRAN_CHUNK_MIN, SCTPCTL_MAX_RETRAN_CHUNK_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_logging_level), SCTPCTL_LOGGING_LEVEL_MIN, SCTPCTL_LOGGING_LEVEL_MAX); @@ -1437,10 +1421,6 @@ sysctl_setup_sctp(void) &SCTP_BASE_SYSCTL(sctp_pktdrop_enable), 0, sctp_sysctl_handle_int, SCTPCTL_PKTDROP_ENABLE_DESC); - sysctl_add_oid(&sysctl_oid_top, "strict_sacks", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_strict_sacks), 0, sctp_sysctl_handle_int, - SCTPCTL_STRICT_SACKS_DESC); - #if !defined(SCTP_WITH_NO_CSUM) sysctl_add_oid(&sysctl_oid_top, "loopback_nocsum", CTLTYPE_INT|CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), 0, sctp_sysctl_handle_int, @@ -1595,10 +1575,6 @@ sysctl_setup_sctp(void) &SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit), 0, sctp_sysctl_handle_int, SCTPCTL_ABORT_AT_LIMIT_DESC); - sysctl_add_oid(&sysctl_oid_top, "strict_data_order", CTLTYPE_INT|CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_strict_data_order), 0, sctp_sysctl_handle_int, - SCTPCTL_STRICT_DATA_ORDER_DESC); - sysctl_add_oid(&sysctl_oid_top, "min_residual", CTLTYPE_INT|CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_min_residual), 0, sctp_sysctl_handle_int, SCTPCTL_MIN_RESIDUAL_DESC); diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_sysctl.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_sysctl.h index ea9b3e35243..cbd29e3702d 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_sysctl.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_sysctl.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.h 287529 2015-09-07 02:00:05Z allanjude $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_sysctl.h 299543 2016-05-12 16:34:59Z tuexen $"); #endif #ifndef _NETINET_SCTP_SYSCTL_H_ @@ -54,7 +54,6 @@ struct sctp_sysctl { uint32_t sctp_nrsack_enable; uint32_t sctp_pktdrop_enable; uint32_t sctp_fr_max_burst_default; - uint32_t sctp_strict_sacks; #if !(defined(__FreeBSD__) && __FreeBSD_version >= 800000) #if !defined(SCTP_WITH_NO_CSUM) uint32_t sctp_no_csum_on_loopback; @@ -96,7 +95,6 @@ struct sctp_sysctl { uint32_t sctp_do_drain; uint32_t sctp_hb_maxburst; uint32_t sctp_abort_if_one_2_one_hits_limit; - uint32_t sctp_strict_data_order; uint32_t sctp_min_residual; uint32_t sctp_max_retran_chunk; uint32_t sctp_logging_level; @@ -148,13 +146,21 @@ struct sctp_sysctl { #define SCTPCTL_MAXDGRAM_DESC "Maximum outgoing SCTP buffer size" #define SCTPCTL_MAXDGRAM_MIN 0 #define SCTPCTL_MAXDGRAM_MAX 0xFFFFFFFF +#if defined(__Userspace__) +#define SCTPCTL_MAXDGRAM_DEFAULT SB_MAX +#else #define SCTPCTL_MAXDGRAM_DEFAULT 262144 /* 256k */ +#endif /* recvspace: Maximum incoming SCTP buffer size */ #define SCTPCTL_RECVSPACE_DESC "Maximum incoming SCTP buffer size" #define SCTPCTL_RECVSPACE_MIN 0 #define SCTPCTL_RECVSPACE_MAX 0xFFFFFFFF +#if defined(__Userspace__) +#define SCTPCTL_RECVSPACE_DEFAULT SB_RAW +#else #define SCTPCTL_RECVSPACE_DEFAULT 262144 /* 256k */ +#endif /* autoasconf: Enable SCTP Auto-ASCONF */ #define SCTPCTL_AUTOASCONF_DESC "Enable SCTP Auto-ASCONF" @@ -210,12 +216,6 @@ struct sctp_sysctl { #define SCTPCTL_PKTDROP_ENABLE_MAX 1 #define SCTPCTL_PKTDROP_ENABLE_DEFAULT 0 -/* strict_sacks: Enable SCTP Strict SACK checking */ -#define SCTPCTL_STRICT_SACKS_DESC "Enable SCTP Strict SACK checking" -#define SCTPCTL_STRICT_SACKS_MIN 0 -#define SCTPCTL_STRICT_SACKS_MAX 1 -#define SCTPCTL_STRICT_SACKS_DEFAULT 1 - /* loopback_nocsum: Enable NO Csum on packets sent on loopback */ #define SCTPCTL_LOOPBACK_NOCSUM_DESC "Enable NO Csum on packets sent on loopback" #define SCTPCTL_LOOPBACK_NOCSUM_MIN 0 @@ -445,12 +445,6 @@ struct sctp_sysctl { #define SCTPCTL_ABORT_AT_LIMIT_MAX 1 #define SCTPCTL_ABORT_AT_LIMIT_DEFAULT 0 -/* strict_data_order: Enforce strict data ordering, abort if control inside data */ -#define SCTPCTL_STRICT_DATA_ORDER_DESC "Enforce strict data ordering, abort if control inside data" -#define SCTPCTL_STRICT_DATA_ORDER_MIN 0 -#define SCTPCTL_STRICT_DATA_ORDER_MAX 1 -#define SCTPCTL_STRICT_DATA_ORDER_DEFAULT 0 - /* min_residual: min residual in a data fragment leftover */ #define SCTPCTL_MIN_RESIDUAL_DESC "Minimum residual data chunk in second part of split" #define SCTPCTL_MIN_RESIDUAL_MIN 20 @@ -513,7 +507,7 @@ struct sctp_sysctl { #define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DESC "Enable sending of the SACK-IMMEDIATELY-bit." #define SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN 0 #define SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX 1 -#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN +#define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX /* Enable sending of the NAT-FRIENDLY message */ #define SCTPCTL_NAT_FRIENDLY_INITS_DESC "Enable sending of the nat-friendly SCTP option on INITs." @@ -566,7 +560,7 @@ struct sctp_sysctl { #define SCTPCTL_RTTVAR_DCCCECN_MAX 1 #define SCTPCTL_RTTVAR_DCCCECN_DEFAULT 1 /* 0 means disable feature */ -#define SCTPCTL_BLACKHOLE_DESC "Enable SCTP blackholing. See blackhole(4) man page for more details." +#define SCTPCTL_BLACKHOLE_DESC "Enable SCTP blackholing. See blackhole(4) for more details." #define SCTPCTL_BLACKHOLE_MIN 0 #define SCTPCTL_BLACKHOLE_MAX 2 #define SCTPCTL_BLACKHOLE_DEFAULT SCTPCTL_BLACKHOLE_MIN diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_timer.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_timer.c index bd13dd38f50..4241deb71eb 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_timer.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_timer.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.c 291700 2015-12-03 15:19:29Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.c 299273 2016-05-09 16:35:05Z tuexen $"); #endif #define _IP_VHL @@ -95,7 +95,7 @@ sctp_audit_retranmission_queue(struct sctp_association *asoc) asoc->sent_queue_cnt); } -int +static int sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net, uint16_t threshold) { @@ -121,9 +121,9 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, net->last_active = sctp_get_tick_count(); sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, stcb, net, + inp, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); } } } @@ -665,7 +665,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO, chk->whoTo->flight_size, chk->book_size, - (uintptr_t)chk->whoTo, + (uint32_t)(uintptr_t)chk->whoTo, chk->rec.data.TSN_seq); } sctp_flight_size_decrease(chk); @@ -793,7 +793,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, sctp_misc_ints(SCTP_FLIGHT_LOG_UP, chk->whoTo->flight_size, chk->book_size, - (uintptr_t)chk->whoTo, + (uint32_t)(uintptr_t)chk->whoTo, chk->rec.data.TSN_seq); } @@ -1082,8 +1082,8 @@ sctp_cookie_timer(struct sctp_inpcb *inp, return (1); } /* - * cleared theshold management now lets backoff the address & select - * an alternate + * Cleared threshold management, now lets backoff the address + * and select an alternate */ stcb->asoc.dropped_special_cnt = 0; sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0); @@ -1128,8 +1128,8 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, return (1); } /* - * cleared theshold management now lets backoff the address & select - * an alternate + * Cleared threshold management, now lets backoff the address + * and select an alternate */ sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0, 0); alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0); @@ -1288,7 +1288,7 @@ sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, { struct sctp_nets *alt; - /* first threshold managment */ + /* first threshold management */ if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { /* Assoc is over */ return (1); @@ -1311,7 +1311,7 @@ sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, { struct sctp_nets *alt; - /* first threshold managment */ + /* first threshold management */ if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { /* Assoc is over */ return (1); diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_timer.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_timer.h index 3662bd2c7a5..a519bb6ab68 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_timer.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_timer.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 235828 2012-05-23 11:26:28Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 295709 2016-02-17 18:04:22Z tuexen $"); #endif #ifndef _NETINET_SCTP_TIMER_H_ @@ -48,10 +48,6 @@ sctp_find_alternate_net(struct sctp_tcb *, struct sctp_nets *, int mode); int -sctp_threshold_management(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *, uint16_t); - -int sctp_t3rxt_timer(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *); int diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_uio.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_uio.h index 104c30a341e..b91329cd868 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_uio.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_uio.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_uio.h 290444 2015-11-06 14:00:26Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_uio.h 302950 2016-07-17 13:33:35Z tuexen $"); #endif #ifndef _NETINET_SCTP_UIO_H_ @@ -288,7 +288,8 @@ struct sctp_snd_all_completes { /* The lower four bits is an enumeration of PR-SCTP policies */ #define SCTP_PR_SCTP_NONE 0x0000 /* Reliable transfer */ #define SCTP_PR_SCTP_TTL 0x0001 /* Time based PR-SCTP */ -#define SCTP_PR_SCTP_BUF 0x0002 /* Buffer based PR-SCTP */ +#define SCTP_PR_SCTP_PRIO 0x0002 /* Buffer based PR-SCTP */ +#define SCTP_PR_SCTP_BUF SCTP_PR_SCTP_PRIO /* For backwards compatibility */ #define SCTP_PR_SCTP_RTX 0x0003 /* Number of retransmissions based PR-SCTP */ #define SCTP_PR_SCTP_MAX SCTP_PR_SCTP_RTX #define SCTP_PR_SCTP_ALL 0x000f /* Used for aggregated stats */ @@ -347,12 +348,13 @@ struct sctp_assoc_change { #define SCTP_CANT_STR_ASSOC 0x0005 /* sac_info values */ -#define SCTP_ASSOC_SUPPORTS_PR 0x01 -#define SCTP_ASSOC_SUPPORTS_AUTH 0x02 -#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03 -#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04 -#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05 -#define SCTP_ASSOC_SUPPORTS_MAX 0x05 +#define SCTP_ASSOC_SUPPORTS_PR 0x01 +#define SCTP_ASSOC_SUPPORTS_AUTH 0x02 +#define SCTP_ASSOC_SUPPORTS_ASCONF 0x03 +#define SCTP_ASSOC_SUPPORTS_MULTIBUF 0x04 +#define SCTP_ASSOC_SUPPORTS_RE_CONFIG 0x05 +#define SCTP_ASSOC_SUPPORTS_INTERLEAVING 0x06 +#define SCTP_ASSOC_SUPPORTS_MAX 0x06 /* * Address event */ @@ -617,6 +619,7 @@ struct sctp_paddrthlds { sctp_assoc_t spt_assoc_id; uint16_t spt_pathmaxrxt; uint16_t spt_pathpfthld; + uint16_t spt_pathcpthld; }; struct sctp_paddrinfo { @@ -1198,25 +1201,42 @@ struct xsctp_inpcb { uint32_t total_nospaces; uint32_t fragmentation_point; uint16_t local_port; +#if defined(__FreeBSD__) && __FreeBSD_version > 1100096 + uint16_t qlen_old; + uint16_t maxqlen_old; +#else uint16_t qlen; uint16_t maxqlen; +#endif #if defined(__Windows__) uint16_t padding; #endif #if !(defined(__FreeBSD__) && (__FreeBSD_version < 1001517)) void *socket; #endif +#if defined(__FreeBSD__) && __FreeBSD_version > 1100096 + uint32_t qlen; + uint32_t maxqlen; +#endif #if defined(__FreeBSD__) && __FreeBSD_version < 1000048 uint32_t extra_padding[32]; /* future */ #elif defined(__FreeBSD__) && (__FreeBSD_version < 1001517) uint32_t extra_padding[31]; /* future */ #else #if defined(__LP64__) +#if defined(__FreeBSD__) && __FreeBSD_version > 1100096 + uint32_t extra_padding[27]; /* future */ +#else uint32_t extra_padding[29]; /* future */ +#endif +#else +#if defined(__FreeBSD__) && __FreeBSD_version > 1100096 + uint32_t extra_padding[28]; /* future */ #else uint32_t extra_padding[30]; /* future */ #endif #endif +#endif }; struct xsctp_tcb { diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_userspace.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_userspace.c index de09a7a7d49..1c2116059cb 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_userspace.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_userspace.c @@ -38,6 +38,10 @@ #include <pthread_np.h> #endif +#if defined(__Userspace_os_Linux) +#include <sys/prctl.h> +#endif + #if defined(__Userspace_os_Windows) /* Adapter to translate Unix thread start routines to Windows thread start * routines. @@ -72,7 +76,7 @@ sctp_userspace_set_threadname(const char *name) pthread_setname_np(name); #endif #if defined(__Userspace_os_Linux) - pthread_setname_np(pthread_self(), name); + prctl(PR_SET_NAME, name); #endif #if defined(__Userspace_os_FreeBSD) pthread_set_name_np(pthread_self(), name); @@ -114,27 +118,38 @@ sctp_userspace_get_mtu_from_ifn(uint32_t if_index, int af) { PIP_ADAPTER_ADDRESSES pAdapterAddrs, pAdapt; DWORD AdapterAddrsSize, Err; + int ret; + ret = 0; AdapterAddrsSize = 0; + pAdapterAddrs = NULL; if ((Err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersAddresses() sizing failed with error code %d, AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); - return (-1); + ret = -1; + goto cleanup; } } if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n"); - return (-1); + ret = -1; + goto cleanup; } if ((Err = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersAddresses() failed with error code %d\n", Err); - return (-1); + ret = -1; + goto cleanup; } for (pAdapt = pAdapterAddrs; pAdapt; pAdapt = pAdapt->Next) { if (pAdapt->IfIndex == if_index) - return (pAdapt->Mtu); + ret = pAdapt->Mtu; + break; + } +cleanup: + if (pAdapterAddrs != NULL) { + GlobalFree(pAdapterAddrs); } - return (0); + return (ret); } void @@ -150,6 +165,7 @@ getwintimeofday(struct timeval *tv) int Win_getifaddrs(struct ifaddrs** interfaces) { + int ret; #if defined(INET) || defined(INET6) DWORD Err, AdapterAddrsSize; int count; @@ -165,23 +181,28 @@ Win_getifaddrs(struct ifaddrs** interfaces) #if defined(INET) || defined(INET6) count = 0; #endif + ret = 0; #if defined(INET) AdapterAddrsSize = 0; + pAdapterAddrs = NULL; if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV4Addresses() sizing failed with error code %d and AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); - return (-1); + ret = -1; + goto cleanup; } } /* Allocate memory from sizing information */ if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n"); - return (-1); + ret = -1; + goto cleanup; } /* Get actual adapter information */ if ((Err = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV4Addresses() failed with error code %d\n", Err); - return (-1); + ret = -1; + goto cleanup; } /* Enumerate through each returned adapter and save its information */ for (pAdapt = pAdapterAddrs, count; pAdapt; pAdapt = pAdapt->Next, count++) { @@ -189,7 +210,8 @@ Win_getifaddrs(struct ifaddrs** interfaces) ifa = (struct ifaddrs *)malloc(sizeof(struct ifaddrs)); if ((addr == NULL) || (ifa == NULL)) { SCTPDBG(SCTP_DEBUG_USR, "Can't allocate memory\n"); - return (-1); + ret = -1; + goto cleanup; } ifa->ifa_name = _strdup(pAdapt->AdapterName); ifa->ifa_flags = pAdapt->Flags; @@ -197,43 +219,53 @@ Win_getifaddrs(struct ifaddrs** interfaces) memcpy(addr, &pAdapt->FirstUnicastAddress->Address.lpSockaddr, sizeof(struct sockaddr_in)); interfaces[count] = ifa; } + GlobalFree(pAdapterAddrs); #endif #if defined(INET6) - if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) { - AdapterAddrsSize = 0; - if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { - if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { - SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV6Addresses() sizing failed with error code %d AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); - return (-1); - } - } - /* Allocate memory from sizing information */ - if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { - SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n"); - return (-1); - } - /* Get actual adapter information */ - if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { - SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV6Addresses() failed with error code %d\n", Err); - return (-1); + AdapterAddrsSize = 0; + pAdapterAddrs = NULL; + if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, NULL, &AdapterAddrsSize)) != 0) { + if ((Err != ERROR_BUFFER_OVERFLOW) && (Err != ERROR_INSUFFICIENT_BUFFER)) { + SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV6Addresses() sizing failed with error code %d AdapterAddrsSize = %d\n", Err, AdapterAddrsSize); + ret = -1; + goto cleanup; } - /* Enumerate through each returned adapter and save its information */ - for (pAdapt = pAdapterAddrs, count; pAdapt; pAdapt = pAdapt->Next, count++) { - addr6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6)); - ifa = (struct ifaddrs *)malloc(sizeof(struct ifaddrs)); - if ((addr6 == NULL) || (ifa == NULL)) { - SCTPDBG(SCTP_DEBUG_USR, "Can't allocate memory\n"); - return (-1); - } - ifa->ifa_name = _strdup(pAdapt->AdapterName); - ifa->ifa_flags = pAdapt->Flags; - ifa->ifa_addr = (struct sockaddr *)addr6; - memcpy(addr6, &pAdapt->FirstUnicastAddress->Address.lpSockaddr, sizeof(struct sockaddr_in6)); - interfaces[count] = ifa; + } + /* Allocate memory from sizing information */ + if ((pAdapterAddrs = (PIP_ADAPTER_ADDRESSES) GlobalAlloc(GPTR, AdapterAddrsSize)) == NULL) { + SCTPDBG(SCTP_DEBUG_USR, "Memory allocation error!\n"); + ret = -1; + goto cleanup; + } + /* Get actual adapter information */ + if ((Err = GetAdaptersAddresses(AF_INET6, 0, NULL, pAdapterAddrs, &AdapterAddrsSize)) != ERROR_SUCCESS) { + SCTPDBG(SCTP_DEBUG_USR, "GetAdaptersV6Addresses() failed with error code %d\n", Err); + ret = -1; + goto cleanup; + } + /* Enumerate through each returned adapter and save its information */ + for (pAdapt = pAdapterAddrs, count; pAdapt; pAdapt = pAdapt->Next, count++) { + addr6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6)); + ifa = (struct ifaddrs *)malloc(sizeof(struct ifaddrs)); + if ((addr6 == NULL) || (ifa == NULL)) { + SCTPDBG(SCTP_DEBUG_USR, "Can't allocate memory\n"); + ret = -1; + goto cleanup; } + ifa->ifa_name = _strdup(pAdapt->AdapterName); + ifa->ifa_flags = pAdapt->Flags; + ifa->ifa_addr = (struct sockaddr *)addr6; + memcpy(addr6, &pAdapt->FirstUnicastAddress->Address.lpSockaddr, sizeof(struct sockaddr_in6)); + interfaces[count] = ifa; + } +#endif +#if defined(INET) || defined(INET6) +cleanup: + if (pAdapterAddrs != NULL) { + GlobalFree(pAdapterAddrs); } #endif - return (0); + return (ret); } int diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_usrreq.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_usrreq.c index 22d7d007f80..4c94103bdc1 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_usrreq.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_usrreq.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 291904 2015-12-06 16:17:57Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 304573 2016-08-22 00:40:45Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -68,8 +68,8 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 291904 2015-12-06 16:17:57Z t #define APPLE_FILE_NO 7 #endif -extern struct sctp_cc_functions sctp_cc_functions[]; -extern struct sctp_ss_functions sctp_ss_functions[]; +extern const struct sctp_cc_functions sctp_cc_functions[]; +extern const struct sctp_ss_functions sctp_ss_functions[]; void #if defined(__Userspace__) @@ -100,8 +100,6 @@ sctp_init(void) sctp_recvspace = SB_MAX; #elif defined(__Userspace__) - SCTP_BASE_SYSCTL(sctp_sendspace) = SB_MAX; - SCTP_BASE_SYSCTL(sctp_recvspace) = SB_RAW; SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = port; #else #if !defined(__APPLE__) @@ -166,6 +164,16 @@ sctp_init(void) #endif } +#if defined(__FreeBSD__) +#ifdef VIMAGE +static void +sctp_finish(void *unused __unused) +{ + sctp_pcb_finish(); +} +VNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL); +#endif +#else void sctp_finish(void) { @@ -235,8 +243,7 @@ sctp_finish(void) sctp_finish_sysctls(); #endif } - - +#endif void sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz) @@ -273,7 +280,7 @@ sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz) sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, chk->whoTo->flight_size, chk->book_size, - (uintptr_t)chk->whoTo, + (uint32_t)(uintptr_t)chk->whoTo, chk->rec.data.TSN_seq); } /* Clear any time so NO RTT is being done */ @@ -285,158 +292,52 @@ sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz) #ifdef INET #if !defined(__Userspace__) -#if defined(__Panda__) || defined(__Windows__) -void -#else -static void -#endif -sctp_notify_mbuf(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net, - struct ip *ip, - struct sctphdr *sh) -{ - struct icmp *icmph; - int totsz, tmr_stopped = 0; - uint16_t nxtsz; - - /* protection */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL) || - (ip == NULL) || (sh == NULL)) { - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - return; - } - /* First job is to verify the vtag matches what I would send */ - if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } - icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - - sizeof(struct ip))); - if (icmph->icmp_type != ICMP_UNREACH) { - /* We only care about unreachable */ - SCTP_TCB_UNLOCK(stcb); - return; - } - if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { - /* not a unreachable message due to frag. */ - SCTP_TCB_UNLOCK(stcb); - return; - } -#if defined(__FreeBSD__) && __FreeBSD_version >= 1000000 - totsz = ntohs(ip->ip_len); -#else - totsz = ip->ip_len; -#endif - - nxtsz = ntohs(icmph->icmp_nextmtu); - if (nxtsz == 0) { - /* - * old type router that does not tell us what the next size - * mtu is. Rats we will have to guess (in a educated fashion - * of course) - */ - nxtsz = sctp_get_prev_mtu(totsz); - } - /* Stop any PMTU timer */ - if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { - tmr_stopped = 1; - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); - } - /* Adjust destination size limit */ - if (net->mtu > nxtsz) { - net->mtu = nxtsz; - if (net->port) { - net->mtu -= sizeof(struct udphdr); - } - } - /* now what about the ep? */ - if (stcb->asoc.smallest_mtu > nxtsz) { - sctp_pathmtu_adjustment(stcb, nxtsz); - } - if (tmr_stopped) - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); - - SCTP_TCB_UNLOCK(stcb); -} - void sctp_notify(struct sctp_inpcb *inp, - struct ip *ip, - struct sctphdr *sh, - struct sockaddr *to, - struct sctp_tcb *stcb, - struct sctp_nets *net) + struct sctp_tcb *stcb, + struct sctp_nets *net, + uint8_t icmp_type, + uint8_t icmp_code, + uint16_t ip_len, + uint16_t next_mtu) { #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) struct socket *so; - #endif - struct icmp *icmph; - - /* protection */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL) || - (sh == NULL) || (to == NULL)) { - if (stcb) - SCTP_TCB_UNLOCK(stcb); - return; - } - /* First job is to verify the vtag matches what I would send */ - if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } + int timer_stopped; - icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - - sizeof(struct ip))); - if (icmph->icmp_type != ICMP_UNREACH) { + if (icmp_type != ICMP_UNREACH) { /* We only care about unreachable */ SCTP_TCB_UNLOCK(stcb); return; } - if ((icmph->icmp_code == ICMP_UNREACH_NET) || - (icmph->icmp_code == ICMP_UNREACH_HOST) || - (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || - (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || - (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || - (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || - (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || + if ((icmp_code == ICMP_UNREACH_NET) || + (icmp_code == ICMP_UNREACH_HOST) || + (icmp_code == ICMP_UNREACH_NET_UNKNOWN) || + (icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || + (icmp_code == ICMP_UNREACH_ISOLATED) || + (icmp_code == ICMP_UNREACH_NET_PROHIB) || + (icmp_code == ICMP_UNREACH_HOST_PROHIB) || #if defined(__Panda__) - (icmph->icmp_code == ICMP_UNREACH_ADMIN)) { + (icmp_code == ICMP_UNREACH_ADMIN)) { #elif defined(__Userspace_os_NetBSD) - (icmph->icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) { + (icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) { #else - (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { + (icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { #endif - - /* - * Hmm reachablity problems we must examine closely. If its - * not reachable, we may have lost a network. Or if there is - * NO protocol at the other end named SCTP. well we consider - * it a OOTB abort. - */ + /* Mark the net unreachable. */ if (net->dest_state & SCTP_ADDR_REACHABLE) { - /* Ok that destination is NOT reachable */ + /* OK, that destination is NOT reachable. */ net->dest_state &= ~SCTP_ADDR_REACHABLE; net->dest_state &= ~SCTP_ADDR_PF; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, - stcb, 0, - (void *)net, SCTP_SO_NOT_LOCKED); + stcb, 0, + (void *)net, SCTP_SO_NOT_LOCKED); } SCTP_TCB_UNLOCK(stcb); - } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || - (icmph->icmp_code == ICMP_UNREACH_PORT)) { - /* - * Here the peer is either playing tricks on us, - * including an address that belongs to someone who - * does not support SCTP OR was a userland - * implementation that shutdown and now is dead. In - * either case treat it like a OOTB abort with no - * TCB - */ + } else if ((icmp_code == ICMP_UNREACH_PROTOCOL) || + (icmp_code == ICMP_UNREACH_PORT)) { + /* Treat it like an ABORT. */ sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) so = SCTP_INP_SO(inp); @@ -453,30 +354,69 @@ sctp_notify(struct sctp_inpcb *inp, /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/ #endif /* no need to unlock here, since the TCB is gone */ + } else if (icmp_code == ICMP_UNREACH_NEEDFRAG) { + /* Find the next (smaller) MTU */ + if (next_mtu == 0) { + /* + * Old type router that does not tell us what the next + * MTU is. + * Rats we will have to guess (in a educated fashion + * of course). + */ + next_mtu = sctp_get_prev_mtu(ip_len); + } + /* Stop the PMTU timer. */ + if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { + timer_stopped = 1; + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); + } else { + timer_stopped = 0; + } + /* Update the path MTU. */ + if (net->mtu > next_mtu) { + net->mtu = next_mtu; + if (net->port) { + net->mtu -= sizeof(struct udphdr); + } + } + /* Update the association MTU */ + if (stcb->asoc.smallest_mtu > next_mtu) { + sctp_pathmtu_adjustment(stcb, next_mtu); + } + /* Finally, start the PMTU timer if it was running before. */ + if (timer_stopped) { + sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); + } + SCTP_TCB_UNLOCK(stcb); } else { SCTP_TCB_UNLOCK(stcb); } } #endif -#endif -#ifdef INET #if !defined(__Panda__) && !defined(__Userspace__) #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) void #else void * #endif -sctp_ctlinput(cmd, sa, vip) - int cmd; - struct sockaddr *sa; - void *vip; +sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) { - struct ip *ip = vip; +#if defined(__FreeBSD__) + struct ip *outer_ip; +#endif + struct ip *inner_ip; struct sctphdr *sh; - uint32_t vrf_id; - /* FIX, for non-bsd is this right? */ - vrf_id = SCTP_DEFAULT_VRFID; + struct icmp *icmp; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; +#if defined(__FreeBSD__) + struct sctp_init_chunk *ch; +#endif + struct sockaddr_in src, dst; + if (sa->sa_family != AF_INET || ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) @@ -486,7 +426,7 @@ sctp_ctlinput(cmd, sa, vip) #endif } if (PRC_IS_REDIRECT(cmd)) { - ip = 0; + vip = NULL; } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) return; @@ -494,48 +434,94 @@ sctp_ctlinput(cmd, sa, vip) return (NULL); #endif } - if (ip) { - struct sctp_inpcb *inp = NULL; - struct sctp_tcb *stcb = NULL; - struct sctp_nets *net = NULL; - struct sockaddr_in to, from; - - sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); - bzero(&to, sizeof(to)); - bzero(&from, sizeof(from)); - from.sin_family = to.sin_family = AF_INET; + if (vip != NULL) { + inner_ip = (struct ip *)vip; + icmp = (struct icmp *)((caddr_t)inner_ip - + (sizeof(struct icmp) - sizeof(struct ip))); +#if defined(__FreeBSD__) + outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); +#endif + sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); + memset(&src, 0, sizeof(struct sockaddr_in)); + src.sin_family = AF_INET; #ifdef HAVE_SIN_LEN - from.sin_len = to.sin_len = sizeof(to); + src.sin_len = sizeof(struct sockaddr_in); #endif - from.sin_port = sh->src_port; - from.sin_addr = ip->ip_src; - to.sin_port = sh->dest_port; - to.sin_addr = ip->ip_dst; - + src.sin_port = sh->src_port; + src.sin_addr = inner_ip->ip_src; + memset(&dst, 0, sizeof(struct sockaddr_in)); + dst.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); +#endif + dst.sin_port = sh->dest_port; + dst.sin_addr = inner_ip->ip_dst; /* - * 'to' holds the dest of the packet that failed to be sent. - * 'from' holds our local endpoint address. Thus we reverse - * the to and the from in the lookup. + * 'dst' holds the dest of the packet that failed to be sent. + * 'src' holds our local endpoint address. Thus we reverse + * the dst and the src in the lookup. */ - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to, - (struct sockaddr *)&from, - &inp, &net, 1, vrf_id); - if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { - if (cmd != PRC_MSGSIZE) { - sctp_notify(inp, ip, sh, - (struct sockaddr *)&to, stcb, - net); + inp = NULL; + net = NULL; + stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, + (struct sockaddr *)&src, + &inp, &net, 1, + SCTP_DEFAULT_VRFID); + if ((stcb != NULL) && + (net != NULL) && + (inp != NULL)) { + /* Check the verification tag */ + if (ntohl(sh->v_tag) != 0) { + /* + * This must be the verification tag used for + * sending out packets. We don't consider + * packets reflecting the verification tag. + */ + if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { + SCTP_TCB_UNLOCK(stcb); + return; + } } else { - /* handle possible ICMP size messages */ - sctp_notify_mbuf(inp, stcb, net, ip, sh); +#if defined(__FreeBSD__) + if (ntohs(outer_ip->ip_len) >= + sizeof(struct ip) + + 8 + (inner_ip->ip_hl << 2) + 20) { + /* + * In this case we can check if we + * got an INIT chunk and if the + * initiate tag matches. + */ + ch = (struct sctp_init_chunk *)(sh + 1); + if ((ch->ch.chunk_type != SCTP_INITIATION) || + (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { + SCTP_TCB_UNLOCK(stcb); + return; + } + } else { + SCTP_TCB_UNLOCK(stcb); + return; + } +#else + SCTP_TCB_UNLOCK(stcb); + return; +#endif } + sctp_notify(inp, stcb, net, + icmp->icmp_type, + icmp->icmp_code, +#if defined(__FreeBSD__) && __FreeBSD_version >= 1000000 + ntohs(inner_ip->ip_len), +#else + inner_ip->ip_len, +#endif + ntohs(icmp->icmp_nextmtu)); } else { #if defined(__FreeBSD__) && __FreeBSD_version < 500000 /* * XXX must be fixed for 5.x and higher, leave for * 4.x */ - if (PRC_IS_REDIRECT(cmd) && inp) { + if (PRC_IS_REDIRECT(cmd) && (inp != NULL)) { in_rtchange((struct inpcb *)inp, inetctlerrmap[cmd]); } @@ -717,7 +703,7 @@ sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED #endif inp = (struct sctp_inpcb *)so->so_pcb; - if (inp != 0) { + if (inp != NULL) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } @@ -1169,7 +1155,7 @@ sctp_disconnect(struct socket *so) TAILQ_EMPTY(&asoc->sent_queue) && (asoc->stream_queue_cnt == 0)) { /* there is nothing queued to send, so done */ - if (asoc->locked_on_sending) { + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { goto abort_anyway; } if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && @@ -1217,17 +1203,8 @@ sctp_disconnect(struct socket *so) asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, netp); - if (asoc->locked_on_sending) { - /* Locked to send out the data */ - struct sctp_stream_queue_pending *sp; - sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); - if (sp == NULL) { - SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", - asoc->locked_on_sending->stream_no); - } else { - if ((sp->length == 0) && (sp->msg_is_complete == 0)) - asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; - } + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { + asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; } if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && @@ -1394,7 +1371,7 @@ sctp_shutdown(struct socket *so) TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && (asoc->stream_queue_cnt == 0)) { - if (asoc->locked_on_sending) { + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { goto abort_anyway; } /* there is nothing queued to send, so I'm done... */ @@ -1411,19 +1388,8 @@ sctp_shutdown(struct socket *so) * SHUTDOWN_PENDING. */ SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); - if (asoc->locked_on_sending) { - /* Locked to send out the data */ - struct sctp_stream_queue_pending *sp; - - sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); - if (sp == NULL) { - SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", - asoc->locked_on_sending->stream_no); - } else { - if ((sp->length == 0) && (sp-> msg_is_complete == 0)) { - SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT); - } - } + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { + SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT); } if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && @@ -1968,7 +1934,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, int creat_lock_on = 0; struct sctp_tcb *stcb = NULL; struct sockaddr *sa; - int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; + unsigned int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; uint32_t vrf_id; int bad_addresses = 0; sctp_assoc_t *a_id; @@ -2006,10 +1972,10 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, error = EFAULT; goto out_now; } - totaddrp = (int *)optval; + totaddrp = (unsigned int *)optval; totaddr = *totaddrp; sa = (struct sockaddr *)(totaddrp + 1); - stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); + stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (unsigned int)(optsize - sizeof(int)), &bad_addresses); if ((stcb != NULL) || bad_addresses) { /* Already have or am bring up an association */ SCTP_ASOC_CREATE_UNLOCK(inp); @@ -2060,6 +2026,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, /* We are GOOD to go */ stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, + inp->sctp_ep.port, #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 (struct thread *)p #elif defined(__Windows__) @@ -2117,11 +2084,6 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); } SCTP_TCB_UNLOCK(stcb); - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { - stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; - /* Set the connected flag so we can queue data */ - soisconnecting(so); - } out_now: if (creat_lock_on) { SCTP_ASOC_CREATE_UNLOCK(inp); @@ -2137,19 +2099,19 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, stcb = LIST_FIRST(&inp->sctp_asoc_list); \ if (stcb) { \ SCTP_TCB_LOCK(stcb); \ - } \ + } \ SCTP_INP_RUNLOCK(inp); \ } else if (assoc_id > SCTP_ALL_ASSOC) { \ stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ if (stcb == NULL) { \ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ error = ENOENT; \ break; \ } \ } else { \ stcb = NULL; \ - } \ - } + } \ +} #define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ @@ -2160,7 +2122,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, } else { \ destp = (type *)srcp; \ } \ - } +} #if defined(__Panda__) || defined(__Userspace__) int @@ -2298,6 +2260,37 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, *optsize = sizeof(uint32_t); break; } + case SCTP_INTERLEAVING_SUPPORTED: + { + struct sctp_assoc_value *av; + + SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + + if (stcb) { + av->assoc_value = stcb->asoc.idata_supported; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { + SCTP_INP_RLOCK(inp); + if (inp->idata_supported) { + av->assoc_value = 1; + } else { + av->assoc_value = 0; + } + SCTP_INP_RUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + if (error == 0) { + *optsize = sizeof(struct sctp_assoc_value); + } + break; + } case SCTP_CMT_ON_OFF: { struct sctp_assoc_value *av; @@ -2454,8 +2447,15 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, uint32_t *value, cnt; SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); - cnt = 0; SCTP_INP_RLOCK(inp); + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { + /* Can't do this for a 1-1 socket */ + error = EINVAL; + SCTP_INP_RUNLOCK(inp); + break; + } + cnt = 0; LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { cnt++; } @@ -2467,15 +2467,28 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, case SCTP_GET_ASSOC_ID_LIST: { struct sctp_assoc_ids *ids; - unsigned int at, limit; + uint32_t at; + size_t limit; SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); - at = 0; - limit = (*optsize-sizeof(uint32_t))/ sizeof(sctp_assoc_t); SCTP_INP_RLOCK(inp); + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { + /* Can't do this for a 1-1 socket */ + error = EINVAL; + SCTP_INP_RUNLOCK(inp); + break; + } + at = 0; + limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t); LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { if (at < limit) { ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); + if (at == 0) { + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } } else { error = EINVAL; SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); @@ -3935,9 +3948,11 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, if (net != NULL) { thlds->spt_pathmaxrxt = net->failure_threshold; thlds->spt_pathpfthld = net->pf_threshold; + thlds->spt_pathcpthld = 0xffff; } else { thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; + thlds->spt_pathcpthld = 0xffff; } thlds->spt_assoc_id = sctp_get_associd(stcb); SCTP_TCB_UNLOCK(stcb); @@ -3949,6 +3964,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_INP_RLOCK(inp); thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; + thlds->spt_pathcpthld = 0xffff; SCTP_INP_RUNLOCK(inp); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); @@ -4552,6 +4568,42 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; } + case SCTP_INTERLEAVING_SUPPORTED: + { + struct sctp_assoc_value *av; + + SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + + if (stcb) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { + SCTP_INP_WLOCK(inp); + if (av->assoc_value == 0) { + inp->idata_supported = 0; + } else { + if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && + (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS))) { + inp->idata_supported = 1; + } else { + /* Must have Frag interleave and stream interleave on */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + SCTP_INP_WUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + break; + } case SCTP_CMT_ON_OFF: if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { struct sctp_assoc_value *av; @@ -6604,6 +6656,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, __func__); continue; } + if ((sctp_is_addr_restricted(stcb, laddr->ifa)) && + (!sctp_is_addr_pending(stcb, laddr->ifa))) { + continue; + } if (laddr->ifa == ifa) { found = 1; break; @@ -6658,6 +6714,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } + sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); out_of_it: SCTP_TCB_UNLOCK(stcb); } else { @@ -7115,6 +7172,11 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, break; } } + if (thlds->spt_pathcpthld != 0xffff) { + error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } if (stcb != NULL) { if (net != NULL) { net->failure_threshold = thlds->spt_pathmaxrxt; @@ -7845,7 +7907,9 @@ sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p) } #endif /* We are GOOD to go */ - stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, p); + stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, + inp->sctp_ep.pre_open_stream_count, + inp->sctp_ep.port, p); if (stcb == NULL) { /* Gak! no memory */ goto out_now; @@ -8010,7 +8074,9 @@ sctpconn_connect(struct socket *so, struct sockaddr *addr) } #endif /* We are GOOD to go */ - stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, p); + stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, + inp->sctp_ep.pre_open_stream_count, + inp->sctp_ep.port, p); if (stcb == NULL) { /* Gak! no memory */ goto out_now; diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_var.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_var.h index 8441d1869bf..d29c94a6a60 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_var.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_var.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctp_var.h 284384 2015-06-14 17:48:44Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctp_var.h 301114 2016-06-01 10:14:04Z bz $"); #endif #ifndef _NETINET_SCTP_VAR_H_ @@ -90,7 +90,7 @@ extern struct pr_usrreqs sctp_usrreqs; #define sctp_sbspace_failedmsgs(sb) ((long) ((sctp_maxspace(sb) > (sb)->sb_cc) ? (sctp_maxspace(sb) - (sb)->sb_cc) : 0)) -#define sctp_sbspace_sub(a,b) ((a > b) ? (a - b) : 0) +#define sctp_sbspace_sub(a,b) (((a) > (b)) ? ((a) - (b)) : 0) /* * I tried to cache the readq entries at one point. But the reality @@ -101,11 +101,19 @@ extern struct pr_usrreqs sctp_usrreqs; * an mbuf cache as well so it is not really worth doing, at least * right now :-D */ - +#ifdef INVARIANTS #define sctp_free_a_readq(_stcb, _readq) { \ + if ((_readq)->on_strm_q) \ + panic("On strm q stcb:%p readq:%p", (_stcb), (_readq)); \ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), (_readq)); \ SCTP_DECR_READQ_COUNT(); \ } +#else +#define sctp_free_a_readq(_stcb, _readq) { \ + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), (_readq)); \ + SCTP_DECR_READQ_COUNT(); \ +} +#endif #define sctp_alloc_a_readq(_stcb, _readq) { \ (_readq) = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_readq), struct sctp_queued_to_read); \ @@ -216,7 +224,7 @@ extern struct pr_usrreqs sctp_usrreqs; atomic_add_int(&(sb)->sb_cc,SCTP_BUF_LEN((m))); \ atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \ if (stcb) { \ - atomic_add_int(&(stcb)->asoc.sb_cc,SCTP_BUF_LEN((m))); \ + atomic_add_int(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \ atomic_add_int(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \ } \ if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \ @@ -413,7 +421,7 @@ void sctp_ctlinput(int, struct sockaddr *, void *); int sctp_ctloutput(struct socket *, struct sockopt *); #ifdef INET void sctp_input_with_port(struct mbuf *, int, uint16_t); -#if defined(__FreeBSD__) && __FreeBSD_version >= 1100020 +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100020 int sctp_input(struct mbuf **, int *, int); #else void sctp_input(struct mbuf *, int); @@ -447,21 +455,19 @@ void sctp_init __P((void)); void sctp_init(struct protosw *pp, struct domain *dp); #else void sctp_init(void); +void sctp_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, + uint8_t, uint8_t, uint16_t, uint16_t); #endif +#if !defined(__FreeBSD__) void sctp_finish(void); +#endif #if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__) int sctp_flush(struct socket *, int); #endif #if defined(__FreeBSD__) && __FreeBSD_version < 902000 int sctp_shutdown __P((struct socket *)); -void sctp_notify __P((struct sctp_inpcb *, struct ip *ip, struct sctphdr *, - struct sockaddr *, struct sctp_tcb *, - struct sctp_nets *)); #else int sctp_shutdown(struct socket *); -void sctp_notify(struct sctp_inpcb *, struct ip *ip, struct sctphdr *, - struct sockaddr *, struct sctp_tcb *, - struct sctp_nets *); #endif int sctp_bindx(struct socket *, int, struct sockaddr_storage *, int, int, struct proc *); diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctputil.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctputil.c index fb0aea965b3..b47df765ac5 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctputil.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctputil.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 291904 2015-12-06 16:17:57Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 304736 2016-08-24 06:22:53Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -60,6 +60,9 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 291904 2015-12-06 16:17:57Z tuex #include <netinet/udp.h> #include <netinet/udp_var.h> #include <sys/proc.h> +#ifdef INET6 +#include <netinet/icmp6.h> +#endif #endif #if defined(__APPLE__) @@ -77,8 +80,8 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 291904 2015-12-06 16:17:57Z tuex #endif #endif -extern struct sctp_cc_functions sctp_cc_functions[]; -extern struct sctp_ss_functions sctp_ss_functions[]; +extern const struct sctp_cc_functions sctp_cc_functions[]; +extern const struct sctp_ss_functions sctp_ss_functions[]; void sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr) @@ -568,7 +571,7 @@ sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from) } void -sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen) +sctp_log_block(uint8_t from, struct sctp_association *asoc, size_t sendlen) { #if defined(__FreeBSD__) || defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; @@ -579,7 +582,7 @@ sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen) sctp_clog.x.blk.stream_qcnt = (uint16_t) asoc->stream_queue_cnt; sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue; sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight/1024); - sctp_clog.x.blk.sndlen = sendlen; + sctp_clog.x.blk.sndlen = (uint32_t)sendlen; SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_BLOCK, from, @@ -1034,11 +1037,13 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off; asoc->ecn_supported = inp->ecn_supported; asoc->prsctp_supported = inp->prsctp_supported; + asoc->idata_supported = inp->idata_supported; asoc->auth_supported = inp->auth_supported; asoc->asconf_supported = inp->asconf_supported; asoc->reconfig_supported = inp->reconfig_supported; asoc->nrsack_supported = inp->nrsack_supported; asoc->pktdrop_supported = inp->pktdrop_supported; + asoc->idata_supported = inp->idata_supported; asoc->sctp_cmt_pf = (uint8_t)0; asoc->sctp_frag_point = inp->sctp_frag_point; asoc->sctp_features = inp->sctp_features; @@ -1149,7 +1154,6 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->minrto = inp->sctp_ep.sctp_minrto; asoc->maxrto = inp->sctp_ep.sctp_maxrto; - asoc->locked_on_sending = NULL; asoc->stream_locked_on = 0; asoc->ecn_echo_cnt_onq = 0; asoc->stream_locked = 0; @@ -1195,7 +1199,8 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * that were dropped must be notified to the upper layer as * failed to send. */ - asoc->strmout[i].next_sequence_send = 0x0; + asoc->strmout[i].next_mid_ordered = 0; + asoc->strmout[i].next_mid_unordered = 0; TAILQ_INIT(&asoc->strmout[i].outqueue); asoc->strmout[i].chunks_on_queues = 0; #if defined(SCTP_DETAILED_STR_STATS) @@ -1210,7 +1215,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->strmout[i].stream_no = i; asoc->strmout[i].last_msg_incomplete = 0; asoc->strmout[i].state = SCTP_STREAM_OPENING; - asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL); + asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL); } asoc->ss_functions.sctp_ss_init(stcb, asoc, 0); @@ -1240,7 +1245,6 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, TAILQ_INIT(&asoc->asconf_send_queue); TAILQ_INIT(&asoc->send_queue); TAILQ_INIT(&asoc->sent_queue); - TAILQ_INIT(&asoc->reasmqueue); TAILQ_INIT(&asoc->resetHead); asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome; TAILQ_INIT(&asoc->asconf_queue); @@ -1352,6 +1356,7 @@ sctp_iterator_work(struct sctp_iterator *it) SCTP_INP_INFO_RLOCK(); SCTP_ITERATOR_LOCK(); + sctp_it_ctl.cur_it = it; if (it->inp) { SCTP_INP_RLOCK(it->inp); SCTP_INP_DECR_REF(it->inp); @@ -1359,6 +1364,7 @@ sctp_iterator_work(struct sctp_iterator *it) if (it->inp == NULL) { /* iterator is complete */ done_with_iterator: + sctp_it_ctl.cur_it = NULL; SCTP_ITERATOR_UNLOCK(); SCTP_INP_INFO_RUNLOCK(); if (it->function_atend != NULL) { @@ -1374,7 +1380,7 @@ select_a_new_ep: SCTP_INP_RLOCK(it->inp); } while (((it->pcb_flags) && - ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || + ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || ((it->pcb_features) && ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) { /* endpoint flags or features don't match, so keep looking */ @@ -1506,7 +1512,6 @@ sctp_iterator_worker(void) sctp_it_ctl.iterator_running = 1; TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { - sctp_it_ctl.cur_it = it; /* now lets work on this one */ TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); SCTP_IPI_ITERATOR_WQ_UNLOCK(); @@ -1514,7 +1519,6 @@ sctp_iterator_worker(void) CURVNET_SET(it->vn); #endif sctp_iterator_work(it); - sctp_it_ctl.cur_it = NULL; #if defined(__FreeBSD__) && __FreeBSD_version >= 801000 CURVNET_RESTORE(); #endif @@ -1524,7 +1528,7 @@ sctp_iterator_worker(void) break; } #endif - /*sa_ignore FREED_MEMORY*/ + /*sa_ignore FREED_MEMORY*/ } sctp_it_ctl.iterator_running = 0; return; @@ -1562,14 +1566,30 @@ sctp_handle_addr_wq(void) if (asc->cnt == 0) { SCTP_FREE(asc, SCTP_M_ASC_IT); } else { - (void)sctp_initiate_iterator(sctp_asconf_iterator_ep, - sctp_asconf_iterator_stcb, - NULL, /* No ep end for boundall */ - SCTP_PCB_FLAGS_BOUNDALL, - SCTP_PCB_ANY_FEATURES, - SCTP_ASOC_ANY_STATE, - (void *)asc, 0, - sctp_asconf_iterator_end, NULL, 0); + int ret; + + ret = sctp_initiate_iterator(sctp_asconf_iterator_ep, + sctp_asconf_iterator_stcb, + NULL, /* No ep end for boundall */ + SCTP_PCB_FLAGS_BOUNDALL, + SCTP_PCB_ANY_FEATURES, + SCTP_ASOC_ANY_STATE, + (void *)asc, 0, + sctp_asconf_iterator_end, NULL, 0); + if (ret) { + SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n"); + /* Freeing if we are stopping or put back on the addr_wq. */ + if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { + sctp_asconf_iterator_end(asc, 0); + } else { + SCTP_WQ_ADDR_LOCK(); + LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) { + LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); + } + SCTP_WQ_ADDR_UNLOCK(); + SCTP_FREE(asc, SCTP_M_ASC_IT); + } + } } } @@ -1585,6 +1605,7 @@ sctp_timeout_handler(void *t) struct socket *so; #endif int did_output; + int type; tmr = (struct sctp_timer *)t; inp = (struct sctp_inpcb *)tmr->ep; @@ -1665,8 +1686,9 @@ sctp_timeout_handler(void *t) return; } } + type = tmr->type; tmr->stopped_from = 0xa005; - SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", tmr->type); + SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", type); if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { if (inp) { SCTP_INP_DECR_REF(inp); @@ -1684,7 +1706,7 @@ sctp_timeout_handler(void *t) if (stcb) { SCTP_TCB_LOCK(stcb); atomic_add_int(&stcb->asoc.refcnt, -1); - if ((tmr->type != SCTP_TIMER_TYPE_ASOCKILL) && + if ((type != SCTP_TIMER_TYPE_ASOCKILL) && ((stcb->asoc.state == 0) || (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) { SCTP_TCB_UNLOCK(stcb); @@ -1697,8 +1719,8 @@ sctp_timeout_handler(void *t) return; } } - /* record in stopped what t-o occured */ - tmr->stopped_from = tmr->type; + /* record in stopped what t-o occurred */ + tmr->stopped_from = type; /* mark as being serviced now */ if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { @@ -1716,7 +1738,7 @@ sctp_timeout_handler(void *t) SCTP_OS_TIMER_DEACTIVATE(&tmr->timer); /* call the handler for the appropriate timer type */ - switch (tmr->type) { + switch (type) { case SCTP_TIMER_TYPE_ZERO_COPY: if (inp == NULL) { break; @@ -2006,11 +2028,11 @@ sctp_timeout_handler(void *t) goto out_no_decr; default: SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n", - tmr->type); + type); break; } #ifdef SCTP_AUDITING_ENABLED - sctp_audit_log(0xF1, (uint8_t) tmr->type); + sctp_audit_log(0xF1, (uint8_t) type); if (inp) sctp_auditing(5, inp, stcb, net); #endif @@ -2035,8 +2057,7 @@ out_decr: } out_no_decr: - SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type %d)\n", - tmr->type); + SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type = %d)\n", type); #if defined(__FreeBSD__) && __FreeBSD_version >= 801000 CURVNET_RESTORE(); #endif @@ -2776,7 +2797,8 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, struct mbuf *m_notify; struct sctp_assoc_change *sac; struct sctp_queued_to_read *control; - size_t notif_len, abort_len; + unsigned int notif_len; + uint16_t abort_len; unsigned int i; #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) struct socket *so; @@ -2786,7 +2808,7 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, return; } if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) { - notif_len = sizeof(struct sctp_assoc_change); + notif_len = (unsigned int)sizeof(struct sctp_assoc_change); if (abort != NULL) { abort_len = ntohs(abort->ch.chunk_length); } else { @@ -2800,7 +2822,7 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) { /* Retry with smaller value. */ - notif_len = sizeof(struct sctp_assoc_change); + notif_len = (unsigned int)sizeof(struct sctp_assoc_change); m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) { goto set_error; @@ -2830,6 +2852,9 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, if (stcb->asoc.asconf_supported == 1) { sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF; } + if (stcb->asoc.idata_supported == 1) { + sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING; + } sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF; if (stcb->asoc.reconfig_supported == 1) { sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG; @@ -3036,7 +3061,8 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, struct sctp_send_failed *ssf; struct sctp_send_failed_event *ssfe; struct sctp_queued_to_read *control; - int length; + struct sctp_chunkhdr *chkhdr; + int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len; if ((stcb == NULL) || (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && @@ -3046,27 +3072,49 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, } if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { - length = sizeof(struct sctp_send_failed_event); + notifhdr_len = sizeof(struct sctp_send_failed_event); } else { - length = sizeof(struct sctp_send_failed); + notifhdr_len = sizeof(struct sctp_send_failed); } - m_notify = sctp_get_mbuf_for_msg(length, 0, M_NOWAIT, 1, MT_DATA); + m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) /* no space left */ return; - SCTP_BUF_LEN(m_notify) = 0; + SCTP_BUF_LEN(m_notify) = notifhdr_len; + if (stcb->asoc.idata_supported) { + chkhdr_len = sizeof(struct sctp_idata_chunk); + } else { + chkhdr_len = sizeof(struct sctp_data_chunk); + } + /* Use some defaults in case we can't access the chunk header */ + if (chk->send_size >= chkhdr_len) { + payload_len = chk->send_size - chkhdr_len; + } else { + payload_len = 0; + } + padding_len = 0; + if (chk->data != NULL) { + chkhdr = mtod(chk->data, struct sctp_chunkhdr *); + if (chkhdr != NULL) { + chk_len = ntohs(chkhdr->chunk_length); + if ((chk_len >= chkhdr_len) && + (chk->send_size >= chk_len) && + (chk->send_size - chk_len < 4)) { + padding_len = chk->send_size - chk_len; + payload_len = chk->send_size - chkhdr_len - padding_len; + } + } + } if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { ssfe = mtod(m_notify, struct sctp_send_failed_event *); - memset(ssfe, 0, length); + memset(ssfe, 0, notifhdr_len); ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; if (sent) { ssfe->ssfe_flags = SCTP_DATA_SENT; } else { ssfe->ssfe_flags = SCTP_DATA_UNSENT; } - length += chk->send_size; - length -= sizeof(struct sctp_data_chunk); - ssfe->ssfe_length = length; + ssfe->ssfe_length = (uint32_t)(notifhdr_len + payload_len); ssfe->ssfe_error = error; /* not exactly what the user sent in, but should be close :) */ ssfe->ssfe_info.snd_sid = chk->rec.data.stream_number; @@ -3075,40 +3123,33 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, ssfe->ssfe_info.snd_context = chk->rec.data.context; ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); ssfe->ssfe_assoc_id = sctp_get_associd(stcb); - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event); } else { ssf = mtod(m_notify, struct sctp_send_failed *); - memset(ssf, 0, length); + memset(ssf, 0, notifhdr_len); ssf->ssf_type = SCTP_SEND_FAILED; if (sent) { ssf->ssf_flags = SCTP_DATA_SENT; } else { ssf->ssf_flags = SCTP_DATA_UNSENT; } - length += chk->send_size; - length -= sizeof(struct sctp_data_chunk); - ssf->ssf_length = length; + ssf->ssf_length = (uint32_t)(notifhdr_len + payload_len); ssf->ssf_error = error; /* not exactly what the user sent in, but should be close :) */ - bzero(&ssf->ssf_info, sizeof(ssf->ssf_info)); ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number; - ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq; + ssf->ssf_info.sinfo_ssn = (uint16_t)chk->rec.data.stream_seq; ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags; ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype; ssf->ssf_info.sinfo_context = chk->rec.data.context; ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); ssf->ssf_assoc_id = sctp_get_associd(stcb); - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed); } - if (chk->data) { - /* - * trim off the sctp chunk header(it should - * be there) - */ - if (chk->send_size >= sizeof(struct sctp_data_chunk)) { - m_adj(chk->data, sizeof(struct sctp_data_chunk)); + if (chk->data != NULL) { + /* Trim off the sctp chunk header (it should be there) */ + if (chk->send_size == chkhdr_len + payload_len + padding_len) { + m_adj(chk->data, chkhdr_len); + m_adj(chk->data, -padding_len); sctp_mbuf_crush(chk->data); - chk->send_size -= sizeof(struct sctp_data_chunk); + chk->send_size -= (chkhdr_len + padding_len); } } SCTP_BUF_NEXT(m_notify) = chk->data; @@ -3153,7 +3194,7 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, struct sctp_send_failed *ssf; struct sctp_send_failed_event *ssfe; struct sctp_queued_to_read *control; - int length; + int notifhdr_len; if ((stcb == NULL) || (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && @@ -3162,23 +3203,22 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, return; } if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { - length = sizeof(struct sctp_send_failed_event); + notifhdr_len = sizeof(struct sctp_send_failed_event); } else { - length = sizeof(struct sctp_send_failed); + notifhdr_len = sizeof(struct sctp_send_failed); } - m_notify = sctp_get_mbuf_for_msg(length, 0, M_NOWAIT, 1, MT_DATA); + m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) { /* no space left */ return; } - SCTP_BUF_LEN(m_notify) = 0; + SCTP_BUF_LEN(m_notify) = notifhdr_len; if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { ssfe = mtod(m_notify, struct sctp_send_failed_event *); - memset(ssfe, 0, length); + memset(ssfe, 0, notifhdr_len); ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; ssfe->ssfe_flags = SCTP_DATA_UNSENT; - length += sp->length; - ssfe->ssfe_length = length; + ssfe->ssfe_length = (uint32_t)(notifhdr_len + sp->length); ssfe->ssfe_error = error; /* not exactly what the user sent in, but should be close :) */ ssfe->ssfe_info.snd_sid = sp->stream; @@ -3191,14 +3231,12 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, ssfe->ssfe_info.snd_context = sp->context; ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); ssfe->ssfe_assoc_id = sctp_get_associd(stcb); - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event); } else { ssf = mtod(m_notify, struct sctp_send_failed *); - memset(ssf, 0, length); + memset(ssf, 0, notifhdr_len); ssf->ssf_type = SCTP_SEND_FAILED; ssf->ssf_flags = SCTP_DATA_UNSENT; - length += sp->length; - ssf->ssf_length = length; + ssf->ssf_length = (uint32_t)(notifhdr_len + sp->length); ssf->ssf_error = error; /* not exactly what the user sent in, but should be close :) */ ssf->ssf_info.sinfo_stream = sp->stream; @@ -3212,7 +3250,6 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, ssf->ssf_info.sinfo_context = sp->context; ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); ssf->ssf_assoc_id = sctp_get_associd(stcb); - SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed); } SCTP_BUF_NEXT(m_notify) = sp->data; @@ -3689,7 +3726,8 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro struct mbuf *m_notify; struct sctp_remote_error *sre; struct sctp_queued_to_read *control; - size_t notif_len, chunk_len; + unsigned int notif_len; + uint16_t chunk_len; if ((stcb == NULL) || sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) { @@ -3700,11 +3738,11 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro } else { chunk_len = 0; } - notif_len = sizeof(struct sctp_remote_error) + chunk_len; + notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len); m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) { /* Retry with smaller value. */ - notif_len = sizeof(struct sctp_remote_error); + notif_len = (unsigned int)sizeof(struct sctp_remote_error); m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); if (m_notify == NULL) { return; @@ -4036,10 +4074,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, /* For each stream */ outs = &asoc->strmout[i]; /* clean up any sends there */ - asoc->locked_on_sending = NULL; TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { - asoc->stream_queue_cnt--; + atomic_subtract_int(&asoc->stream_queue_cnt, 1); TAILQ_REMOVE(&outs->outqueue, sp, next); + stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, holds_lock); sctp_free_spbufspace(stcb, asoc, sp); if (sp->data) { sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, @@ -4120,12 +4158,8 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, vtag = 0; if (stcb != NULL) { - /* We have a TCB to abort, send notification too */ vtag = stcb->asoc.peer_vtag; - sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED); - /* get the assoc vrf id and table id */ vrf_id = stcb->asoc.vrf_id; - stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; } sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err, #if defined(__FreeBSD__) @@ -4133,6 +4167,9 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, #endif vrf_id, port); if (stcb != NULL) { + /* We have a TCB to abort, send notification too */ + sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED); + stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; /* Ok, now lets free it */ #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) so = SCTP_INP_SO(inp); @@ -4261,10 +4298,6 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } else { stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; } - /* notify the ulp */ - if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - sctp_abort_notification(stcb, 0, 0, NULL, so_locked); - } /* notify the peer */ sctp_send_abort_tcb(stcb, op_err, so_locked); SCTP_STAT_INCR_COUNTER32(sctps_aborted); @@ -4272,6 +4305,10 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } + /* notify the ulp */ + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { + sctp_abort_notification(stcb, 0, 0, NULL, so_locked); + } /* now free the asoc */ #ifdef SCTP_ASOCLOG_OF_TSNS sctp_print_out_track_log(stcb); @@ -4718,6 +4755,148 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, } void +sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, + struct sctp_tcb *stcb, + int so_locked +#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) + SCTP_UNUSED +#endif +) +{ + if ((inp != NULL) && (inp->sctp_socket != NULL)) { + if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { + SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); + } else { +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + struct socket *so; + + so = SCTP_INP_SO(inp); + if (!so_locked) { + if (stcb) { + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + } + SCTP_SOCKET_LOCK(so, 1); + if (stcb) { + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); + } + if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { + SCTP_SOCKET_UNLOCK(so, 1); + return; + } + } +#endif + sctp_sorwakeup(inp, inp->sctp_socket); +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + if (!so_locked) { + SCTP_SOCKET_UNLOCK(so, 1); + } +#endif + } + } +} +#if defined(__Userspace__) + +void +sctp_invoke_recv_callback(struct sctp_inpcb *inp, + struct sctp_tcb *stcb, + struct sctp_queued_to_read *control, + int inp_read_lock_held) +{ + uint32_t pd_point, length; + + if ((inp->recv_callback == NULL) || + (stcb == NULL) || + (stcb->sctp_socket == NULL)) { + return; + } + + length = control->length; + if (stcb != NULL && stcb->sctp_socket != NULL) { + pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT, + stcb->sctp_ep->partial_delivery_point); + } else { + pd_point = inp->partial_delivery_point; + } + if ((control->end_added == 1) || (length >= pd_point)) { + struct socket *so; + struct mbuf *m; + char *buffer; + struct sctp_rcvinfo rcv; + union sctp_sockstore addr; + int flags; + + if ((buffer = malloc(length)) == NULL) { + return; + } + if (inp_read_lock_held == 0) { + SCTP_INP_READ_LOCK(inp); + } + so = stcb->sctp_socket; + for (m = control->data; m; m = SCTP_BUF_NEXT(m)) { + sctp_sbfree(control, control->stcb, &so->so_rcv, m); + } + m_copydata(control->data, 0, length, buffer); + memset(&rcv, 0, sizeof(struct sctp_rcvinfo)); + rcv.rcv_sid = control->sinfo_stream; + rcv.rcv_ssn = control->sinfo_ssn; + rcv.rcv_flags = control->sinfo_flags; + rcv.rcv_ppid = control->sinfo_ppid; + rcv.rcv_tsn = control->sinfo_tsn; + rcv.rcv_cumtsn = control->sinfo_cumtsn; + rcv.rcv_context = control->sinfo_context; + rcv.rcv_assoc_id = control->sinfo_assoc_id; + memset(&addr, 0, sizeof(union sctp_sockstore)); + switch (control->whoFrom->ro._l_addr.sa.sa_family) { +#ifdef INET + case AF_INET: + addr.sin = control->whoFrom->ro._l_addr.sin; + break; +#endif +#ifdef INET6 + case AF_INET6: + addr.sin6 = control->whoFrom->ro._l_addr.sin6; + break; +#endif + case AF_CONN: + addr.sconn = control->whoFrom->ro._l_addr.sconn; + break; + default: + addr.sa = control->whoFrom->ro._l_addr.sa; + break; + } + flags = 0; + if (control->end_added == 1) { + flags |= MSG_EOR; + } + if (control->spec_flags & M_NOTIFICATION) { + flags |= MSG_NOTIFICATION; + } + sctp_m_freem(control->data); + control->data = NULL; + control->tail_mbuf = NULL; + control->length = 0; + if (control->end_added) { + TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next); + control->on_read_q = 0; + sctp_free_remote_addr(control->whoFrom); + control->whoFrom = NULL; + sctp_free_a_readq(stcb, control); + } + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + if (inp_read_lock_held == 0) { + SCTP_INP_READ_UNLOCK(inp); + } + inp->recv_callback(so, addr, buffer, length, rcv, flags, inp->ulp_info); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); + } +} +#endif + +void sctp_add_to_readq(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_queued_to_read *control, @@ -4759,7 +4938,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp, sctp_m_freem(control->data); control->data = NULL; } - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control); + sctp_free_a_readq(stcb, control); if (inp_read_lock_held == 0) SCTP_INP_READ_UNLOCK(inp); return; @@ -4805,7 +4984,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp, } else { /* Everything got collapsed out?? */ sctp_free_remote_addr(control->whoFrom); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control); + sctp_free_a_readq(stcb, control); if (inp_read_lock_held == 0) SCTP_INP_READ_UNLOCK(inp); return; @@ -4813,349 +4992,18 @@ sctp_add_to_readq(struct sctp_inpcb *inp, if (end) { control->end_added = 1; } -#if defined(__Userspace__) - if (inp->recv_callback != NULL) { - if (inp_read_lock_held == 0) - SCTP_INP_READ_UNLOCK(inp); - if ((control->end_added == 1) && - (stcb != NULL) && (stcb->sctp_socket != NULL)) { - struct socket *so; - struct mbuf *m; - char *buffer; - struct sctp_rcvinfo rcv; - union sctp_sockstore addr; - int flags; - - if ((buffer = malloc(control->length)) == NULL) { - return; - } - so = stcb->sctp_socket; - for (m = control->data; m; m = SCTP_BUF_NEXT(m)) { - sctp_sbfree(control, control->stcb, &so->so_rcv, m); - } - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - m_copydata(control->data, 0, control->length, buffer); - memset(&rcv, 0, sizeof(struct sctp_rcvinfo)); - rcv.rcv_sid = control->sinfo_stream; - rcv.rcv_ssn = control->sinfo_ssn; - rcv.rcv_flags = control->sinfo_flags; - rcv.rcv_ppid = control->sinfo_ppid; - rcv.rcv_tsn = control->sinfo_tsn; - rcv.rcv_cumtsn = control->sinfo_cumtsn; - rcv.rcv_context = control->sinfo_context; - rcv.rcv_assoc_id = control->sinfo_assoc_id; - memset(&addr, 0, sizeof(union sctp_sockstore)); - switch (control->whoFrom->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - addr.sin = control->whoFrom->ro._l_addr.sin; - break; -#endif -#ifdef INET6 - case AF_INET6: - addr.sin6 = control->whoFrom->ro._l_addr.sin6; - break; -#endif - case AF_CONN: - addr.sconn = control->whoFrom->ro._l_addr.sconn; - break; - default: - addr.sa = control->whoFrom->ro._l_addr.sa; - break; - } - flags = MSG_EOR; - if (control->spec_flags & M_NOTIFICATION) { - flags |= MSG_NOTIFICATION; - } - inp->recv_callback(so, addr, buffer, control->length, rcv, flags, inp->ulp_info); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - sctp_free_remote_addr(control->whoFrom); - control->whoFrom = NULL; - sctp_m_freem(control->data); - control->data = NULL; - control->length = 0; - sctp_free_a_readq(stcb, control); - } - return; - } -#endif TAILQ_INSERT_TAIL(&inp->read_queue, control, next); + control->on_read_q = 1; if (inp_read_lock_held == 0) SCTP_INP_READ_UNLOCK(inp); - if (inp && inp->sctp_socket) { - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { - SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); - } else { -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - struct socket *so; - - so = SCTP_INP_SO(inp); - if (!so_locked) { - if (stcb) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_SOCKET_LOCK(so, 1); - if (stcb) { - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - SCTP_SOCKET_UNLOCK(so, 1); - return; - } - } -#endif - sctp_sorwakeup(inp, inp->sctp_socket); -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - if (!so_locked) { - SCTP_SOCKET_UNLOCK(so, 1); - } -#endif - } - } -} - - -int -sctp_append_to_readq(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_queued_to_read *control, - struct mbuf *m, - int end, - int ctls_cumack, - struct sockbuf *sb) -{ - /* - * A partial delivery API event is underway. OR we are appending on - * the reassembly queue. - * - * If PDAPI this means we need to add m to the end of the data. - * Increase the length in the control AND increment the sb_cc. - * Otherwise sb is NULL and all we need to do is put it at the end - * of the mbuf chain. - */ - int len = 0; - struct mbuf *mm, *tail = NULL, *prev = NULL; - - if (inp) { - SCTP_INP_READ_LOCK(inp); - } - if (control == NULL) { - get_out: - if (inp) { - SCTP_INP_READ_UNLOCK(inp); - } - return (-1); - } - if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ)) { - SCTP_INP_READ_UNLOCK(inp); - return (0); - } - if (control->end_added) { - /* huh this one is complete? */ - goto get_out; - } - mm = m; - if (mm == NULL) { - goto get_out; - } - - while (mm) { - if (SCTP_BUF_LEN(mm) == 0) { - /* Skip mbufs with NO lenght */ - if (prev == NULL) { - /* First one */ - m = sctp_m_free(mm); - mm = m; - } else { - SCTP_BUF_NEXT(prev) = sctp_m_free(mm); - mm = SCTP_BUF_NEXT(prev); - } - continue; - } - prev = mm; - len += SCTP_BUF_LEN(mm); - if (sb) { - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(mm)); - } - sctp_sballoc(stcb, sb, mm); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { - sctp_sblog(sb, control->do_not_ref_stcb?NULL:stcb, SCTP_LOG_SBRESULT, 0); - } - } - mm = SCTP_BUF_NEXT(mm); - } - if (prev) { - tail = prev; - } else { - /* Really there should always be a prev */ - if (m == NULL) { - /* Huh nothing left? */ -#ifdef INVARIANTS - panic("Nothing left to add?"); -#else - goto get_out; -#endif - } - tail = m; - } - if (control->tail_mbuf) { - /* append */ - SCTP_BUF_NEXT(control->tail_mbuf) = m; - control->tail_mbuf = tail; - } else { - /* nothing there */ -#ifdef INVARIANTS - if (control->data != NULL) { - panic("This should NOT happen"); - } -#endif - control->data = m; - control->tail_mbuf = tail; - } - atomic_add_int(&control->length, len); - if (end) { - /* message is complete */ - if (stcb && (control == stcb->asoc.control_pdapi)) { - stcb->asoc.control_pdapi = NULL; - } - control->held_length = 0; - control->end_added = 1; - } - if (stcb == NULL) { - control->do_not_ref_stcb = 1; - } - /* - * When we are appending in partial delivery, the cum-ack is used - * for the actual pd-api highest tsn on this mbuf. The true cum-ack - * is populated in the outbound sinfo structure from the true cumack - * if the association exists... - */ - control->sinfo_tsn = control->sinfo_cumtsn = ctls_cumack; #if defined(__Userspace__) - if ((inp != NULL) && (inp->recv_callback != NULL)) { - uint32_t pd_point, length; - - length = control->length; - if (stcb != NULL && stcb->sctp_socket != NULL) { - pd_point = min(SCTP_SB_LIMIT_RCV(stcb->sctp_socket) >> SCTP_PARTIAL_DELIVERY_SHIFT, - stcb->sctp_ep->partial_delivery_point); - } else { - pd_point = inp->partial_delivery_point; - } - if (((control->end_added == 1) || (length >= pd_point)) && - ((stcb != NULL) && (stcb->sctp_socket))) { - struct socket *so; - char *buffer; - struct sctp_rcvinfo rcv; - union sctp_sockstore addr; - int flags; - - if ((buffer = malloc(control->length)) == NULL) { - return (-1); - } - so = stcb->sctp_socket; - for (m = control->data; m; m = SCTP_BUF_NEXT(m)) { - sctp_sbfree(control, control->stcb, &so->so_rcv, m); - } - m_copydata(control->data, 0, control->length, buffer); - memset(&rcv, 0, sizeof(struct sctp_rcvinfo)); - rcv.rcv_sid = control->sinfo_stream; - rcv.rcv_ssn = control->sinfo_ssn; - rcv.rcv_flags = control->sinfo_flags; - rcv.rcv_ppid = control->sinfo_ppid; - rcv.rcv_tsn = control->sinfo_tsn; - rcv.rcv_cumtsn = control->sinfo_cumtsn; - rcv.rcv_context = control->sinfo_context; - rcv.rcv_assoc_id = control->sinfo_assoc_id; - memset(&addr, 0, sizeof(union sctp_sockstore)); - switch (control->whoFrom->ro._l_addr.sa.sa_family) { -#ifdef INET - case AF_INET: - addr.sin = control->whoFrom->ro._l_addr.sin; - break; -#endif -#ifdef INET6 - case AF_INET6: - addr.sin6 = control->whoFrom->ro._l_addr.sin6; - break; -#endif - case AF_CONN: - addr.sconn = control->whoFrom->ro._l_addr.sconn; - break; - default: - addr.sa = control->whoFrom->ro._l_addr.sa; - break; - } - flags = 0; - if (control->end_added == 1) { - flags |= MSG_EOR; - } - if (control->spec_flags & M_NOTIFICATION) { - flags |= MSG_NOTIFICATION; - } - sctp_m_freem(control->data); - control->data = NULL; - control->tail_mbuf = NULL; - control->length = 0; - if (control->end_added) { - sctp_free_remote_addr(control->whoFrom); - control->whoFrom = NULL; - sctp_free_a_readq(stcb, control); - } else { - control->some_taken = 1; - } - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - inp->recv_callback(so, addr, buffer, length, rcv, flags, inp->ulp_info); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (inp) - SCTP_INP_READ_UNLOCK(inp); - return (0); - } + sctp_invoke_recv_callback(inp, stcb, control, inp_read_lock_held); #endif - if (inp) { - SCTP_INP_READ_UNLOCK(inp); - } if (inp && inp->sctp_socket) { - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { - SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); - } else { -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - struct socket *so; - - so = SCTP_INP_SO(inp); - if (stcb) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_SOCKET_LOCK(so, 1); - if (stcb) { - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - SCTP_SOCKET_UNLOCK(so, 1); - return (0); - } -#endif - sctp_sorwakeup(inp, inp->sctp_socket); -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - SCTP_SOCKET_UNLOCK(so, 1); -#endif - } + sctp_wakeup_the_read_socket(inp, stcb, so_locked); } - return (0); } - - /*************HOLD THIS COMMENT FOR PATCH FILE OF *************ALTERNATE ROUTING CODE */ @@ -5169,19 +5017,23 @@ sctp_generate_cause(uint16_t code, char *info) { struct mbuf *m; struct sctp_gen_error_cause *cause; - size_t info_len, len; + size_t info_len; + uint16_t len; if ((code == 0) || (info == NULL)) { return (NULL); } info_len = strlen(info); - len = sizeof(struct sctp_paramhdr) + info_len; + if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) { + return (NULL); + } + len = (uint16_t)(sizeof(struct sctp_paramhdr) + info_len); m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); if (m != NULL) { SCTP_BUF_LEN(m) = len; cause = mtod(m, struct sctp_gen_error_cause *); cause->code = htons(code); - cause->length = htons((uint16_t)len); + cause->length = htons(len); memcpy(cause->info, info, info_len); } return (m); @@ -5192,15 +5044,15 @@ sctp_generate_no_user_data_cause(uint32_t tsn) { struct mbuf *m; struct sctp_error_no_user_data *no_user_data_cause; - size_t len; + uint16_t len; - len = sizeof(struct sctp_error_no_user_data); + len = (uint16_t)sizeof(struct sctp_error_no_user_data); m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); if (m != NULL) { SCTP_BUF_LEN(m) = len; no_user_data_cause = mtod(m, struct sctp_error_no_user_data *); no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA); - no_user_data_cause->cause.length = htons((uint16_t)len); + no_user_data_cause->cause.length = htons(len); no_user_data_cause->tsn = tsn; /* tsn is passed in as NBO */ } return (m); @@ -5394,10 +5246,22 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, goto oh_well; } memset(chk, 0, sizeof(*chk)); - chk->rec.data.rcv_flags = SCTP_DATA_LAST_FRAG; + chk->rec.data.rcv_flags = 0; chk->sent = SCTP_FORWARD_TSN_SKIP; chk->asoc = &stcb->asoc; - chk->rec.data.stream_seq = strq->next_sequence_send; + if (stcb->asoc.idata_supported == 0) { + if (sp->sinfo_flags & SCTP_UNORDERED) { + chk->rec.data.stream_seq = 0; + } else { + chk->rec.data.stream_seq = strq->next_mid_ordered; + } + } else { + if (sp->sinfo_flags & SCTP_UNORDERED) { + chk->rec.data.stream_seq = strq->next_mid_unordered; + } else { + chk->rec.data.stream_seq = strq->next_mid_ordered; + } + } chk->rec.data.stream_number = sp->stream; chk->rec.data.payloadtype = sp->ppid; chk->rec.data.context = sp->context; @@ -5412,10 +5276,22 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next); stcb->asoc.sent_queue_cnt++; stcb->asoc.pr_sctp_cnt++; + } + chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; + if (sp->sinfo_flags & SCTP_UNORDERED) { + chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED; + } + if (stcb->asoc.idata_supported == 0) { + if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) { + strq->next_mid_ordered++; + } } else { - chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; + if (sp->sinfo_flags & SCTP_UNORDERED) { + strq->next_mid_unordered++; + } else { + strq->next_mid_ordered++; + } } - strq->next_sequence_send++; oh_well: if (sp->data) { /* Pull any data to free up the SB and @@ -5775,7 +5651,7 @@ sctp_sorecvmsg(struct socket *so, uint32_t rwnd_req = 0; int hold_sblock = 0; int hold_rlock = 0; - int slen = 0; + ssize_t slen = 0; uint32_t held_length = 0; #if defined(__FreeBSD__) && __FreeBSD_version >= 700000 int sockbuf_lock = 0; @@ -5842,7 +5718,7 @@ sctp_sorecvmsg(struct socket *so, #endif #else sctp_misc_ints(SCTP_SORECV_ENTER, - rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid); + rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); #endif } #if (defined(__FreeBSD__) && __FreeBSD_version < 700000) || defined(__Userspace__) @@ -5860,7 +5736,7 @@ sctp_sorecvmsg(struct socket *so, #endif #else sctp_misc_ints(SCTP_SORECV_ENTERPL, - rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid); + rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); #endif } @@ -5919,8 +5795,14 @@ sctp_sorecvmsg(struct socket *so, } } } - if ((so->so_rcv.sb_cc <= held_length) && block_allowed) { - /* we need to wait for data */ + if (so->so_rcv.sb_cc <= held_length) { + if (so->so_error) { + error = so->so_error; + if ((in_flags & MSG_PEEK) == 0) { + so->so_error = 0; + } + goto out; + } if ((so->so_rcv.sb_cc == 0) && ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { @@ -5946,46 +5828,18 @@ sctp_sorecvmsg(struct socket *so, goto out; } } - error = sbwait(&so->so_rcv); - if (error) { - goto out; - } - held_length = 0; - goto restart_nosblocks; - } else if (so->so_rcv.sb_cc == 0) { - if (so->so_error) { - error = so->so_error; - if ((in_flags & MSG_PEEK) == 0) - so->so_error = 0; - } else { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { - /* For active open side clear flags for re-use - * passive open is blocked by connect. - */ - if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { - /* You were aborted, passive side always hits here */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); - error = ECONNRESET; - } - so->so_state &= ~(SS_ISCONNECTING | - SS_ISDISCONNECTING | - SS_ISCONFIRMING | - SS_ISCONNECTED); - if (error == 0) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); - error = ENOTCONN; - } - } - goto out; - } + if (block_allowed) { + error = sbwait(&so->so_rcv); + if (error) { + goto out; } + held_length = 0; + goto restart_nosblocks; + } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK); error = EWOULDBLOCK; + goto out; } - goto out; } if (hold_sblock == 1) { SOCKBUF_UNLOCK(&so->so_rcv); @@ -6079,6 +5933,12 @@ sctp_sorecvmsg(struct socket *so, sctp_m_free (control->aux_data); control->aux_data = NULL; } +#ifdef INVARIANTS + if (control->on_strm_q) { + panic("About to free ctl:%p so:%p and its in %d", + control, so, control->on_strm_q); + } +#endif sctp_free_remote_addr(control->whoFrom); sctp_free_a_readq(stcb, control); if (hold_rlock) { @@ -6139,20 +5999,16 @@ sctp_sorecvmsg(struct socket *so, } /* Clear the held length since there is something to read */ control->held_length = 0; - if (hold_rlock) { - SCTP_INP_READ_UNLOCK(inp); - hold_rlock = 0; - } found_one: /* * If we reach here, control has a some data for us to read off. * Note that stcb COULD be NULL. */ - control->some_taken++; - if (hold_sblock) { - SOCKBUF_UNLOCK(&so->so_rcv); - hold_sblock = 0; + if (hold_rlock == 0) { + hold_rlock = 1; + SCTP_INP_READ_LOCK(inp); } + control->some_taken++; stcb = control->stcb; if (stcb) { if ((control->do_not_ref_stcb == 0) && @@ -6189,7 +6045,7 @@ sctp_sorecvmsg(struct socket *so, freed_so_far = stcb->freed_by_sorcv_sincelast; stcb->freed_by_sorcv_sincelast = 0; } - } + } if (stcb && ((control->spec_flags & M_NOTIFICATION) == 0) && control->do_not_ref_stcb == 0) { @@ -6197,8 +6053,16 @@ sctp_sorecvmsg(struct socket *so, } /* First lets get off the sinfo and sockaddr info */ - if ((sinfo) && filling_sinfo) { - memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo)); + if ((sinfo != NULL) && (filling_sinfo != 0)) { + sinfo->sinfo_stream = control->sinfo_stream; + sinfo->sinfo_ssn = (uint16_t)control->sinfo_ssn; + sinfo->sinfo_flags = control->sinfo_flags; + sinfo->sinfo_ppid = control->sinfo_ppid; + sinfo->sinfo_context =control->sinfo_context; + sinfo->sinfo_timetolive = control->sinfo_timetolive; + sinfo->sinfo_tsn = control->sinfo_tsn; + sinfo->sinfo_cumtsn = control->sinfo_cumtsn; + sinfo->sinfo_assoc_id = control->sinfo_assoc_id; nxt = TAILQ_NEXT(control, next); if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) { @@ -6323,6 +6187,14 @@ sctp_sorecvmsg(struct socket *so, #endif #endif } + if (hold_rlock) { + SCTP_INP_READ_UNLOCK(inp); + hold_rlock = 0; + } + if (hold_sblock) { + SOCKBUF_UNLOCK(&so->so_rcv); + hold_sblock = 0; + } /* now copy out what data we can */ if (mp == NULL) { /* copy out each mbuf in the chain up to length */ @@ -6369,15 +6241,8 @@ sctp_sorecvmsg(struct socket *so, /* error we are out of here */ goto release; } - if ((SCTP_BUF_NEXT(m) == NULL) && - (cp_len >= SCTP_BUF_LEN(m)) && - ((control->end_added == 0) || - (control->end_added && - (TAILQ_NEXT(control, next) == NULL))) - ) { - SCTP_INP_READ_LOCK(inp); - hold_rlock = 1; - } + SCTP_INP_READ_LOCK(inp); + hold_rlock = 1; if (cp_len == SCTP_BUF_LEN(m)) { if ((SCTP_BUF_NEXT(m)== NULL) && (control->end_added)) { @@ -6498,17 +6363,9 @@ sctp_sorecvmsg(struct socket *so, #endif } done_with_control: - if (TAILQ_NEXT(control, next) == NULL) { - /* If we don't have a next we need a - * lock, if there is a next interrupt - * is filling ahead of us and we don't - * need a lock to remove this guy - * (which is the head of the queue). - */ - if (hold_rlock == 0) { - SCTP_INP_READ_LOCK(inp); - hold_rlock = 1; - } + if (hold_rlock == 0) { + SCTP_INP_READ_LOCK(inp); + hold_rlock = 1; } TAILQ_REMOVE(&inp->read_queue, control, next); /* Add back any hiddend data */ @@ -6524,6 +6381,12 @@ sctp_sorecvmsg(struct socket *so, no_rcv_needed = control->do_not_ref_stcb; sctp_free_remote_addr(control->whoFrom); control->data = NULL; +#ifdef INVARIANTS + if (control->on_strm_q) { + panic("About to free ctl:%p so:%p and its in %d", + control, so, control->on_strm_q); + } +#endif sctp_free_a_readq(stcb, control); control = NULL; if ((freed_so_far >= rwnd_req) && @@ -6810,9 +6673,9 @@ sctp_sorecvmsg(struct socket *so, goto stage_left; #endif } - atomic_add_int(&stcb->asoc.refcnt, -1); /* Save the value back for next time */ stcb->freed_by_sorcv_sincelast = freed_so_far; + atomic_add_int(&stcb->asoc.refcnt, -1); } if (SCTP_BASE_SYSCTL(sctp_logging_level) &SCTP_RECV_RWND_LOGGING_ENABLE) { if (stcb) { @@ -6825,7 +6688,7 @@ sctp_sorecvmsg(struct socket *so, ((uio) ? (slen - uio_resid(uio)) : slen), #endif #else - ((uio) ? (slen - uio->uio_resid) : slen), + (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), #endif stcb->asoc.my_rwnd, so->so_rcv.sb_cc); @@ -6839,7 +6702,7 @@ sctp_sorecvmsg(struct socket *so, ((uio) ? (slen - uio_resid(uio)) : slen), #endif #else - ((uio) ? (slen - uio->uio_resid) : slen), + (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), #endif 0, so->so_rcv.sb_cc); @@ -7175,7 +7038,9 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, *error = EINVAL; goto out_now; } - if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, + SCTP_DONOT_SETSCOPE, + SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, @@ -7198,7 +7063,9 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, *error = EINVAL; goto out_now; } - if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, + SCTP_DONOT_SETSCOPE, + SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, @@ -7212,7 +7079,9 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, #if defined(__Userspace__) case AF_CONN: incr = sizeof(struct sockaddr_in6); - if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, + SCTP_DONOT_SETSCOPE, + SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, @@ -7234,23 +7103,23 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, struct sctp_tcb * sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, - int *totaddr, int *num_v4, int *num_v6, int *error, - int limit, int *bad_addr) + unsigned int *totaddr, + unsigned int *num_v4, unsigned int *num_v6, int *error, + unsigned int limit, int *bad_addr) { struct sockaddr *sa; struct sctp_tcb *stcb = NULL; - size_t incr, at, i; - at = incr = 0; - sa = addr; + unsigned int incr, at, i; + at = 0; + sa = addr; *error = *num_v6 = *num_v4 = 0; /* account and validate addresses */ - for (i = 0; i < (size_t)*totaddr; i++) { + for (i = 0; i < *totaddr; i++) { switch (sa->sa_family) { #ifdef INET case AF_INET: - (*num_v4) += 1; - incr = sizeof(struct sockaddr_in); + incr = (unsigned int)sizeof(struct sockaddr_in); #ifdef HAVE_SA_LEN if (sa->sa_len != incr) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); @@ -7259,6 +7128,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, return (NULL); } #endif + (*num_v4) += 1; break; #endif #ifdef INET6 @@ -7274,8 +7144,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, *bad_addr = 1; return (NULL); } - (*num_v6) += 1; - incr = sizeof(struct sockaddr_in6); + incr = (unsigned int)sizeof(struct sockaddr_in6); #ifdef HAVE_SA_LEN if (sa->sa_len != incr) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); @@ -7284,15 +7153,17 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, return (NULL); } #endif + (*num_v6) += 1; break; } #endif default: *totaddr = i; + incr = 0; /* we are done */ break; } - if (i == (size_t)*totaddr) { + if (i == *totaddr) { break; } SCTP_INP_INCR_REF(inp); @@ -7303,7 +7174,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, } else { SCTP_INP_DECR_REF(inp); } - if ((at + incr) > (size_t)limit) { + if ((at + incr) > limit) { *totaddr = i; break; } @@ -7404,7 +7275,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, } #endif if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { -#if !(defined(__Panda__) || defined(__Windows__)) +#if !(defined(__Panda__) || defined(__Windows__) || defined(__Userspace__)) if (p == NULL) { /* Can't get proc for Net/Open BSD */ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); @@ -7899,6 +7770,293 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, } #endif +#if __FreeBSD_version >= 1100000 +#ifdef INET +static void +sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED) +{ + struct ip *outer_ip, *inner_ip; + struct sctphdr *sh; + struct icmp *icmp; + struct udphdr *udp; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; + struct sctp_init_chunk *ch; + struct sockaddr_in src, dst; + uint8_t type, code; + + inner_ip = (struct ip *)vip; + icmp = (struct icmp *)((caddr_t)inner_ip - + (sizeof(struct icmp) - sizeof(struct ip))); + outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); + if (ntohs(outer_ip->ip_len) < + sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) { + return; + } + udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); + sh = (struct sctphdr *)(udp + 1); + memset(&src, 0, sizeof(struct sockaddr_in)); + src.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + src.sin_len = sizeof(struct sockaddr_in); +#endif + src.sin_port = sh->src_port; + src.sin_addr = inner_ip->ip_src; + memset(&dst, 0, sizeof(struct sockaddr_in)); + dst.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); +#endif + dst.sin_port = sh->dest_port; + dst.sin_addr = inner_ip->ip_dst; + /* + * 'dst' holds the dest of the packet that failed to be sent. + * 'src' holds our local endpoint address. Thus we reverse + * the dst and the src in the lookup. + */ + inp = NULL; + net = NULL; + stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, + (struct sockaddr *)&src, + &inp, &net, 1, + SCTP_DEFAULT_VRFID); + if ((stcb != NULL) && + (net != NULL) && + (inp != NULL)) { + /* Check the UDP port numbers */ + if ((udp->uh_dport != net->port) || + (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { + SCTP_TCB_UNLOCK(stcb); + return; + } + /* Check the verification tag */ + if (ntohl(sh->v_tag) != 0) { + /* + * This must be the verification tag used + * for sending out packets. We don't + * consider packets reflecting the + * verification tag. + */ + if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { + SCTP_TCB_UNLOCK(stcb); + return; + } + } else { + if (ntohs(outer_ip->ip_len) >= + sizeof(struct ip) + + 8 + (inner_ip->ip_hl << 2) + 8 + 20) { + /* + * In this case we can check if we + * got an INIT chunk and if the + * initiate tag matches. + */ + ch = (struct sctp_init_chunk *)(sh + 1); + if ((ch->ch.chunk_type != SCTP_INITIATION) || + (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { + SCTP_TCB_UNLOCK(stcb); + return; + } + } else { + SCTP_TCB_UNLOCK(stcb); + return; + } + } + type = icmp->icmp_type; + code = icmp->icmp_code; + if ((type == ICMP_UNREACH) && + (code == ICMP_UNREACH_PORT)) { + code = ICMP_UNREACH_PROTOCOL; + } + sctp_notify(inp, stcb, net, type, code, + ntohs(inner_ip->ip_len), + ntohs(icmp->icmp_nextmtu)); + } else { +#if defined(__FreeBSD__) && __FreeBSD_version < 500000 + /* + * XXX must be fixed for 5.x and higher, leave for + * 4.x + */ + if (PRC_IS_REDIRECT(cmd) && (inp != NULL)) { + in_rtchange((struct inpcb *)inp, + inetctlerrmap[cmd]); + } +#endif + if ((stcb == NULL) && (inp != NULL)) { + /* reduce ref-count */ + SCTP_INP_WLOCK(inp); + SCTP_INP_DECR_REF(inp); + SCTP_INP_WUNLOCK(inp); + } + if (stcb) { + SCTP_TCB_UNLOCK(stcb); + } + } + return; +} +#endif + +#ifdef INET6 +static void +sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED) +{ + struct ip6ctlparam *ip6cp; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; + struct sctphdr sh; + struct udphdr udp; + struct sockaddr_in6 src, dst; + uint8_t type, code; + + ip6cp = (struct ip6ctlparam *)d; + /* + * XXX: We assume that when IPV6 is non NULL, M and OFF are + * valid. + */ + if (ip6cp->ip6c_m == NULL) { + return; + } + /* Check if we can safely examine the ports and the + * verification tag of the SCTP common header. + */ + if (ip6cp->ip6c_m->m_pkthdr.len < + ip6cp->ip6c_off + sizeof(struct udphdr)+ offsetof(struct sctphdr, checksum)) { + return; + } + /* Copy out the UDP header. */ + memset(&udp, 0, sizeof(struct udphdr)); + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off, + sizeof(struct udphdr), + (caddr_t)&udp); + /* Copy out the port numbers and the verification tag. */ + memset(&sh, 0, sizeof(struct sctphdr)); + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + sizeof(struct udphdr), + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), + (caddr_t)&sh); + memset(&src, 0, sizeof(struct sockaddr_in6)); + src.sin6_family = AF_INET6; +#ifdef HAVE_SIN6_LEN + src.sin6_len = sizeof(struct sockaddr_in6); +#endif + src.sin6_port = sh.src_port; + src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; +#if defined(__FreeBSD__) + if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { + return; + } +#endif + memset(&dst, 0, sizeof(struct sockaddr_in6)); + dst.sin6_family = AF_INET6; +#ifdef HAVE_SIN6_LEN + dst.sin6_len = sizeof(struct sockaddr_in6); +#endif + dst.sin6_port = sh.dest_port; + dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; +#if defined(__FreeBSD__) + if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { + return; + } +#endif + inp = NULL; + net = NULL; + stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, + (struct sockaddr *)&src, + &inp, &net, 1, SCTP_DEFAULT_VRFID); + if ((stcb != NULL) && + (net != NULL) && + (inp != NULL)) { + /* Check the UDP port numbers */ + if ((udp.uh_dport != net->port) || + (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { + SCTP_TCB_UNLOCK(stcb); + return; + } + /* Check the verification tag */ + if (ntohl(sh.v_tag) != 0) { + /* + * This must be the verification tag used for + * sending out packets. We don't consider + * packets reflecting the verification tag. + */ + if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { + SCTP_TCB_UNLOCK(stcb); + return; + } + } else { +#if defined(__FreeBSD__) + if (ip6cp->ip6c_m->m_pkthdr.len >= + ip6cp->ip6c_off + sizeof(struct udphdr) + + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr) + + offsetof(struct sctp_init, a_rwnd)) { + /* + * In this case we can check if we + * got an INIT chunk and if the + * initiate tag matches. + */ + uint32_t initiate_tag; + uint8_t chunk_type; + + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + + sizeof(struct udphdr) + + sizeof(struct sctphdr), + sizeof(uint8_t), + (caddr_t)&chunk_type); + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + + sizeof(struct udphdr) + + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr), + sizeof(uint32_t), + (caddr_t)&initiate_tag); + if ((chunk_type != SCTP_INITIATION) || + (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { + SCTP_TCB_UNLOCK(stcb); + return; + } + } else { + SCTP_TCB_UNLOCK(stcb); + return; + } +#else + SCTP_TCB_UNLOCK(stcb); + return; +#endif + } + type = ip6cp->ip6c_icmp6->icmp6_type; + code = ip6cp->ip6c_icmp6->icmp6_code; + if ((type == ICMP6_DST_UNREACH) && + (code == ICMP6_DST_UNREACH_NOPORT)) { + type = ICMP6_PARAM_PROB; + code = ICMP6_PARAMPROB_NEXTHEADER; + } + sctp6_notify(inp, stcb, net, type, code, + (uint16_t)ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); + } else { +#if defined(__FreeBSD__) && __FreeBSD_version < 500000 + if (PRC_IS_REDIRECT(cmd) && (inp != NULL)) { + in6_rtchange((struct in6pcb *)inp, + inet6ctlerrmap[cmd]); + } +#endif + if ((stcb == NULL) && (inp != NULL)) { + /* reduce inp's ref-count */ + SCTP_INP_WLOCK(inp); + SCTP_INP_DECR_REF(inp); + SCTP_INP_WUNLOCK(inp); + } + if (stcb) { + SCTP_TCB_UNLOCK(stcb); + } + } +} +#endif +#endif + void sctp_over_udp_stop(void) { @@ -7960,7 +8118,11 @@ sctp_over_udp_start(void) } /* Call the special UDP hook. */ if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket), - sctp_recv_udp_tunneled_packet, NULL))) { + sctp_recv_udp_tunneled_packet, +#if __FreeBSD_version >= 1100000 + sctp_recv_icmp_tunneled_packet, +#endif + NULL))) { sctp_over_udp_stop(); return (ret); } @@ -7984,7 +8146,11 @@ sctp_over_udp_start(void) } /* Call the special UDP hook. */ if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket), - sctp_recv_udp_tunneled_packet, NULL))) { + sctp_recv_udp_tunneled_packet, +#if __FreeBSD_version >= 1100000 + sctp_recv_icmp6_tunneled_packet, +#endif + NULL))) { sctp_over_udp_stop(); return (ret); } diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctputil.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctputil.h index 2276177e933..9665d487eec 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctputil.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctputil.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 291904 2015-12-06 16:17:57Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 298508 2016-04-23 09:15:58Z tuexen $"); #endif #ifndef _NETINET_SCTP_UTIL_H_ @@ -107,6 +107,21 @@ void sctp_mtu_size_reset(struct sctp_inpcb *, struct sctp_association *, uint32_t); void +sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, struct sctp_tcb *stcb, + int so_locked +#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) + SCTP_UNUSED +#endif +); + +#if defined(__Userspace__) +void sctp_invoke_recv_callback(struct sctp_inpcb *, + struct sctp_tcb *, + struct sctp_queued_to_read *, + int); + +#endif +void sctp_add_to_readq(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_queued_to_read *control, @@ -119,16 +134,6 @@ sctp_add_to_readq(struct sctp_inpcb *inp, #endif ); -int -sctp_append_to_readq(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_queued_to_read *control, - struct mbuf *m, - int end, - int new_cumack, - struct sockbuf *sb); - - void sctp_iterator_worker(void); uint32_t sctp_get_prev_mtu(uint32_t); @@ -218,7 +223,8 @@ int sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, struct sctp_tcb * sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, - int *totaddr, int *num_v4, int *num_v6, int *error, int limit, int *bad_addr); + unsigned int *totaddr, unsigned int *num_v4, unsigned int *num_v6, + int *error, unsigned int limit, int *bad_addr); int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *); #ifdef INET6 @@ -395,7 +401,7 @@ void sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc void sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from); void sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *, int, int, uint8_t); -void sctp_log_block(uint8_t, struct sctp_association *, int); +void sctp_log_block(uint8_t, struct sctp_association *, size_t); void sctp_log_rwnd(uint8_t, uint32_t, uint32_t, uint32_t); void sctp_log_rwnd_set(uint8_t, uint32_t, uint32_t, uint32_t, uint32_t); int sctp_fill_stat_log(void *, size_t *); diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet6/sctp6_usrreq.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet6/sctp6_usrreq.c index 25eebbf5323..f46850f17fc 100644 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet6/sctp6_usrreq.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet6/sctp6_usrreq.c @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 291904 2015-12-06 16:17:57Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 302138 2016-06-23 09:13:15Z tuexen $"); #endif #include <netinet/sctp_os.h> @@ -349,279 +349,247 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED) } #endif -#if defined(__Panda__) -void -#else -static void -#endif -sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6, - struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net) -{ - uint32_t nxtsz; - - if ((inp == NULL) || (stcb == NULL) || (net == NULL) || - (icmp6 == NULL) || (sh == NULL)) { - goto out; - } - /* First do we even look at it? */ - if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) - goto out; - - if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) { - /* not PACKET TO BIG */ - goto out; - } - /* - * ok we need to look closely. We could even get smarter and look at - * anyone that we sent to in case we get a different ICMP that tells - * us there is no way to reach a host, but for this impl, all we - * care about is MTU discovery. - */ - nxtsz = ntohl(icmp6->icmp6_mtu); - /* Stop any PMTU timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, - SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1); - - /* Adjust destination size limit */ - if (net->mtu > nxtsz) { - net->mtu = nxtsz; - if (net->port) { - net->mtu -= sizeof(struct udphdr); - } - } - /* now what about the ep? */ - if (stcb->asoc.smallest_mtu > nxtsz) { - struct sctp_tmit_chunk *chk; - - /* Adjust that too */ - stcb->asoc.smallest_mtu = nxtsz; - /* now off to subtract IP_DF flag if needed */ - - TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { - if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - } - } - TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { - if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { - /* - * For this guy we also mark for immediate - * resend since we sent to big of chunk - */ - chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; - if (chk->sent != SCTP_DATAGRAM_RESEND) - stcb->asoc.sent_queue_retran_cnt++; - chk->sent = SCTP_DATAGRAM_RESEND; - chk->rec.data.doing_fast_retransmit = 0; - - chk->sent = SCTP_DATAGRAM_RESEND; - /* Clear any time so NO RTT is being done */ - chk->sent_rcv_time.tv_sec = 0; - chk->sent_rcv_time.tv_usec = 0; - stcb->asoc.total_flight -= chk->send_size; - net->flight_size -= chk->send_size; - } - } - } - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); -out: - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } -} -#endif - - void sctp6_notify(struct sctp_inpcb *inp, - struct icmp6_hdr *icmph, - struct sctphdr *sh, - struct sockaddr *to, - struct sctp_tcb *stcb, - struct sctp_nets *net) + struct sctp_tcb *stcb, + struct sctp_nets *net, + uint8_t icmp6_type, + uint8_t icmp6_code, + uint16_t next_mtu) { #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) struct socket *so; - #endif - - /* protection */ - if ((inp == NULL) || (stcb == NULL) || (net == NULL) || - (sh == NULL) || (to == NULL)) { - if (stcb) - SCTP_TCB_UNLOCK(stcb); - return; - } - /* First job is to verify the vtag matches what I would send */ - if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { - SCTP_TCB_UNLOCK(stcb); - return; - } - if (icmph->icmp6_type != ICMP_UNREACH) { - /* We only care about unreachable */ - SCTP_TCB_UNLOCK(stcb); - return; - } - if ((icmph->icmp6_code == ICMP_UNREACH_NET) || - (icmph->icmp6_code == ICMP_UNREACH_HOST) || - (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) || - (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) || - (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) || - (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) || - (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) || -#if defined(__Panda__) - (icmph->icmp6_code == ICMP_UNREACH_ADMIN)) { -#elif defined(__Userspace_os_NetBSD) - (icmph->icmp6_code == ICMP_UNREACH_ADMIN_PROHIBIT)) { -#else - (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) { -#endif - - /* - * Hmm reachablity problems we must examine closely. If its - * not reachable, we may have lost a network. Or if there is - * NO protocol at the other end named SCTP. well we consider - * it a OOTB abort. - */ - if (net->dest_state & SCTP_ADDR_REACHABLE) { - /* Ok that destination is NOT reachable */ - net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state &= ~SCTP_ADDR_PF; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, - stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED); + int timer_stopped; + + switch (icmp6_type) { + case ICMP6_DST_UNREACH: + if ((icmp6_code == ICMP6_DST_UNREACH_NOROUTE) || + (icmp6_code == ICMP6_DST_UNREACH_ADMIN) || + (icmp6_code == ICMP6_DST_UNREACH_BEYONDSCOPE) || + (icmp6_code == ICMP6_DST_UNREACH_ADDR)) { + /* Mark the net unreachable. */ + if (net->dest_state & SCTP_ADDR_REACHABLE) { + /* Ok that destination is not reachable */ + net->dest_state &= ~SCTP_ADDR_REACHABLE; + net->dest_state &= ~SCTP_ADDR_PF; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, + stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED); + } } SCTP_TCB_UNLOCK(stcb); - } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) || - (icmph->icmp6_code == ICMP_UNREACH_PORT)) { - /* - * Here the peer is either playing tricks on us, - * including an address that belongs to someone who - * does not support SCTP OR was a userland - * implementation that shutdown and now is dead. In - * either case treat it like a OOTB abort with no - * TCB - */ - sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); + break; + case ICMP6_PARAM_PROB: + /* Treat it like an ABORT. */ + if (icmp6_code == ICMP6_PARAMPROB_NEXTHEADER) { + sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); + so = SCTP_INP_SO(inp); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_SOCKET_LOCK(so, 1); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_2); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - SCTP_SOCKET_UNLOCK(so, 1); - /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/ + SCTP_SOCKET_UNLOCK(so, 1); #endif - /* no need to unlock here, since the TCB is gone */ - } else { + } else { + SCTP_TCB_UNLOCK(stcb); + } + break; + case ICMP6_PACKET_TOO_BIG: + if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { + timer_stopped = 1; + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); + } else { + timer_stopped = 0; + } + /* Update the path MTU. */ + if (net->mtu > next_mtu) { + net->mtu = next_mtu; + if (net->port) { + net->mtu -= sizeof(struct udphdr); + } + } + /* Update the association MTU */ + if (stcb->asoc.smallest_mtu > next_mtu) { + sctp_pathmtu_adjustment(stcb, next_mtu); + } + /* Finally, start the PMTU timer if it was running before. */ + if (timer_stopped) { + sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); + } + SCTP_TCB_UNLOCK(stcb); + break; + default: SCTP_TCB_UNLOCK(stcb); + break; } } - - -#if !defined(__Panda__) && !defined(__Userspace__) void sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) { + struct ip6ctlparam *ip6cp; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; struct sctphdr sh; - struct ip6ctlparam *ip6cp = NULL; - uint32_t vrf_id; - -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) - vrf_id = SCTP_DEFAULT_VRFID; -#endif + struct sockaddr_in6 src, dst; #ifdef HAVE_SA_LEN if (pktdst->sa_family != AF_INET6 || - pktdst->sa_len != sizeof(struct sockaddr_in6)) + pktdst->sa_len != sizeof(struct sockaddr_in6)) { #else - if (pktdst->sa_family != AF_INET6) + if (pktdst->sa_family != AF_INET6) { #endif return; + } - if ((unsigned)cmd >= PRC_NCMDS) + if ((unsigned)cmd >= PRC_NCMDS) { return; + } if (PRC_IS_REDIRECT(cmd)) { d = NULL; } else if (inet6ctlerrmap[cmd] == 0) { return; } - /* if the parameter is from icmp6, decode it. */ + /* If the parameter is from icmp6, decode it. */ if (d != NULL) { ip6cp = (struct ip6ctlparam *)d; } else { ip6cp = (struct ip6ctlparam *)NULL; } - if (ip6cp) { + if (ip6cp != NULL) { /* * XXX: We assume that when IPV6 is non NULL, M and OFF are * valid. */ - /* check if we can safely examine src and dst ports */ - struct sctp_inpcb *inp = NULL; - struct sctp_tcb *stcb = NULL; - struct sctp_nets *net = NULL; - struct sockaddr_in6 final; + if (ip6cp->ip6c_m == NULL) { + return; + } - if (ip6cp->ip6c_m == NULL) + /* Check if we can safely examine the ports and the + * verification tag of the SCTP common header. + */ + if (ip6cp->ip6c_m->m_pkthdr.len < + (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) { return; + } + /* Copy out the port numbers and the verification tag. */ bzero(&sh, sizeof(sh)); - bzero(&final, sizeof(final)); - inp = NULL; - net = NULL; - m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh), - (caddr_t)&sh); - ip6cp->ip6c_src->sin6_port = sh.src_port; + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off, + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), + (caddr_t)&sh); + memset(&src, 0, sizeof(struct sockaddr_in6)); + src.sin6_family = AF_INET6; #ifdef HAVE_SIN6_LEN - final.sin6_len = sizeof(final); + src.sin6_len = sizeof(struct sockaddr_in6); #endif - final.sin6_family = AF_INET6; -#if defined(__FreeBSD__) && __FreeBSD_cc_version < 440000 - final.sin6_addr = *ip6cp->ip6c_finaldst; -#else - final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr; -#endif /* __FreeBSD_cc_version */ - final.sin6_port = sh.dest_port; - stcb = sctp_findassociation_addr_sa((struct sockaddr *)&final, - (struct sockaddr *)ip6cp->ip6c_src, - &inp, &net, 1, vrf_id); - /* inp's ref-count increased && stcb locked */ - if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { - if (cmd == PRC_MSGSIZE) { - sctp6_notify_mbuf(inp, - ip6cp->ip6c_icmp6, - &sh, - stcb, - net); - /* inp's ref-count reduced && stcb unlocked */ + src.sin6_port = sh.src_port; + src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; +#if defined(__FreeBSD__) + if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { + return; + } +#endif + memset(&dst, 0, sizeof(struct sockaddr_in6)); + dst.sin6_family = AF_INET6; +#ifdef HAVE_SIN6_LEN + dst.sin6_len = sizeof(struct sockaddr_in6); +#endif + dst.sin6_port = sh.dest_port; + dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; +#if defined(__FreeBSD__) + if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { + return; + } +#endif + inp = NULL; + net = NULL; + stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, + (struct sockaddr *)&src, + &inp, &net, 1, SCTP_DEFAULT_VRFID); + if ((stcb != NULL) && + (net != NULL) && + (inp != NULL)) { + /* Check the verification tag */ + if (ntohl(sh.v_tag) != 0) { + /* + * This must be the verification tag used for + * sending out packets. We don't consider + * packets reflecting the verification tag. + */ + if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { + SCTP_TCB_UNLOCK(stcb); + return; + } } else { - sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh, - (struct sockaddr *)&final, - stcb, net); - /* inp's ref-count reduced && stcb unlocked */ +#if defined(__FreeBSD__) + if (ip6cp->ip6c_m->m_pkthdr.len >= + ip6cp->ip6c_off + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr) + + offsetof(struct sctp_init, a_rwnd)) { + /* + * In this case we can check if we + * got an INIT chunk and if the + * initiate tag matches. + */ + uint32_t initiate_tag; + uint8_t chunk_type; + + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + + sizeof(struct sctphdr), + sizeof(uint8_t), + (caddr_t)&chunk_type); + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr), + sizeof(uint32_t), + (caddr_t)&initiate_tag); + if ((chunk_type != SCTP_INITIATION) || + (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { + SCTP_TCB_UNLOCK(stcb); + return; + } + } else { + SCTP_TCB_UNLOCK(stcb); + return; + } +#else + SCTP_TCB_UNLOCK(stcb); + return; +#endif } + sctp6_notify(inp, stcb, net, + ip6cp->ip6c_icmp6->icmp6_type, + ip6cp->ip6c_icmp6->icmp6_code, + (uint16_t)ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); } else { -#if !defined(__Windows__) - if (PRC_IS_REDIRECT(cmd) && inp) { +#if defined(__FreeBSD__) && __FreeBSD_version < 500000 + if (PRC_IS_REDIRECT(cmd) && (inp != NULL)) { in6_rtchange((struct in6pcb *)inp, inet6ctlerrmap[cmd]); } #endif - if (inp) { + if ((stcb == NULL) && (inp != NULL)) { /* reduce inp's ref-count */ SCTP_INP_WLOCK(inp); SCTP_INP_DECR_REF(inp); SCTP_INP_WUNLOCK(inp); } - if (stcb) + if (stcb) { SCTP_TCB_UNLOCK(stcb); + } } } } @@ -1312,7 +1280,9 @@ sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p) return (EALREADY); } /* We are GOOD to go */ - stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, p); + stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, + inp->sctp_ep.pre_open_stream_count, + inp->sctp_ep.port, p); SCTP_ASOC_CREATE_UNLOCK(inp); if (stcb == NULL) { /* Gak! no memory */ @@ -1393,7 +1363,12 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam) int fnd; stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb == NULL) { - goto notConn6; + SCTP_INP_RUNLOCK(inp); +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) + SCTP_FREE_SONAME(sin6); +#endif + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); + return (ENOENT); } fnd = 0; sin_a6 = NULL; @@ -1410,7 +1385,12 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam) } if ((!fnd) || (sin_a6 == NULL)) { /* punt */ - goto notConn6; + SCTP_INP_RUNLOCK(inp); +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) + SCTP_FREE_SONAME(sin6); +#endif + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); + return (ENOENT); } vrf_id = inp->def_vrf_id; sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *)&net->ro, net, 0, vrf_id); @@ -1419,7 +1399,6 @@ sctp6_getaddr(struct socket *so, struct mbuf *nam) } } else { /* For the bound all case you get back 0 */ - notConn6: memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); } } else { @@ -1572,9 +1551,6 @@ sctp6_peeraddr(struct socket *so, struct mbuf *nam) static int sctp6_in6getaddr(struct socket *so, struct sockaddr **nam) { -#ifdef INET - struct sockaddr *addr; -#endif #elif defined(__Panda__) int sctp6_in6getaddr(struct socket *so, struct sockaddr *nam, uint32_t *namelen) @@ -1607,21 +1583,31 @@ sctp6_in6getaddr(struct socket *so, struct mbuf *nam) error = sctp6_getaddr(so, nam); #ifdef INET if (error) { +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) + struct sockaddr_in6 *sin6; +#else + struct sockaddr_in6 sin6; +#endif + /* try v4 next if v6 failed */ error = sctp_ingetaddr(so, nam); if (error) { return (error); } #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) - addr = *nam; -#endif - /* if I'm V6ONLY, convert it to v4-mapped */ - if (SCTP_IPV6_V6ONLY(inp6)) { - struct sockaddr_in6 sin6; - - in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); - memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); + SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); + if (sin6 == NULL) { + SCTP_FREE_SONAME(*nam); + return (ENOMEM); } + in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6); + SCTP_FREE_SONAME(*nam); + *nam = (struct sockaddr *)sin6; +#else + in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); + SCTP_BUF_LEN(nam) = sizeof(struct sockaddr_in6); + memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); +#endif } #endif #if defined(__Panda__) @@ -1635,9 +1621,6 @@ sctp6_in6getaddr(struct socket *so, struct mbuf *nam) static int sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam) { -#ifdef INET - struct sockaddr *addr; -#endif #elif defined(__Panda__) int sctp6_getpeeraddr(struct socket *so, struct sockaddr *nam, uint32_t *namelen) @@ -1672,21 +1655,31 @@ sctp6_getpeeraddr(struct socket *so, struct mbuf *nam) error = sctp6_peeraddr(so, nam); #ifdef INET if (error) { +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) + struct sockaddr_in6 *sin6; +#else + struct sockaddr_in6 sin6; +#endif + /* try v4 next if v6 failed */ error = sctp_peeraddr(so, nam); if (error) { return (error); } #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) - addr = *nam; -#endif - /* if I'm V6ONLY, convert it to v4-mapped */ - if (SCTP_IPV6_V6ONLY(inp6)) { - struct sockaddr_in6 sin6; - - in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); - memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); + SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); + if (sin6 == NULL) { + SCTP_FREE_SONAME(*nam); + return (ENOMEM); } + in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6); + SCTP_FREE_SONAME(*nam); + *nam = (struct sockaddr *)sin6; +#else + in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); + SCTP_BUF_LEN(nam) = sizeof(struct sockaddr_in6); + memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); +#endif } #endif #if defined(__Panda__) diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet6/sctp6_var.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet6/sctp6_var.h index 3402bc08cd7..1ef58d29e2b 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet6/sctp6_var.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/netinet6/sctp6_var.h @@ -32,7 +32,7 @@ #ifdef __FreeBSD__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_var.h 243186 2012-11-17 20:04:04Z tuexen $"); +__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_var.h 298132 2016-04-16 21:34:49Z tuexen $"); #endif #ifndef _NETINET6_SCTP6_VAR_H_ @@ -81,8 +81,7 @@ extern void in6_sin_2_v4mapsin6(struct sockaddr_in *, struct sockaddr_in6 *); extern void in6_sin6_2_sin(struct sockaddr_in *, struct sockaddr_in6 *); extern void in6_sin6_2_sin_in_sock(struct sockaddr *); #endif -extern void sctp6_notify(struct sctp_inpcb *, struct icmp6_hdr *, - struct sctphdr *, struct sockaddr *, - struct sctp_tcb *, struct sctp_nets *); +void sctp6_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, + uint8_t, uint8_t, uint16_t); #endif #endif diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_mbuf.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_mbuf.c index ddc371c3c8f..9a827463712 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_mbuf.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_mbuf.c @@ -732,7 +732,7 @@ m_pullup(struct mbuf *n, int len) if (n->m_flags & M_PKTHDR) M_MOVE_PKTHDR(m, n); } - space = &m->m_dat[MLEN] - (m->m_data + m->m_len); + space = (int)(&m->m_dat[MLEN] - (m->m_data + m->m_len)); do { count = min(min(max(len, max_protohdr), space), n->m_len); bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_recv_thread.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_recv_thread.c index 650029964c7..103bd9fdd87 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_recv_thread.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_recv_thread.c @@ -92,51 +92,36 @@ static void sctp_handle_ifamsg(unsigned char type, unsigned short index, struct sockaddr *sa) { int rc; - struct ifaddrs *ifa, *found_ifa = NULL; + struct ifaddrs *ifa, *ifas; /* handle only the types we want */ if ((type != RTM_NEWADDR) && (type != RTM_DELADDR)) { return; } - rc = getifaddrs(&g_interfaces); + rc = getifaddrs(&ifas); if (rc != 0) { return; } - for (ifa = g_interfaces; ifa; ifa = ifa->ifa_next) { + for (ifa = ifas; ifa; ifa = ifa->ifa_next) { if (index == if_nametoindex(ifa->ifa_name)) { - found_ifa = ifa; break; } } - if (found_ifa == NULL) { + if (ifa == NULL) { + freeifaddrs(ifas); return; } - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - ifa->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in)); - memcpy(ifa->ifa_addr, sa, sizeof(struct sockaddr_in)); - break; -#endif -#ifdef INET6 - case AF_INET6: - ifa->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in6)); - memcpy(ifa->ifa_addr, sa, sizeof(struct sockaddr_in6)); - break; -#endif - default: - SCTPDBG(SCTP_DEBUG_USR, "Address family %d not supported.\n", sa->sa_family); - } - /* relay the appropriate address change to the base code */ if (type == RTM_NEWADDR) { - (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, ifa, if_nametoindex(ifa->ifa_name), + (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, + NULL, + if_nametoindex(ifa->ifa_name), 0, ifa->ifa_name, - (void *)ifa, - ifa->ifa_addr, + NULL, + sa, 0, 1); } else { @@ -144,6 +129,7 @@ sctp_handle_ifamsg(unsigned char type, unsigned short index, struct sockaddr *sa if_nametoindex(ifa->ifa_name), ifa->ifa_name); } + freeifaddrs(ifas); } static void * @@ -422,7 +408,10 @@ recv_function_raw(void *arg) #if defined(SCTP_WITH_NO_CSUM) SCTP_STAT_INCR(sctps_recvnocrc); #else - if (src.sin_addr.s_addr == dst.sin_addr.s_addr) { + if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + ((IN4_ISLOOPBACK_ADDRESS(&src.sin_addr) && + IN4_ISLOOPBACK_ADDRESS(&dst.sin_addr)) || + (src.sin_addr.s_addr == dst.sin_addr.s_addr))) { compute_crc = 0; SCTP_STAT_INCR(sctps_recvnocrc); } else { @@ -1053,8 +1042,13 @@ recv_function_udp6(void *arg) } #endif +#if defined (__Userspace_os_Windows) +static void +setReceiveBufferSize(SOCKET sfd, int new_size) +#else static void setReceiveBufferSize(int sfd, int new_size) +#endif { int ch = new_size; @@ -1068,8 +1062,13 @@ setReceiveBufferSize(int sfd, int new_size) return; } +#if defined (__Userspace_os_Windows) +static void +setSendBufferSize(SOCKET sfd, int new_size) +#else static void setSendBufferSize(int sfd, int new_size) +#endif { int ch = new_size; @@ -1108,7 +1107,7 @@ recv_thread_init(void) #endif #if defined(__Userspace_os_Darwin) || defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD) if (SCTP_BASE_VAR(userspace_route) == -1) { - if ((SCTP_BASE_VAR(userspace_route) = socket(AF_ROUTE, SOCK_RAW, 0)) < 0) { + if ((SCTP_BASE_VAR(userspace_route) = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { SCTPDBG(SCTP_DEBUG_USR, "Can't create routing socket (errno = %d).\n", errno); } #if 0 @@ -1147,7 +1146,7 @@ recv_thread_init(void) #endif #if defined(INET) if (SCTP_BASE_VAR(userspace_rawsctp) == -1) { - if ((SCTP_BASE_VAR(userspace_rawsctp) = socket(AF_INET, SOCK_RAW, IPPROTO_SCTP)) < 0) { + if ((SCTP_BASE_VAR(userspace_rawsctp) = socket(AF_INET, SOCK_RAW, IPPROTO_SCTP)) == -1) { #if defined(__Userspace_os_Windows) SCTPDBG(SCTP_DEBUG_USR, "Can't create raw socket for IPv4 (errno = %d).\n", WSAGetLastError()); #else @@ -1198,7 +1197,7 @@ recv_thread_init(void) } } if (SCTP_BASE_VAR(userspace_udpsctp) == -1) { - if ((SCTP_BASE_VAR(userspace_udpsctp) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + if ((SCTP_BASE_VAR(userspace_udpsctp) = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { #if defined(__Userspace_os_Windows) SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv4 (errno = %d).\n", WSAGetLastError()); #else @@ -1262,7 +1261,7 @@ recv_thread_init(void) #endif #if defined(INET6) if (SCTP_BASE_VAR(userspace_rawsctp6) == -1) { - if ((SCTP_BASE_VAR(userspace_rawsctp6) = socket(AF_INET6, SOCK_RAW, IPPROTO_SCTP)) < 0) { + if ((SCTP_BASE_VAR(userspace_rawsctp6) = socket(AF_INET6, SOCK_RAW, IPPROTO_SCTP)) == -1) { #if defined(__Userspace_os_Windows) SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/IPv6 (errno = %d).\n", WSAGetLastError()); #else @@ -1335,7 +1334,7 @@ recv_thread_init(void) } } if (SCTP_BASE_VAR(userspace_udpsctp6) == -1) { - if ((SCTP_BASE_VAR(userspace_udpsctp6) = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + if ((SCTP_BASE_VAR(userspace_udpsctp6) = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) { #if defined(__Userspace_os_Windows) SCTPDBG(SCTP_DEBUG_USR, "Can't create socket for SCTP/UDP/IPv6 (errno = %d).\n", WSAGetLastError()); #else diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_socket.c b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_socket.c index 9f13cb249e3..d6d1534d1be 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_socket.c +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_socket.c @@ -581,13 +581,13 @@ struct sctp_generic_recvmsg_args { Source: /src/sys/gnu/fs/xfs/FreeBSD/xfs_ioctl.c */ static __inline__ int -copy_to_user(void *dst, void *src, int len) { +copy_to_user(void *dst, void *src, size_t len) { memcpy(dst, src, len); return 0; } static __inline__ int -copy_from_user(void *dst, void *src, int len) { +copy_from_user(void *dst, void *src, size_t len) { memcpy(dst, src, len); return 0; } @@ -631,7 +631,7 @@ int uiomove(void *cp, int n, struct uio *uio) { struct iovec *iov; - int cnt; + size_t cnt; int error = 0; if ((uio->uio_rw != UIO_READ) && @@ -647,7 +647,7 @@ uiomove(void *cp, int n, struct uio *uio) uio->uio_iovcnt--; continue; } - if (cnt > n) + if (cnt > (size_t)n) cnt = n; switch (uio->uio_segflg) { @@ -671,9 +671,9 @@ uiomove(void *cp, int n, struct uio *uio) iov->iov_base = (char *)iov->iov_base + cnt; iov->iov_len -= cnt; uio->uio_resid -= cnt; - uio->uio_offset += cnt; + uio->uio_offset += (off_t)cnt; cp = (char *)cp + cnt; - n -= cnt; + n -= (int)cnt; } out: return (error); @@ -707,6 +707,52 @@ getsockaddr(namp, uaddr, len) return (error); } +int +usrsctp_getsockopt(struct socket *so, int level, int option_name, + void *option_value, socklen_t *option_len); + +sctp_assoc_t +usrsctp_getassocid(struct socket *sock, struct sockaddr *sa) +{ + struct sctp_paddrinfo sp; + socklen_t siz; +#ifndef HAVE_SA_LEN + size_t sa_len; +#endif + + /* First get the assoc id */ + siz = sizeof(sp); + memset(&sp, 0, sizeof(sp)); +#ifdef HAVE_SA_LEN + memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len); +#else + switch (sa->sa_family) { +#ifdef INET + case AF_INET: + sa_len = sizeof(struct sockaddr_in); + break; +#endif +#ifdef INET6 + case AF_INET6: + sa_len = sizeof(struct sockaddr_in6); + break; +#endif + case AF_CONN: + sa_len = sizeof(struct sockaddr_conn); + break; + default: + sa_len = 0; + break; + } + memcpy((caddr_t)&sp.spinfo_address, sa, sa_len); +#endif + if (usrsctp_getsockopt(sock, IPPROTO_SCTP, SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) { + /* We depend on the fact that 0 can never be returned */ + return ((sctp_assoc_t) 0); + } + return (sp.spinfo_assoc_id); +} + /* Taken from /src/lib/libc/net/sctp_sys_calls.c * and modified for __Userspace__ @@ -792,6 +838,7 @@ usrsctp_sendv(struct socket *so, struct uio auio; struct iovec iov[1]; int use_sinfo; + sctp_assoc_t *assoc_id; if (so == NULL) { errno = EBADF; @@ -802,6 +849,7 @@ usrsctp_sendv(struct socket *so, return (-1); } memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); + assoc_id = NULL; use_sinfo = 0; switch (infotype) { case SCTP_SENDV_NOINFO: @@ -820,6 +868,7 @@ usrsctp_sendv(struct socket *so, sinfo.sinfo_ppid = ((struct sctp_sndinfo *)info)->snd_ppid; sinfo.sinfo_context = ((struct sctp_sndinfo *)info)->snd_context; sinfo.sinfo_assoc_id = ((struct sctp_sndinfo *)info)->snd_assoc_id; + assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id); use_sinfo = 1; break; case SCTP_SENDV_PRINFO: @@ -846,6 +895,7 @@ usrsctp_sendv(struct socket *so, sinfo.sinfo_ppid = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_ppid; sinfo.sinfo_context = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_context; sinfo.sinfo_assoc_id = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_assoc_id; + assoc_id = &(((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_assoc_id); } else { sinfo.sinfo_flags = 0; sinfo.sinfo_stream = 0; @@ -882,6 +932,9 @@ usrsctp_sendv(struct socket *so, auio.uio_resid = len; errno = sctp_lower_sosend(so, to, &auio, NULL, NULL, flags, use_sinfo ? &sinfo : NULL); if (errno == 0) { + if ((to != NULL) && (assoc_id != NULL)) { + *assoc_id = usrsctp_getassocid(so, to); + } return (len - auio.uio_resid); } else { return (-1); @@ -907,7 +960,7 @@ userspace_sctp_sendmbuf(struct socket *so, struct iovec iov[1]; */ int error = 0; int uflags = 0; - int retvalsendmsg; + ssize_t retval; sinfo->sinfo_ppid = ppid; sinfo->sinfo_flags = flags; @@ -937,16 +990,16 @@ userspace_sctp_sendmbuf(struct socket *so, sendmsg_return: /* TODO: Needs a condition for non-blocking when error is EWOULDBLOCK */ if (0 == error) - retvalsendmsg = len; + retval = len; else if (error == EWOULDBLOCK) { errno = EWOULDBLOCK; - retvalsendmsg = (-1); + retval = -1; } else { SCTP_PRINTF("%s: error = %d\n", __func__, error); errno = error; - retvalsendmsg = (-1); + retval = -1; } - return retvalsendmsg; + return (retval); } @@ -972,7 +1025,8 @@ userspace_sctp_recvmsg(struct socket *so, struct iovec *tiov; int iovlen = 1; int error = 0; - int ulen, i, retval; + ssize_t ulen; + int i; socklen_t fromlen; iov[0].iov_base = dbuf; @@ -1003,7 +1057,7 @@ userspace_sctp_recvmsg(struct socket *so, (struct sctp_sndrcvinfo *)sinfo, 1); if (error) { - if (auio.uio_resid != (int)ulen && + if ((auio.uio_resid != ulen) && (error == EINTR || #if !defined(__Userspace_os_NetBSD) error == ERESTART || @@ -1035,10 +1089,9 @@ userspace_sctp_recvmsg(struct socket *so, *fromlenp = fromlen; } } - if (error == 0){ + if (error == 0) { /* ready return value */ - retval = (int)ulen - auio.uio_resid; - return (retval); + return (ulen - auio.uio_resid); } else { SCTP_PRINTF("%s: error = %d\n", __func__, error); return (-1); @@ -1060,7 +1113,8 @@ usrsctp_recvv(struct socket *so, struct iovec iov[SCTP_SMALL_IOVEC_SIZE]; struct iovec *tiov; int iovlen = 1; - int ulen, i; + ssize_t ulen; + int i; socklen_t fromlen; struct sctp_rcvinfo *rcv; struct sctp_recvv_rn *rn; @@ -1096,7 +1150,7 @@ usrsctp_recvv(struct socket *so, from, fromlen, msg_flags, (struct sctp_sndrcvinfo *)&seinfo, 1); if (errno) { - if (auio.uio_resid != (int)ulen && + if ((auio.uio_resid != ulen) && (errno == EINTR || #if !defined(__Userspace_os_NetBSD) errno == ERESTART || @@ -1181,7 +1235,7 @@ usrsctp_recvv(struct socket *so, } if (errno == 0) { /* ready return value */ - return ((int)ulen - auio.uio_resid); + return (ulen - auio.uio_resid); } else { return (-1); } @@ -1362,7 +1416,7 @@ usrsctp_socket(int domain, int type, int protocol, { struct socket *so; - if ((protocol = IPPROTO_SCTP) && (SCTP_BASE_VAR(sctp_pcb_initialized) == 0)) { + if ((protocol == IPPROTO_SCTP) && (SCTP_BASE_VAR(sctp_pcb_initialized) == 0)) { errno = EPROTONOSUPPORT; return (NULL); } @@ -2496,6 +2550,24 @@ usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags) gaddrs->sget_assoc_id = 0; #ifdef HAVE_SA_LEN memcpy(gaddrs->addr, sa, sa->sa_len); +#if defined(INET) || defined(INET6) + if ((i == 0) && (sport != 0)) { + switch (gaddrs->addr->sa_family) { +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)gaddrs->addr; + sin->sin_port = sport; + break; +#endif +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)gaddrs->addr; + sin6->sin6_port = sport; + break; +#endif + } + } +#endif if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, gaddrs, (socklen_t)argsz) != 0) { free(gaddrs); return (-1); @@ -2921,12 +2993,12 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak, msg_hdr.msg_controllen = 0; msg_hdr.msg_flags = 0; - if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) > -1)) { + if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) != -1)) { if ((res = sendmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg_hdr, MSG_DONTWAIT)) != send_len) { *result = errno; } } - if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) > -1)) { + if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) != -1)) { if ((res = sendmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg_hdr, MSG_DONTWAIT)) != send_len) { *result = errno; } @@ -2941,14 +3013,14 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak, win_msg_hdr.Control = winbuf; win_msg_hdr.dwFlags = 0; - if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) > -1)) { + if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) != -1)) { if (WSASendTo(SCTP_BASE_VAR(userspace_rawsctp), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) { *result = WSAGetLastError(); } else if (win_sent_len != send_len) { *result = WSAGetLastError(); } } - if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) > -1)) { + if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) != -1)) { if (WSASendTo(SCTP_BASE_VAR(userspace_udpsctp), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) { *result = WSAGetLastError(); } else if (win_sent_len != send_len) { @@ -3079,12 +3151,12 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, msg_hdr.msg_controllen = 0; msg_hdr.msg_flags = 0; - if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) > -1)) { + if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) != -1)) { if ((res = sendmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg_hdr, MSG_DONTWAIT)) != send_len) { *result = errno; } } - if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) > -1)) { + if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) != -1)) { if ((res = sendmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg_hdr, MSG_DONTWAIT)) != send_len) { *result = errno; } @@ -3099,14 +3171,14 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, win_msg_hdr.Control = winbuf; win_msg_hdr.dwFlags = 0; - if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) > -1)) { + if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) != -1)) { if (WSASendTo(SCTP_BASE_VAR(userspace_rawsctp6), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) { *result = WSAGetLastError(); } else if (win_sent_len != send_len) { *result = WSAGetLastError(); } } - if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) > -1)) { + if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) != -1)) { if (WSASendTo(SCTP_BASE_VAR(userspace_udpsctp6), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) { *result = WSAGetLastError(); } else if (win_sent_len != send_len) { @@ -3256,10 +3328,10 @@ usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bit dst.sconn_len = sizeof(struct sockaddr_conn); #endif dst.sconn_addr = addr; - if ((m = sctp_get_mbuf_for_msg(length, 1, M_NOWAIT, 0, MT_DATA)) == NULL) { + if ((m = sctp_get_mbuf_for_msg((unsigned int)length, 1, M_NOWAIT, 0, MT_DATA)) == NULL) { return; } - m_copyback(m, 0, length, (caddr_t)buffer); + m_copyback(m, 0, (int)length, (caddr_t)buffer); if (SCTP_BUF_LEN(m) < (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) { if ((m = m_pullup(m, sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) == NULL) { SCTP_STAT_INCR(sctps_hdrops); @@ -3270,7 +3342,7 @@ usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bit ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); src.sconn_port = sh->src_port; dst.sconn_port = sh->dest_port; - sctp_common_input_processing(&m, 0, sizeof(struct sctphdr), length, + sctp_common_input_processing(&m, 0, sizeof(struct sctphdr), (int)length, (struct sockaddr *)&src, (struct sockaddr *)&dst, sh, ch, @@ -3302,7 +3374,6 @@ USRSCTP_SYSCTL_SET_DEF(sctp_asconf_enable) USRSCTP_SYSCTL_SET_DEF(sctp_reconfig_enable) USRSCTP_SYSCTL_SET_DEF(sctp_nrsack_enable) USRSCTP_SYSCTL_SET_DEF(sctp_pktdrop_enable) -USRSCTP_SYSCTL_SET_DEF(sctp_strict_sacks) #if !defined(SCTP_WITH_NO_CSUM) USRSCTP_SYSCTL_SET_DEF(sctp_no_csum_on_loopback) #endif @@ -3340,7 +3411,6 @@ USRSCTP_SYSCTL_SET_DEF(sctp_mbuf_threshold_count) USRSCTP_SYSCTL_SET_DEF(sctp_do_drain) USRSCTP_SYSCTL_SET_DEF(sctp_hb_maxburst) USRSCTP_SYSCTL_SET_DEF(sctp_abort_if_one_2_one_hits_limit) -USRSCTP_SYSCTL_SET_DEF(sctp_strict_data_order) USRSCTP_SYSCTL_SET_DEF(sctp_min_residual) USRSCTP_SYSCTL_SET_DEF(sctp_max_retran_chunk) USRSCTP_SYSCTL_SET_DEF(sctp_logging_level) @@ -3384,7 +3454,6 @@ USRSCTP_SYSCTL_GET_DEF(sctp_asconf_enable) USRSCTP_SYSCTL_GET_DEF(sctp_reconfig_enable) USRSCTP_SYSCTL_GET_DEF(sctp_nrsack_enable) USRSCTP_SYSCTL_GET_DEF(sctp_pktdrop_enable) -USRSCTP_SYSCTL_GET_DEF(sctp_strict_sacks) #if !defined(SCTP_WITH_NO_CSUM) USRSCTP_SYSCTL_GET_DEF(sctp_no_csum_on_loopback) #endif @@ -3422,7 +3491,6 @@ USRSCTP_SYSCTL_GET_DEF(sctp_mbuf_threshold_count) USRSCTP_SYSCTL_GET_DEF(sctp_do_drain) USRSCTP_SYSCTL_GET_DEF(sctp_hb_maxburst) USRSCTP_SYSCTL_GET_DEF(sctp_abort_if_one_2_one_hits_limit) -USRSCTP_SYSCTL_GET_DEF(sctp_strict_data_order) USRSCTP_SYSCTL_GET_DEF(sctp_min_residual) USRSCTP_SYSCTL_GET_DEF(sctp_max_retran_chunk) USRSCTP_SYSCTL_GET_DEF(sctp_logging_level) diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_socketvar.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_socketvar.h index 6adf23e1b44..ffc8270efda 100755 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_socketvar.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/user_socketvar.h @@ -84,9 +84,9 @@ MALLOC_DECLARE(M_SONAME); */ struct uio { struct iovec *uio_iov; /* scatter/gather list */ - int uio_iovcnt; /* length of scatter/gather list */ + int uio_iovcnt; /* length of scatter/gather list */ off_t uio_offset; /* offset in target object */ - int uio_resid; /* remaining bytes to process */ + ssize_t uio_resid; /* remaining bytes to process */ enum uio_seg uio_segflg; /* address space */ enum uio_rw uio_rw; /* operation */ }; diff --git a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/usrsctp.h b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/usrsctp.h index b897f44742d..dfb16c046f0 100644 --- a/chromium/third_party/usrsctp/usrsctplib/usrsctplib/usrsctp.h +++ b/chromium/third_party/usrsctp/usrsctplib/usrsctplib/usrsctp.h @@ -67,6 +67,7 @@ extern "C" { #define uint8_t unsigned __int8 #define uint16_t unsigned __int16 #define uint32_t unsigned __int32 +#define uint64_t unsigned __int64 #define int16_t __int16 #define int32_t __int32 #endif @@ -90,7 +91,8 @@ typedef uint32_t sctp_assoc_t; /* The definition of struct sockaddr_conn MUST be in * tune with other sockaddr_* structures. */ -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#if defined(__APPLE__) || defined(__Bitrig__) || defined(__DragonFly__) || \ + defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) struct sockaddr_conn { uint8_t sconn_len; uint8_t sconn_family; @@ -522,6 +524,10 @@ struct sctp_event_subscribe { #define SCTP_ENABLE_STREAM_RESET 0x00000900 /* struct sctp_assoc_value */ +/* Pluggable Stream Scheduling Socket option */ +#define SCTP_PLUGGABLE_SS 0x00001203 +#define SCTP_SS_VALUE 0x00001204 + /* * read-only options */ @@ -780,6 +786,12 @@ struct sctp_cc_option { struct sctp_assoc_value aid_value; }; +struct sctp_stream_value { + sctp_assoc_t assoc_id; + uint16_t stream_id; + uint16_t stream_value; +}; + struct sctp_timeouts { sctp_assoc_t stimo_assoc_id; uint32_t stimo_init; @@ -943,6 +955,9 @@ usrsctp_connectx(struct socket *so, void usrsctp_close(struct socket *so); +sctp_assoc_t +usrsctp_getassocid(struct socket *, struct sockaddr *); + int usrsctp_finish(void); @@ -991,7 +1006,6 @@ USRSCTP_SYSCTL_DECL(sctp_asconf_enable) USRSCTP_SYSCTL_DECL(sctp_reconfig_enable) USRSCTP_SYSCTL_DECL(sctp_nrsack_enable) USRSCTP_SYSCTL_DECL(sctp_pktdrop_enable) -USRSCTP_SYSCTL_DECL(sctp_strict_sacks) #if !defined(SCTP_WITH_NO_CSUM) USRSCTP_SYSCTL_DECL(sctp_no_csum_on_loopback) #endif @@ -1030,7 +1044,6 @@ USRSCTP_SYSCTL_DECL(sctp_mbuf_threshold_count) USRSCTP_SYSCTL_DECL(sctp_do_drain) USRSCTP_SYSCTL_DECL(sctp_hb_maxburst) USRSCTP_SYSCTL_DECL(sctp_abort_if_one_2_one_hits_limit) -USRSCTP_SYSCTL_DECL(sctp_strict_data_order) USRSCTP_SYSCTL_DECL(sctp_min_residual) USRSCTP_SYSCTL_DECL(sctp_max_retran_chunk) USRSCTP_SYSCTL_DECL(sctp_logging_level) |