Compare commits

...

42 Commits

Author SHA1 Message Date
Christopher Friedt
6ed0a3557f release: Zephyr 2.7.6
Set version to 2.7.6

Signed-off-by: Christopher Friedt <cfriedt@meta.com>
2024-03-01 17:28:52 -05:00
Christopher Friedt
a405f8b6b0 release: add v2.7.6 release notes
List bugfixes and CVEs in v2.7.6 release notes.

Signed-off-by: Christopher Friedt <cfriedt@meta.com>
2024-03-01 14:24:35 -05:00
Benjamin Cabé
3683fe625b doc: fix broken Sphinx by updating to Sphinx 5.0.2
Sphinx 4.x is way past EOL and due to it not pinning its dependencies,
it's effectively broken. See
https://github.com/sphinx-doc/sphinx/issues/11890 The recommended fix,
although not ideal in the context of an LTS branch, is to update to
Sphinx 5.0.2, which should have minimal impact of how the rendered
documentation looks.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2024-03-01 08:29:26 -05:00
Flavio Ceolin
e9fcfa14e6 syscall: Fix static analysis compalins
Since K_SYSCALL_MEMORY can be called with signed/unsigned size types, if
we check if size >= 0, static anlysis will complain about it when
size in unsigned.

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
2024-03-01 00:54:04 -05:00
Flavio Ceolin
1d16757282 userspace: Additional checks in K_SYSCALL_MEMORY
This macros needed additional checks before invoking
arch_buffer_validate.

- size can not be less then 0. Some functions invoke this macro
  using signed type which will be promote to unsigned when invoking
  arch_buffer_validate. We need to do an early check.
- We need to check for possible overflow, since a malicious user
  application could use a negative number that would be promoted
  to a big value that would cause a integer overflow when adding it
  to the buffer address, leading to invalid checks.

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
2024-03-01 00:54:04 -05:00
Peter Mitsis
eeefd07f68 include: util: Add Z_DETECT_POINTER_OVERFLOW()
The Z_DETECT_POINTER_OVERFLOW() macro is intended detect whether
or not a buffer spans a region of memory that goes beyond the
highest possible address (thereby overflowing the pointer).

Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
2024-03-01 00:54:04 -05:00
Flavio Ceolin
d013132f55 fs: fuse: Avoid possible buffer overflow
Checks path's size before copying it to local variable.

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
(cherry picked from commit 3267bdc4b7)
2024-02-29 12:07:00 -05:00
Benedikt Schmidt
25398f36da shell: modules: do not use k_thread_foreach with shell callbacks
Always use k_thread_foreach_unlocked with callbacks which print
something out to the shell, as they might call arch_irq_unlock.
Fixes #66660.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
(cherry picked from commit 4c731f27c6)
2024-02-27 13:29:34 -05:00
Maxim Adelman
d3c2a2457d kernel shell, stacks shell commands: iterate unlocked on SMP
call k_thread_foreach_unlocked to avoid assertions caused
by calling shell_print while holding a global lock

Signed-off-by: Maxim Adelman <imax@meta.com>
(cherry picked from commit ecf2cb5932)
2024-02-27 13:29:34 -05:00
Adrien Ricciardi
10086910f5 drivers: i2c: i2c_dw: Fixed integer overflow in i2c_dw_data_ask().
The controller can implement a reception FIFO as deep as 256 bytes.
However, the computation made by the driver code to determine how many
bytes can be asked is stored in a signed 8-bit variable called rx_empty.

If the reception FIFO depth is greater or equal to 128 bytes and the FIFO
is currently empty, the rx_empty value will be 128 (or more), which
stands for a negative value as the variable is signed.

Thus, the later code checking if the FIFO is full will run while it should
not and exit from the i2c_dw_data_ask() function too early.

This hangs the controller in an infinite loop of interrupt storm because
the interrupt flags are never cleared.

Storing the rx_empty empty on a signed 32-bit variable instead of a 8-bit
one solves the issue and is compliant with the controller hardware
specifications of a maximum FIFO depth of 256 bytes.

It has been agreed with upstream maintainers to change the type of the
variables tx_empty, rx_empty, cnt, rx_buffer_depth and tx_buffer_depth to
plain int because it is most effectively handled by the CPUs. Using 8-bit
or 16-bit variables had no meaning here.

Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
(cherry picked from commit 4824e405cf)
2024-01-16 16:13:25 -05:00
Jukka Rissanen
01ad11252c tests: net: ipv6: Adjust the source address of test pkt
We would drop the received packet if the source address is our
address so tweak the test and make source address different.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
(cherry picked from commit 155e2149f2)
2024-01-09 12:55:32 -05:00
Jukka Rissanen
652b7f6f83 net: ipv6: Check that received src address is not mine
Drop received packet if the source address is the same as
the device address.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
(cherry picked from commit 8d3d48e057)
2024-01-09 12:55:32 -05:00
Jukka Rissanen
32748c69b8 net: ipv4: Drop packet if source address is my address
If we receive a packet where the source address is our own
address, then we should drop it.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
(cherry picked from commit 19392a6d2b)
2024-01-03 13:13:51 -05:00
Jukka Rissanen
65104bc3cc net: ipv4: Check localhost for incoming packet
If we receive a packet from non localhost interface, then
drop it if either source or destination address is a localhost
address.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
(cherry picked from commit 6d41e68352)
2024-01-03 13:13:51 -05:00
Keith Packard
ce4c30fc21 toolchain: Replace GCC_VERSION, CLANG_VERSION and BUILD_ASSERT macros
GCC_VERSION is defined in a few modules, and those headers are often
included first, so replace the one used in zephyr with
TOOLCHAIN_GCC_VERSION. Do the same with CLANG_VERSION, replacing it with
TOOLCHAIN_CLANG_VERSION.

BUILD_ASSERT is also defined in include/toolchain/common.h, which might
get included before gcc.h. We want to use the gcc-specific one instead
of the general one.

Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit c58c76ef0a)
2023-12-19 04:31:03 -05:00
Nikolay Agishev
5d382fa560 toolchain: Move extra warning options to toolchain abstraction
Move extra warning option from generic twister script into
compiler-dependent config files.
ARCMWDT compiler doesn't support extra warning options ex.
"-Wl,--fatal-warnings". To avoid build fails flag
"disable_warnings_as_errors" should be passed to twister.
This allows all warning messages and make atomatic test useles.

Signed-off-by: Nikolay Agishev <agishev@synopsys.com>
(cherry picked from commit 0dec4cf927)
2023-12-19 04:31:03 -05:00
Jamie McCrae
e677cfd61d cmake: modules: dts: Fix board revision 0 overlay
Fixes an issue whereby a board revision is 0 and the overlay file
exists but would not be included

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2023-12-01 08:28:59 -05:00
Sven Ginka
db1ed25fad drivers: sam dma xdmac: implemented dma device get_status()
the sam xdmac driver does not yet implement the
get_status() function. with this commit the function
will be implemented. Fixes #62003

Signed-off-by: Sven Ginka <sven.ginka@gmail.com>
(cherry picked from commit bc695c6df5)
2023-11-16 20:31:29 -05:00
Joshua Crawford
e6f70e97c8 drivers: flash: spi_nor: select largest valid erase operation
The spi_nor erase op selection was based on the alignment of the end of
the region to be erased. This prevented larger erase operations being
selected in many cases

Closes #60904

Signed-off-by: Joshua Crawford <joshua.crawford@levno.com>
(cherry picked from commit ea2dd9fc65)
2023-11-16 20:31:16 -05:00
Abram Early
f89298cf0e drivers: can: mcan: Move RF0L and RF1L to line 1
The code is designed to handle RF0L and RF1L in
line 1, but they were being sent to line 0. Becuase
they weren't handled, the interrupts would never
be handled which locked up the chip.

Signed-off-by: Abram Early <abram.early@gmail.com>
2023-11-05 07:49:19 -05:00
Henrik Brix Andersen
2e98b1fd8c drivers: can: be consistent in filter_id checks when removing rx filters
Change the CAN controller driver implementations for the
can_remove_rx_filter() API call to be consistent in their
validation of the supplied filter_id.

Fixes: #64398

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2023-10-26 09:34:14 -04:00
Christopher Friedt
13072b4c7b logging: log_core: correct timeout of -1 ms to K_FOREVER
Many releases ago, specifying to block indefinitely in the log
processing thread would do just that.

However, a subtle bug was introduced  such that specifying -1
for `CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS` would have the
exact opposite effect than what was intended.

As per Kconfig, a value of -1 should translate to a timeout of
`K_FOREVER`. However, conversion via `K_MSEC(-1)` results in
a `k_timeout_t` that is equal to `K_NO_WAIT` rather than the
intent which is `K_FOREVER`.

Add a dedicated check to to ensure that a value of -1 is
correctly interpreted as `K_FOREVER` in `log_core.c`.

For reference, the blocking feature was described in #15196,
added in #16194, and it would appear that the regression
happened in c5f2cdef09.

Signed-off-by: Christopher Friedt <cfriedt@meta.com>
(cherry picked from commit 137097f5c3)
2023-10-25 22:39:44 -04:00
Jukka Rissanen
43c936a5dd net: socket: mgmt: Check buf size in recvfrom()
Return EMSGSIZE if trying to copy too much data into
user supplied buffer.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
(cherry picked from commit 0a16d5c7c3)
(cherry picked from commit b13b4eb38a50ee02d599332eb99752e814340487)
2023-10-12 21:20:39 -04:00
Robert Lubos
acc7cfaadf drivers: ieee802154_nrf5: Add payload length check on TX
In case upper layer does not follow the convention, and the net_pkt
provided to the nRF 15.4 driver had a payload larger than the maximum
payload size of an individual 15.4 frame, the driver would end up with
buffer overflow.

Fix this by adding an extra payload_len check before attempting to copy
the payload to the internal buffer.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2023-10-02 14:55:05 -04:00
Fabio Baltieri
f9a56bcfd4 can: rework the table lookup code in can_dlc_to_bytes
Rework the can_dlc_to_bytes table lookup code in a way that allow the
compiler to guess the resulting output and somehow fix the build
warning:

zephyr/drivers/can/can_nxp_s32_canxl.c:757:9: warning:
'__builtin___memcpy_chk' forming offset [16, 71] is out of the bounds
[0, 16] of object 'frame' with type 'struct can_frame' [-Warray-bounds]
 757 | memcpy(frame->data, msg_data.data, can_dlc_to_bytes(frame->dlc));

where the compiler detects that frame->data is 8 bytes long but
can_dlc_to_bytes could return more than that.

Can be reproduced with:

west build -p -b s32z270dc2_rtu1_r52 \
	-T samples/net/sockets/can/sample.net.sockets.can.one_socket

Suggested-by: Martin Jäger <martin@libre.solar>
Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
2023-09-19 02:32:36 -04:00
Carles Cufi
4a3b59d47b Bluetooth: controller: Check minimum sizes of adv PDUs
While the maximum sizes were already correctly checked by the code, the
minimum sizes of the PDUs were not. This meant that PDUs smaller than
the minimum required length (typically 6 bytes for AdvA) were
incorrectly forwarded up to the Host.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
(cherry picked from commit 3f0d7012a6)
2023-09-06 18:02:35 -04:00
Thomas Stranger
414d6c91a1 drivers: can: stm32: correct timing_max parameters
The timing_max parameters defined in the stm32 bxcan driver don't match the
register description in the reference manuals.
- sjw does have only 2 bits representing 1 to 4 tq.
- phase_seg1 and phase_seg2 max is one tq higher.

I have checked the following reference manuals and all match:
- RM0090: STM32F405, F415, F407, F417, F427, F437 AND F429
- RM0008: STM32F101, F102, F103, F105, F107 advanced arm-based mcus
- RM0351, RM0394: all STM32L4
- RM0091: all STM32F0 with CAN support

Signed-off-by: Thomas Stranger <thomas.stranger@outlook.com>
(cherry picked from commit cec279b5b6)
2023-08-25 09:44:40 -04:00
Henrik Brix Andersen
2daec8c70c canbus: isotp: convert SF length check from ASSERT to runtime check
Convert the ISO-TP SF length check in send_sf() from __ASSERT() to a
runtime check.

Fixes: #61501

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
(cherry picked from commit 1b3d1e01de)
2023-08-25 09:44:26 -04:00
Grant Ramsay
229ca396aa canbus: isotp: Fix context buffer memory leaks
Ensure context buffers are free'd when errors occur

Signed-off-by: Grant Ramsay <gramsay@enphaseenergy.com>
2023-08-08 19:01:38 -04:00
Andrzej Głąbek
06ae95e45c drivers: nrf_rtc_timer: Always set an initial timeout
In the tickless kernel mode, the nRF system timer does not schedule
any timeout on initialization. This can lead to a situation that
for certain applications no timeout is scheduled at all (for example,
when an application does not create any threads, it exits `main()`
without any sleeping and only handles interrupts) and in consequence
`sys_clock_announce()` is never called (the nRF system timer calls
this function only from the timeout handler). This in turn causes that
uptime is reported correctly only until the RTC used as the system
timer overflows (what happens after 512 seconds).

Fix this by setting a maximum allowed timeout when initializing
the nRF system timer for the tickless kernel mode.

Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
2023-06-13 12:06:52 +02:00
Théo Battrel
f72d8ffe80 Net: Increase NET_BUF_USER_DATA_SIZE value to 8
Increase `NET_BUF_USER_DATA_SIZE` value to 8 if `BT_CONN` is enabled.
This is necessary because one of the backported commits adds one struct
member into `struct tx_meta`, and that will be stored in the buffer
user data.

On main, this Kconfig option has been deprecated, hence why this change
was not present in the original patch set.

Signed-off-by: Théo Battrel <theo.battrel@nordicsemi.no>
2023-06-06 12:42:08 -04:00
Pavel Vasilyev
f2eeeda113 bluetooth: mesh: Remove illegal use of NET_BUF_FRAG in friend.c
This commit removes illegal use of NET_BUF_FRAG in friend.c, which is an
internal flag.

Now `struct bt_mesh_friend_seg` keeps pointer to a first received
segment of a segmented message. The rest segments are added as fragments
using net_buf API. Friend Queue keeps only head of the fragments.
When one segment (currently head of fragments) is removed from Friend
Queue, the next segment is added to the queue. Head has always 2
references: one when allocated, another one when added as fragments
head.

Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
(cherry picked from commit 5d059117fd)
2023-06-06 12:42:08 -04:00
Carles Cufi
916d9ad13b net: buf: Simplify fragment handling
This patch reworks how fragments are handled in the net_buf
infrastructure.

In particular, it removes the union around the node and frags members
in the main net_buf structure. This is done so that both can be used at
the same time, at a cost of 4 bytes per net_buf instance.
This implies that the layout of net_buf instances changes whenever
being inserted into a queue (fifo or lifo) or a linked list (slist).

Until now, this is what happened when enqueueing a net_buf with frags
in a queue or linked list:

1.1 Before enqueueing:

 +--------+      +--------+      +--------+
 |#1  node|\     |#2  node|\     |#3  node|\
 |        | \    |        | \    |        | \
 | frags  |------| frags  |------| frags  |------NULL
 +--------+      +--------+      +--------+

net_buf #1 has 2 fragments, net_bufs #2 and #3. Both the node and frags
pointers (they are the same, since they are unioned) point to the next
fragment.

1.2 After enqueueing:

 +--------+     +--------+     +--------+     +--------+     +--------+
 |q/slist |-----|#1  node|-----|#2  node|-----|#3  node|-----|q/slist |
 |node    |     | *flag  | /   | *flag  | /   |        | /   |node    |
 |        |     | frags  |/    | frags  |/    | frags  |/    |        |
 +--------+     +--------+     +--------+     +--------+     +--------+

When enqueing a net_buf (in this case #1) that contains fragments, the
current net_buf implementation actually enqueues all the fragments (in
this case #2 and #3) as actual queue/slist items, since node and frags
are one and the same in memory. This makes the enqueuing operation
expensive and it makes it impossible to atomically dequeue. The `*flag`
notation here means that the `flags` member has been set to
`NET_BUF_FRAGS` in order to be able to reconstruct the frags pointers
when dequeuing.

After this patch, the layout changes considerably:

2.1 Before enqueueing:

 +--------+       +--------+       +--------+
 |#1  node|--NULL |#2  node|--NULL |#3  node|--NULL
 |        |       |        |       |        |
 | frags  |-------| frags  |-------| frags  |------NULL
 +--------+       +--------+       +--------+

This is very similar to 1.1, except that now node and frags are
different pointers, so node is just set to NULL.

2.2 After enqueueing:

 +--------+      +--------+      +--------+
 |q/slist |------|#1  node|------|q/slist |
 |node    |      |        |      |node    |
 |        |      | frags  |      |        |
 +--------+      +--------+      +--------+
                     |           +--------+       +--------+
                     |           |#2  node|--NULL |#3  node|--NULL
                     |           |        |       |        |
                     +-----------| frags  |-------| frags  |------NULL
                                 +--------+       +--------+

When enqueuing net_buf #1, now we only enqueue that very item, instead
of enqueing the frags as well, since now node and frags are separate
pointers. This simplifies the operation and makes it atomic.

Resolves #52718.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
(cherry picked from commit 3d306c181f)
2023-06-06 12:42:08 -04:00
Jonathan Rico
a90a3cc493 Bluetooth: host: update l2cap stress test
Do these things:
- use the proper macros for reserving the SDU header
- make every L2CAP PDU fragment into 3 ACL packets
- set tx data and verify rx matches the pattern
- measure segment pool usage

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit 8bc094610c)
2023-06-06 12:42:08 -04:00
Jonathan Rico
fb5845a072 Bluetooth: host: copy fragment data at the last minute
Only copy the data from the 'parent' buf into the segment buf if we
successfully acquired the HCI semaphore (ie there are available
controller buffers).

This way we avoid pulling and pushing back the data in the case where
there aren't any controller buffers available.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit ca51439cd1)
2023-06-06 12:42:08 -04:00
Jonathan Rico
c0d6fad199 Bluetooth: host: poll on CTLR buffers instead of host TX queue
When there are no buffers, it doesn't make sense to repeatedly try to
send the host TX queue.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit ef19c64f1b)
2023-06-06 12:42:08 -04:00
Jonathan Rico
60ae4f9351 Bluetooth: host: make HCI fragmentation async
Make the ACL fragmentation asynchronous, freeing the TX thread for
sending commands when the ACL buffers are full.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit c3e5fabbf1)
2023-06-06 12:42:08 -04:00
Jonathan Rico
6ebce3643e Bluetooth: host: l2cap: add alloc_seg callback
This callback allows use-cases where the SDU is much larger than the
l2cap MPS. The stack will then try to allocate using this callback if
specified, and fall-back on using the buffer's pool (previous
behavior).

This way one can define two buffer pools, one with a very large buffer
size, and one with a buffer size >= MPS, and the stack will allocate
from that instead.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit 77e1a9dcad)
2023-06-06 12:42:08 -04:00
Jonathan Rico
80ab098d64 Bluetooth: host: l2cap: workaround SDU deadlock
See the code comments.

SDUs might enter a state where they will be blocked forever, as a
workaround, we nudge them when another SDU has been sent.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit 8e207fefad)
2023-06-06 12:42:08 -04:00
Jonathan Rico
d00c98d585 Bluetooth: host: l2cap: don't send too much credits
There was an edge-case where we were sending back too much credits, add
a check so we can't do that anymore.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit 3c1ca93fe8)
2023-06-06 12:42:08 -04:00
Jonathan Rico
f290106952 Bluetooth: host: l2cap: release segment in all cases
See code comment

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit 1c8fe67a52)
2023-06-06 12:42:08 -04:00
Jonathan Rico
2e0e5e27e8 Bluetooth: host: add l2cap stress-test
This test reproduces more-or-less #34600.

It has a central that connects to multiple peripherals, opens one l2cap
CoC channel per connection, and transmits a few SDUs largely exceeding
the MPS of the channel.

In this commit, the test doesn't pass, but when it passes (after the
subsequent commits), error and warning messages are expected from the
stack, as this is not the happy path.

We can later debate on whether these particular error messages should
be downgraded to debug.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
(cherry picked from commit 7a6872d837)
2023-06-06 12:42:08 -04:00
59 changed files with 1211 additions and 221 deletions

View File

@@ -162,6 +162,13 @@ zephyr_compile_options(${OPTIMIZATION_FLAG})
# @Intent: Obtain compiler specific flags related to C++ that are not influenced by kconfig
zephyr_compile_options($<$<COMPILE_LANGUAGE:CXX>:$<TARGET_PROPERTY:compiler-cpp,required>>)
# Extra warnings options for twister run
if (CONFIG_COMPILER_WARNINGS_AS_ERRORS)
zephyr_compile_options($<$<COMPILE_LANGUAGE:C>:$<TARGET_PROPERTY:compiler,warnings_as_errors>>)
zephyr_compile_options($<$<COMPILE_LANGUAGE:ASM>:$<TARGET_PROPERTY:asm,warnings_as_errors>>)
zephyr_link_libraries($<TARGET_PROPERTY:linker,warnings_as_errors>)
endif()
# @Intent: Obtain compiler specific flags for compiling under different ISO standards of C++
if(CONFIG_CPLUSPLUS)
# From kconfig choice, pick a single dialect.

View File

@@ -305,9 +305,13 @@ config NO_OPTIMIZATIONS
help
Compiler optimizations will be set to -O0 independently of other
options.
endchoice
config COMPILER_WARNINGS_AS_ERRORS
bool "Treat warnings as errors"
help
Turn on "warning as error" toolchain flags
config COMPILER_COLOR_DIAGNOSTICS
bool "Enable colored diganostics"
default y

View File

@@ -1,5 +1,5 @@
VERSION_MAJOR = 2
VERSION_MINOR = 7
PATCHLEVEL = 5
PATCHLEVEL = 6
VERSION_TWEAK = 0
EXTRAVERSION =

View File

@@ -132,6 +132,10 @@ set_property(TARGET compiler-cpp PROPERTY dialect_cpp2a "")
set_property(TARGET compiler-cpp PROPERTY dialect_cpp20 "")
set_property(TARGET compiler-cpp PROPERTY dialect_cpp2b "")
# Flags for set extra warnigs (ARCMWDT asm can't recognize --fatal-warnings. Skip it)
set_property(TARGET compiler PROPERTY warnings_as_errors -Werror)
set_property(TARGET asm PROPERTY warnings_as_errors -Werror)
# Disable exeptions flag in C++
set_property(TARGET compiler-cpp PROPERTY no_exceptions "-fno-exceptions")

View File

@@ -65,6 +65,10 @@ set_property(TARGET compiler-cpp PROPERTY dialect_cpp2a)
set_property(TARGET compiler-cpp PROPERTY dialect_cpp20)
set_property(TARGET compiler-cpp PROPERTY dialect_cpp2b)
# Extra warnings options for twister run
set_property(TARGET compiler PROPERTY warnings_as_errors)
set_property(TARGET asm PROPERTY warnings_as_errors)
# Flag for disabling exeptions in C++
set_property(TARGET compiler-cpp PROPERTY no_exceptions)

View File

@@ -137,6 +137,10 @@ set_property(TARGET compiler-cpp PROPERTY dialect_cpp20 "-std=c++20"
set_property(TARGET compiler-cpp PROPERTY dialect_cpp2b "-std=c++2b"
"-Wno-register" "-Wno-volatile")
# Flags for set extra warnigs (ARCMWDT asm can't recognize --fatal-warnings. Skip it)
set_property(TARGET compiler PROPERTY warnings_as_errors -Werror)
set_property(TARGET asm PROPERTY warnings_as_errors -Werror)
# Disable exeptions flag in C++
set_property(TARGET compiler-cpp PROPERTY no_exceptions "-fno-exceptions")

View File

@@ -53,7 +53,7 @@ list(REMOVE_DUPLICATES
# Drop support for NOT CONFIG_HAS_DTS perhaps?
if(EXISTS ${DTS_SOURCE})
set(SUPPORTS_DTS 1)
if(BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay)
if(DEFINED BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay)
list(APPEND DTS_SOURCE ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay)
endif()
else()

View File

@@ -0,0 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
# Extra warnings options for twister run
set_property(TARGET linker PROPERTY warnings_as_errors -Wl,--fatal-warnings)

View File

@@ -3,6 +3,9 @@ if (NOT CONFIG_COVERAGE_GCOV)
set_property(TARGET linker PROPERTY coverage --coverage)
endif()
# Extra warnings options for twister run
set_property(TARGET linker PROPERTY ld_extra_warning_options -Wl,--fatal-warnings)
# ld/clang linker flags for sanitizing.
check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_address -fsanitize=address)

View File

@@ -7,6 +7,9 @@ if (NOT CONFIG_COVERAGE_GCOV)
set_property(TARGET linker PROPERTY coverage -lgcov)
endif()
# Extra warnings options for twister run
set_property(TARGET linker PROPERTY warnings_as_errors -Wl,--fatal-warnings)
# ld/gcc linker flags for sanitizing.
check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_address -lasan)
check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_address -fsanitize=address)

View File

@@ -14,3 +14,6 @@ check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_undefined)
# If memory reporting is a post build command, please use
# cmake/bintools/bintools.cmake insted.
check_set_linker_property(TARGET linker PROPERTY memusage)
# Extra warnings options for twister run
set_property(TARGET linker PROPERTY warnings_as_errors)

View File

@@ -253,8 +253,8 @@ graphviz_dot_args = [
# -- Linkcheck options ----------------------------------------------------
extlinks = {
"jira": ("https://jira.zephyrproject.org/browse/%s", ""),
"github": ("https://github.com/zephyrproject-rtos/zephyr/issues/%s", ""),
"jira": ("https://jira.zephyrproject.org/browse/%s", "JIRA %s"),
"github": ("https://github.com/zephyrproject-rtos/zephyr/issues/%s", "GitHub #%s"),
}
linkcheck_timeout = 30

View File

@@ -2,6 +2,70 @@
.. _zephyr_2.7:
.. _zephyr_2.7.6:
Zephyr 2.7.6
####################
This is an LTS maintenance release with fixes.
Issues Fixed
************
These GitHub issues were addressed since the previous 2.7.5 tagged
release:
.. comment List derived from GitHub Issue query: ...
* :github:`issuenumber` - issue title
* :github:`32145` - use ``k_thread_foreach_unlocked()`` with shell callbacks
* :github:`56604` - drivers: nrf: rtc: make uptime consistent for app booted from v3.x mcuboot
* :github:`25917` - bluetooth: fix deadlock with tx of acl data and hci commands
* :github:`47649` - bluetooth: release att notification buffer after reconnection
* :github:`43718` - bluetooth: bt_conn: ensure tx buffers can be allocated within timeout
* :github:`60707` - canbus: isotp: seal context buffer memory leaks
* :github:`60904` - drivers: spi_nor: make erase operation more opportunistic
* :github:`61451` - drivers: can: stm32: correct timing_max parameters
* :github:`61501` - canbus: isotp: convert SF length check from ``ASSERT`` to runtime check
* :github:`61544` - drivers: ieee802154_nrf5: add payload length check on TX
* :github:`61784` - bluetooth: controller: check minmum sizes of adv PDUs
* :github:`62003` - drivers: dma: sam: implement xdmac ``get_status()`` API
* :github:`62701` - can: rework the table lookup code in ``can_dlc_to_bytes()``
* :github:`63544` - drivers: can: mcan: move RF0L and RF1L to line 1
* :github:`63835` - net_mgmt: return ``EMSGSIZE`` if buffer passed to ``recvfrom()`` is too small
* :github:`63965` - logging: fix handling of ``CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS``
* :github:`64398` - drivers: can: be consistent in ``filter_id`` checks when removing rx filters
* :github:`65548` - cmake: modules: dts: fix board revision 0 overlay
* :github:`66500` - toolchain: support ``CONFIG_COMPILER_WARNINGS_AS_ERRORS``
* :github:`66888` - net: ipv6: drop received packets sent by the same interface
* :github:`67692` - i2c: dw: fix integer overflow in ``i2c_dw_data_ask()``
* :github:`69167` - fs: fuse: avoid possible buffer overflow
* :github:`69637` - userspace: additional checks in ``K_SYSCALL_MEMORY``
Security Vulnerability Related
******************************
The following security vulnerabilities (CVEs) were addressed in this
release:
* CVE-2023-4263 `Zephyr project bug tracker GHSA-rf6q-rhhp-pqhf
<https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-rf6q-rhhp-pqhf>`_
* CVE-2023-4424: `Zephyr project bug tracker GHSA-j4qm-xgpf-qjw3
<https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-j4qm-xgpf-qjw3>`_
* CVE-2023-5779 `Zephyr project bug tracker GHSA-7cmj-963q-jj47
<https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-7cmj-963q-jj47>`_
* CVE-2023-6249 `Zephyr project bug tracker GHSA-32f5-3p9h-2rqc
<https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-32f5-3p9h-2rqc>`_
* CVE-2023-6881 `Zephyr project bug tracker GHSA-mh67-4h3q-p437
<https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-mh67-4h3q-p437>`_
More detailed information can be found in:
https://docs.zephyrproject.org/latest/security/vulnerabilities.html
.. _zephyr_2.7.5:
Zephyr 2.7.5

View File

@@ -171,6 +171,11 @@ void can_loopback_detach(const struct device *dev, int filter_id)
{
struct can_loopback_data *data = DEV_DATA(dev);
if (filter_id < 0 || filter_id >= ARRAY_SIZE(data->filters)) {
LOG_ERR("filter ID %d out of bounds", filter_id);
return;
}
LOG_DBG("Detach filter ID: %d", filter_id);
k_mutex_lock(&data->mtx, K_FOREVER);
data->filters[filter_id].rx_cb = NULL;

View File

@@ -404,7 +404,8 @@ int can_mcan_init(const struct device *dev, const struct can_mcan_config *cfg,
#ifdef CONFIG_CAN_STM32FD
can->ils = CAN_MCAN_ILS_RXFIFO0 | CAN_MCAN_ILS_RXFIFO1;
#else
can->ils = CAN_MCAN_ILS_RF0N | CAN_MCAN_ILS_RF1N;
can->ils = CAN_MCAN_ILS_RF0N | CAN_MCAN_ILS_RF1N |
CAN_MCAN_ILS_RF0L | CAN_MCAN_ILS_RF1L;
#endif
can->ile = CAN_MCAN_ILE_EINT0 | CAN_MCAN_ILE_EINT1;
/* Interrupt on every TX fifo element*/
@@ -894,11 +895,16 @@ int can_mcan_attach_isr(struct can_mcan_data *data,
void can_mcan_detach(struct can_mcan_data *data,
struct can_mcan_msg_sram *msg_ram, int filter_nr)
{
if (filter_nr < 0) {
LOG_ERR("filter ID %d out of bounds", filter_nr);
return;
}
k_mutex_lock(&data->inst_mutex, K_FOREVER);
if (filter_nr >= NUM_STD_FILTER_DATA) {
filter_nr -= NUM_STD_FILTER_DATA;
if (filter_nr >= NUM_STD_FILTER_DATA) {
LOG_ERR("Wrong filter id");
LOG_ERR("filter ID %d out of bounds", filter_nr);
return;
}

View File

@@ -551,6 +551,11 @@ static void mcp2515_detach(const struct device *dev, int filter_nr)
{
struct mcp2515_data *dev_data = DEV_DATA(dev);
if (filter_nr < 0 || filter_nr >= CONFIG_CAN_MAX_FILTER) {
LOG_ERR("filter ID %d out of bounds", filter_nr);
return;
}
k_mutex_lock(&dev_data->mutex, K_FOREVER);
dev_data->filter_usage &= ~BIT(filter_nr);
k_mutex_unlock(&dev_data->mutex);

View File

@@ -480,9 +480,8 @@ static void mcux_flexcan_detach(const struct device *dev, int filter_id)
const struct mcux_flexcan_config *config = dev->config;
struct mcux_flexcan_data *data = dev->data;
if (filter_id >= MCUX_FLEXCAN_MAX_RX) {
LOG_ERR("Detach: Filter id >= MAX_RX (%d >= %d)", filter_id,
MCUX_FLEXCAN_MAX_RX);
if (filter_id < 0 || filter_id >= MCUX_FLEXCAN_MAX_RX) {
LOG_ERR("filter ID %d out of bounds", filter_id);
return;
}

View File

@@ -829,7 +829,8 @@ void can_rcar_detach(const struct device *dev, int filter_nr)
{
struct can_rcar_data *data = DEV_CAN_DATA(dev);
if (filter_nr >= CONFIG_CAN_RCAR_MAX_FILTER) {
if (filter_nr < 0 || filter_nr >= CONFIG_CAN_RCAR_MAX_FILTER) {
LOG_ERR("filter ID %d out of bounds", filter_nr);
return;
}

View File

@@ -1113,10 +1113,10 @@ static const struct can_driver_api can_api_funcs = {
.prescaler = 0x01
},
.timing_max = {
.sjw = 0x07,
.sjw = 0x04,
.prop_seg = 0x00,
.phase_seg1 = 0x0F,
.phase_seg2 = 0x07,
.phase_seg1 = 0x10,
.phase_seg2 = 0x08,
.prescaler = 0x400
}
};

View File

@@ -354,11 +354,36 @@ static int sam_xdmac_initialize(const struct device *dev)
return 0;
}
static int sam_xdmac_get_status(const struct device *dev, uint32_t channel,
struct dma_status *status)
{
const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config;
Xdmac * const xdmac = dev_cfg->regs;
uint32_t chan_cfg = xdmac->XDMAC_CHID[channel].XDMAC_CC;
uint32_t ublen = xdmac->XDMAC_CHID[channel].XDMAC_CUBC;
/* we need to check some of the XDMAC_CC registers to determine the DMA direction */
if ((chan_cfg & XDMAC_CC_TYPE_Msk) == 0) {
status->dir = MEMORY_TO_MEMORY;
} else if ((chan_cfg & XDMAC_CC_DSYNC_Msk) == XDMAC_CC_DSYNC_MEM2PER) {
status->dir = MEMORY_TO_PERIPHERAL;
} else {
status->dir = PERIPHERAL_TO_MEMORY;
}
status->busy = ((chan_cfg & XDMAC_CC_INITD_Msk) != 0) || (ublen > 0);
status->pending_length = ublen;
return 0;
}
static const struct dma_driver_api sam_xdmac_driver_api = {
.config = sam_xdmac_config,
.reload = sam_xdmac_transfer_reload,
.start = sam_xdmac_transfer_start,
.stop = sam_xdmac_transfer_stop,
.get_status = sam_xdmac_get_status,
};
/* DMA0 */

View File

@@ -658,7 +658,7 @@ static int spi_nor_erase(const struct device *dev, off_t addr, size_t size)
if ((etp->exp != 0)
&& SPI_NOR_IS_ALIGNED(addr, etp->exp)
&& SPI_NOR_IS_ALIGNED(size, etp->exp)
&& (size >= BIT(etp->exp))
&& ((bet == NULL)
|| (etp->exp > bet->exp))) {
bet = etp;

View File

@@ -43,10 +43,10 @@ static inline void i2c_dw_data_ask(const struct device *dev)
{
struct i2c_dw_dev_config * const dw = dev->data;
uint32_t data;
uint8_t tx_empty;
int8_t rx_empty;
uint8_t cnt;
uint8_t rx_buffer_depth, tx_buffer_depth;
int tx_empty;
int rx_empty;
int cnt;
int rx_buffer_depth, tx_buffer_depth;
union ic_comp_param_1_register ic_comp_param_1;
uint32_t reg_base = get_regs(dev);

View File

@@ -494,6 +494,11 @@ static int nrf5_tx(const struct device *dev,
uint8_t *payload = frag->data;
bool ret = true;
if (payload_len > NRF5_PSDU_LENGTH) {
LOG_ERR("Payload too large: %d", payload_len);
return -EMSGSIZE;
}
LOG_DBG("%p (%u)", payload, payload_len);
nrf5_radio->tx_psdu[0] = payload_len + NRF5_FCS_LENGTH;

View File

@@ -341,10 +341,11 @@ int sys_clock_driver_init(const struct device *dev)
alloc_mask = BIT_MASK(EXT_CHAN_COUNT) << 1;
}
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
compare_set(0, counter() + CYC_PER_TICK,
sys_clock_timeout_handler, NULL);
}
uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
MAX_CYCLES : CYC_PER_TICK;
compare_set(0, counter() + initial_timeout,
sys_clock_timeout_handler, NULL);
z_nrf_clock_control_lf_on(mode);

View File

@@ -266,6 +266,19 @@ struct bt_l2cap_chan_ops {
*/
void (*encrypt_change)(struct bt_l2cap_chan *chan, uint8_t hci_status);
/** @brief Channel alloc_seg callback
*
* If this callback is provided the channel will use it to allocate
* buffers to store segments. This avoids wasting big SDU buffers with
* potentially much smaller PDUs. If this callback is supplied, it must
* return a valid buffer.
*
* @param chan The channel requesting a buffer.
*
* @return Allocated buffer.
*/
struct net_buf *(*alloc_seg)(struct bt_l2cap_chan *chan);
/** @brief Channel alloc_buf callback
*
* If this callback is provided the channel will use it to allocate

View File

@@ -420,7 +420,7 @@ static inline uint8_t can_dlc_to_bytes(uint8_t dlc)
static const uint8_t dlc_table[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12,
16, 20, 24, 32, 48, 64};
return dlc > 0x0F ? 64 : dlc_table[dlc];
return dlc_table[MIN(dlc, ARRAY_SIZE(dlc_table) - 1)];
}
/**

View File

@@ -889,15 +889,6 @@ static inline void net_buf_simple_restore(struct net_buf_simple *buf,
buf->len = state->len;
}
/**
* Flag indicating that the buffer has associated fragments. Only used
* internally by the buffer handling code while the buffer is inside a
* FIFO, meaning this never needs to be explicitly set or unset by the
* net_buf API user. As long as the buffer is outside of a FIFO, i.e.
* in practice always for the user for this API, the buf->frags pointer
* should be used instead.
*/
#define NET_BUF_FRAGS BIT(0)
/**
* Flag indicating that the buffer's associated data pointer, points to
* externally allocated memory. Therefore once ref goes down to zero, the
@@ -907,7 +898,7 @@ static inline void net_buf_simple_restore(struct net_buf_simple *buf,
* Reference count mechanism however will behave the same way, and ref
* count going to 0 will free the net_buf but no the data pointer in it.
*/
#define NET_BUF_EXTERNAL_DATA BIT(1)
#define NET_BUF_EXTERNAL_DATA BIT(0)
/**
* @brief Network buffer representation.
@@ -917,13 +908,11 @@ static inline void net_buf_simple_restore(struct net_buf_simple *buf,
* using the net_buf_alloc() API.
*/
struct net_buf {
union {
/** Allow placing the buffer into sys_slist_t */
sys_snode_t node;
/** Allow placing the buffer into sys_slist_t */
sys_snode_t node;
/** Fragments associated with this buffer. */
struct net_buf *frags;
};
/** Fragments associated with this buffer. */
struct net_buf *frags;
/** Reference count. */
uint8_t ref;

View File

@@ -25,6 +25,7 @@
#include <zephyr/types.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -61,6 +62,23 @@ extern "C" {
/** @brief 0 if @p cond is true-ish; causes a compile error otherwise. */
#define ZERO_OR_COMPILE_ERROR(cond) ((int) sizeof(char[1 - 2 * !(cond)]) - 1)
/**
* @brief Determine if a buffer exceeds highest address
*
* This macro determines if a buffer identified by a starting address @a addr
* and length @a buflen spans a region of memory that goes beond the highest
* possible address (thereby resulting in a pointer overflow).
*
* @param addr Buffer starting address
* @param buflen Length of the buffer
*
* @return true if pointer overflow detected, false otherwise
*/
#define Z_DETECT_POINTER_OVERFLOW(addr, buflen) \
(((buflen) != 0) && \
((UINTPTR_MAX - (uintptr_t)(addr)) <= ((uintptr_t)((buflen) - 1))))
#if defined(__cplusplus)
/* The built-in function used below for type checking in C is not

View File

@@ -329,6 +329,22 @@ extern int z_user_string_copy(char *dst, const char *src, size_t maxlen);
*/
#define Z_SYSCALL_VERIFY(expr) Z_SYSCALL_VERIFY_MSG(expr, #expr)
/**
* @brief Macro to check if size is negative
*
* Z_SYSCALL_MEMORY can be called with signed/unsigned types
* and because of that if we check if size is greater or equal to
* zero, many static analyzers complain about no effect expression.
*
* @param ptr Memory area to examine
* @param size Size of the memory area
* @return true if size is valid, false otherwise
* @note This is an internal API. Do not use unless you are extending
* functionality in the Zephyr tree.
*/
#define Z_SYSCALL_MEMORY_SIZE_CHECK(ptr, size) \
(((uintptr_t)ptr + size) >= (uintptr_t)ptr)
/**
* @brief Runtime check that a user thread has read and/or write permission to
* a memory area
@@ -346,8 +362,10 @@ extern int z_user_string_copy(char *dst, const char *src, size_t maxlen);
* @return 0 on success, nonzero on failure
*/
#define Z_SYSCALL_MEMORY(ptr, size, write) \
Z_SYSCALL_VERIFY_MSG(arch_buffer_validate((void *)ptr, size, write) \
== 0, \
Z_SYSCALL_VERIFY_MSG(Z_SYSCALL_MEMORY_SIZE_CHECK(ptr, size) \
&& !Z_DETECT_POINTER_OVERFLOW(ptr, size) \
&& (arch_buffer_validate((void *)ptr, size, write) \
== 0), \
"Memory region %p (size %zu) %s access denied", \
(void *)(ptr), (size_t)(size), \
write ? "write" : "read")

View File

@@ -48,8 +48,9 @@
#endif
#undef BUILD_ASSERT /* clear out common version */
/* C++11 has static_assert built in */
#ifdef __cplusplus
#if defined(__cplusplus) && (__cplusplus >= 201103L)
#define BUILD_ASSERT(EXPR, MSG...) static_assert(EXPR, "" MSG)
/*

View File

@@ -2017,21 +2017,17 @@ class CMake():
def run_cmake(self, args=[]):
if self.warnings_as_errors:
ldflags = "-Wl,--fatal-warnings"
cflags = "-Werror"
aflags = "-Wa,--fatal-warnings"
warnings_as_errors = 'y'
gen_defines_args = "--edtlib-Werror"
else:
ldflags = cflags = aflags = ""
warnings_as_errors = 'n'
gen_defines_args = ""
logger.debug("Running cmake on %s for %s" % (self.source_dir, self.platform.name))
cmake_args = [
f'-B{self.build_dir}',
f'-S{self.source_dir}',
f'-DEXTRA_CFLAGS="{cflags}"',
f'-DEXTRA_AFLAGS="{aflags}',
f'-DEXTRA_LDFLAGS="{ldflags}"',
f'-DCONFIG_COMPILER_WARNINGS_AS_ERRORS={warnings_as_errors}',
f'-DEXTRA_GEN_DEFINES_ARGS={gen_defines_args}',
f'-G{self.generator}'
]

View File

@@ -1,7 +1,7 @@
# DOC: used to generate docs
breathe>=4.30
sphinx~=4.0
sphinx~=5.0.2
sphinx_rtd_theme~=1.0
sphinx-tabs
sphinxcontrib-svg2pdfconverter

View File

@@ -1181,6 +1181,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx,
/* Active scanner */
} else if (((pdu_adv_rx->type == PDU_ADV_TYPE_ADV_IND) ||
(pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_IND)) &&
(pdu_adv_rx->len >= offsetof(struct pdu_adv_adv_ind, data)) &&
(pdu_adv_rx->len <= sizeof(struct pdu_adv_adv_ind)) &&
lll->type &&
#if defined(CONFIG_BT_CENTRAL)
@@ -1274,6 +1275,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx,
else if (((((pdu_adv_rx->type == PDU_ADV_TYPE_ADV_IND) ||
(pdu_adv_rx->type == PDU_ADV_TYPE_NONCONN_IND) ||
(pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_IND)) &&
(pdu_adv_rx->len >= offsetof(struct pdu_adv_adv_ind, data)) &&
(pdu_adv_rx->len <= sizeof(struct pdu_adv_adv_ind))) ||
((pdu_adv_rx->type == PDU_ADV_TYPE_DIRECT_IND) &&
(pdu_adv_rx->len == sizeof(struct pdu_adv_direct_ind)) &&
@@ -1287,6 +1289,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx,
pdu_adv_rx, rl_idx)) ||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
((pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_RSP) &&
(pdu_adv_rx->len >= offsetof(struct pdu_adv_scan_rsp, data)) &&
(pdu_adv_rx->len <= sizeof(struct pdu_adv_scan_rsp)) &&
(lll->state != 0U) &&
isr_scan_rsp_adva_matches(pdu_adv_rx))) &&
@@ -1334,6 +1337,7 @@ static inline bool isr_scan_init_check(struct lll_scan *lll,
lll_scan_adva_check(lll, pdu->tx_addr, pdu->adv_ind.addr,
rl_idx)) &&
(((pdu->type == PDU_ADV_TYPE_ADV_IND) &&
(pdu->len >= offsetof(struct pdu_adv_adv_ind, data)) &&
(pdu->len <= sizeof(struct pdu_adv_adv_ind))) ||
((pdu->type == PDU_ADV_TYPE_DIRECT_IND) &&
(pdu->len == sizeof(struct pdu_adv_direct_ind)) &&

View File

@@ -41,6 +41,11 @@
struct tx_meta {
struct bt_conn_tx *tx;
/* This flag indicates if the current buffer has already been partially
* sent to the controller (ie, the next fragments should be sent as
* continuations).
*/
bool is_cont;
};
#define tx_data(buf) ((struct tx_meta *)net_buf_user_data(buf))
@@ -396,6 +401,8 @@ int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf,
tx_data(buf)->tx = NULL;
}
tx_data(buf)->is_cont = false;
net_buf_put(&conn->tx_queue, buf);
return 0;
}
@@ -464,25 +471,41 @@ static int send_iso(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
return bt_send(buf);
}
static bool send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
bool always_consume)
static inline uint16_t conn_mtu(struct bt_conn *conn)
{
#if defined(CONFIG_BT_BREDR)
if (conn->type == BT_CONN_TYPE_BR || !bt_dev.le.acl_mtu) {
return bt_dev.br.mtu;
}
#endif /* CONFIG_BT_BREDR */
#if defined(CONFIG_BT_ISO)
if (conn->type == BT_CONN_TYPE_ISO && bt_dev.le.iso_mtu) {
return bt_dev.le.iso_mtu;
}
#endif /* CONFIG_BT_ISO */
#if defined(CONFIG_BT_CONN)
return bt_dev.le.acl_mtu;
#else
return 0;
#endif /* CONFIG_BT_CONN */
}
static int do_send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags)
{
struct bt_conn_tx *tx = tx_data(buf)->tx;
uint32_t *pending_no_cb;
uint32_t *pending_no_cb = NULL;
unsigned int key;
int err = 0;
BT_DBG("conn %p buf %p len %u flags 0x%02x", conn, buf, buf->len,
flags);
/* Wait until the controller can accept ACL packets */
k_sem_take(bt_conn_get_pkts(conn), K_FOREVER);
/* Check for disconnection while waiting for pkts_sem */
if (conn->state != BT_CONN_CONNECTED) {
err = -ENOTCONN;
goto fail;
}
BT_DBG("conn %p buf %p len %u flags 0x%02x", conn, buf, buf->len,
flags);
/* Add to pending, it must be done before bt_buf_set_type */
key = irq_lock();
if (tx) {
@@ -520,46 +543,61 @@ static bool send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
(*pending_no_cb)--;
}
irq_unlock(key);
/* We don't want to end up in a situation where send_acl/iso
* returns the same error code as when we don't get a buffer in
* time.
*/
err = -EIO;
goto fail;
}
return true;
return 0;
fail:
/* If we get here, something has seriously gone wrong:
* We also need to destroy the `parent` buf.
*/
k_sem_give(bt_conn_get_pkts(conn));
if (tx) {
tx_free(tx);
}
if (always_consume) {
net_buf_unref(buf);
}
return false;
return err;
}
static inline uint16_t conn_mtu(struct bt_conn *conn)
static int send_frag(struct bt_conn *conn,
struct net_buf *buf, struct net_buf *frag,
uint8_t flags)
{
#if defined(CONFIG_BT_BREDR)
if (conn->type == BT_CONN_TYPE_BR || !bt_dev.le.acl_mtu) {
return bt_dev.br.mtu;
/* Check if the controller can accept ACL packets */
if (k_sem_take(bt_conn_get_pkts(conn), K_NO_WAIT)) {
BT_DBG("no controller bufs");
return -ENOBUFS;
}
#endif /* CONFIG_BT_BREDR */
#if defined(CONFIG_BT_ISO)
if (conn->type == BT_CONN_TYPE_ISO && bt_dev.le.iso_mtu) {
return bt_dev.le.iso_mtu;
/* Add the data to the buffer */
if (frag) {
uint16_t frag_len = MIN(conn_mtu(conn), net_buf_tailroom(frag));
net_buf_add_mem(frag, buf->data, frag_len);
net_buf_pull(buf, frag_len);
} else {
/* De-queue the buffer now that we know we can send it.
* Only applies if the buffer to be sent is the original buffer,
* and not one of its fragments.
* This buffer was fetched from the FIFO using a peek operation.
*/
buf = net_buf_get(&conn->tx_queue, K_NO_WAIT);
frag = buf;
}
#endif /* CONFIG_BT_ISO */
#if defined(CONFIG_BT_CONN)
return bt_dev.le.acl_mtu;
#else
return 0;
#endif /* CONFIG_BT_CONN */
return do_send_frag(conn, frag, flags);
}
static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf)
{
struct net_buf *frag;
uint16_t frag_len;
switch (conn->type) {
#if defined(CONFIG_BT_ISO)
@@ -583,52 +621,55 @@ static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf)
/* Fragments never have a TX completion callback */
tx_data(frag)->tx = NULL;
frag_len = MIN(conn_mtu(conn), net_buf_tailroom(frag));
net_buf_add_mem(frag, buf->data, frag_len);
net_buf_pull(buf, frag_len);
tx_data(frag)->is_cont = false;
return frag;
}
static bool send_buf(struct bt_conn *conn, struct net_buf *buf)
static int send_buf(struct bt_conn *conn, struct net_buf *buf)
{
struct net_buf *frag;
uint8_t flags;
int err;
BT_DBG("conn %p buf %p len %u", conn, buf, buf->len);
/* Send directly if the packet fits the ACL MTU */
if (buf->len <= conn_mtu(conn)) {
return send_frag(conn, buf, FRAG_SINGLE, false);
}
/* Create & enqueue first fragment */
frag = create_frag(conn, buf);
if (!frag) {
return false;
}
if (!send_frag(conn, frag, FRAG_START, true)) {
return false;
if (buf->len <= conn_mtu(conn) && !tx_data(buf)->is_cont) {
BT_DBG("send single");
return send_frag(conn, buf, NULL, FRAG_SINGLE);
}
BT_DBG("start fragmenting");
/*
* Send the fragments. For the last one simply use the original
* buffer (which works since we've used net_buf_pull on it.
* buffer (which works since we've used net_buf_pull on it).
*/
flags = FRAG_START;
if (tx_data(buf)->is_cont) {
flags = FRAG_CONT;
}
while (buf->len > conn_mtu(conn)) {
frag = create_frag(conn, buf);
if (!frag) {
return false;
return -ENOMEM;
}
if (!send_frag(conn, frag, FRAG_CONT, true)) {
return false;
err = send_frag(conn, buf, frag, flags);
if (err) {
BT_DBG("%p failed, mark as existing frag", buf);
tx_data(buf)->is_cont = flags != FRAG_START;
net_buf_unref(frag);
return err;
}
flags = FRAG_CONT;
}
return send_frag(conn, buf, FRAG_END, false);
BT_DBG("last frag");
tx_data(buf)->is_cont = true;
return send_frag(conn, buf, NULL, FRAG_END);
}
static struct k_poll_signal conn_change =
@@ -674,10 +715,26 @@ static int conn_prepare_events(struct bt_conn *conn,
BT_DBG("Adding conn %p to poll list", conn);
k_poll_event_init(&events[0],
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&conn->tx_queue);
bool buffers_available = k_sem_count_get(bt_conn_get_pkts(conn)) > 0;
bool packets_waiting = !k_fifo_is_empty(&conn->tx_queue);
if (packets_waiting && !buffers_available) {
/* Only resume sending when the controller has buffer space
* available for this connection.
*/
BT_DBG("wait on ctlr buffers");
k_poll_event_init(&events[0],
K_POLL_TYPE_SEM_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
bt_conn_get_pkts(conn));
} else {
/* Wait until there is more data to send. */
BT_DBG("wait on host fifo");
k_poll_event_init(&events[0],
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&conn->tx_queue);
}
events[0].tag = BT_EVENT_CONN_TX_QUEUE;
return 0;
@@ -720,6 +777,7 @@ int bt_conn_prepare_events(struct k_poll_event events[])
void bt_conn_process_tx(struct bt_conn *conn)
{
struct net_buf *buf;
int err;
BT_DBG("conn %p", conn);
@@ -730,10 +788,26 @@ void bt_conn_process_tx(struct bt_conn *conn)
return;
}
/* Get next ACL packet for connection */
buf = net_buf_get(&conn->tx_queue, K_NO_WAIT);
/* Get next ACL packet for connection. The buffer will only get dequeued
* if there is a free controller buffer to put it in.
*
* Important: no operations should be done on `buf` until it is properly
* dequeued from the FIFO, using the `net_buf_get()` API.
*/
buf = k_fifo_peek_head(&conn->tx_queue);
BT_ASSERT(buf);
if (!send_buf(conn, buf)) {
/* Since we used `peek`, the queue still owns the reference to the
* buffer, so we need to take an explicit additional reference here.
*/
buf = net_buf_ref(buf);
err = send_buf(conn, buf);
net_buf_unref(buf);
if (err == -EIO) {
tx_data(buf)->tx = NULL;
/* destroy the buffer */
net_buf_unref(buf);
}
}

View File

@@ -2372,6 +2372,13 @@ static void process_events(struct k_poll_event *ev, int count)
switch (ev->state) {
case K_POLL_STATE_SIGNALED:
break;
case K_POLL_STATE_SEM_AVAILABLE:
/* After this fn is exec'd, `bt_conn_prepare_events()`
* will be called once again, and this time buffers will
* be available, so the FIFO will be added to the poll
* list instead of the ctlr buffers semaphore.
*/
break;
case K_POLL_STATE_FIFO_DATA_AVAILABLE:
if (ev->tag == BT_EVENT_CMD_TX) {
send_cmd();
@@ -2431,6 +2438,7 @@ static void hci_tx_thread(void *p1, void *p2, void *p3)
events[0].state = K_POLL_STATE_NOT_READY;
ev_count = 1;
/* This adds the FIFO per-connection */
if (IS_ENABLED(CONFIG_BT_CONN) || IS_ENABLED(CONFIG_BT_ISO)) {
ev_count += bt_conn_prepare_events(&events[1]);
}

View File

@@ -873,6 +873,12 @@ static void l2cap_chan_tx_process(struct k_work *work)
if (sent < 0) {
if (sent == -EAGAIN) {
ch->tx_buf = buf;
/* If we don't reschedule, and the app doesn't nudge l2cap (e.g. by
* sending another SDU), the channel will be stuck in limbo. To
* prevent this, we attempt to re-schedule the work item for every
* channel on every connection when an SDU has successfully been
* sent.
*/
} else {
net_buf_unref(buf);
}
@@ -1693,13 +1699,20 @@ static void le_disconn_rsp(struct bt_l2cap *l2cap, uint8_t ident,
bt_l2cap_chan_del(&chan->chan);
}
static inline struct net_buf *l2cap_alloc_seg(struct net_buf *buf)
static inline struct net_buf *l2cap_alloc_seg(struct net_buf *buf, struct bt_l2cap_le_chan *ch)
{
struct net_buf_pool *pool = net_buf_pool_get(buf->pool_id);
struct net_buf *seg;
/* Try to use original pool if possible */
seg = net_buf_alloc(pool, K_NO_WAIT);
/* Use the dedicated segment callback if registered */
if (ch->chan.ops->alloc_seg) {
seg = ch->chan.ops->alloc_seg(&ch->chan);
__ASSERT_NO_MSG(seg);
} else {
/* Try to use original pool if possible */
seg = net_buf_alloc(pool, K_NO_WAIT);
}
if (seg) {
net_buf_reserve(seg, BT_L2CAP_CHAN_SEND_RESERVE);
return seg;
@@ -1736,7 +1749,8 @@ static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch,
}
segment:
seg = l2cap_alloc_seg(buf);
seg = l2cap_alloc_seg(buf, ch);
if (!seg) {
return NULL;
}
@@ -1767,6 +1781,17 @@ static void l2cap_chan_tx_resume(struct bt_l2cap_le_chan *ch)
k_work_submit(&ch->tx_work);
}
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
static void resume_all_channels(struct bt_conn *conn, void *data)
{
struct bt_l2cap_chan *chan;
SYS_SLIST_FOR_EACH_CONTAINER(&conn->channels, chan, node) {
l2cap_chan_tx_resume(BT_L2CAP_LE_CHAN(chan));
}
}
#endif
static void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data)
{
uint16_t cid = POINTER_TO_UINT(user_data);
@@ -1784,7 +1809,15 @@ static void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data)
chan->ops->sent(chan);
}
/* Resume the current channel */
l2cap_chan_tx_resume(BT_L2CAP_LE_CHAN(chan));
if (IS_ENABLED(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)) {
/* Resume all other channels in case one might be stuck.
* The current channel has already been given priority.
*/
bt_conn_foreach(BT_CONN_TYPE_LE, resume_all_channels, NULL);
}
}
static void l2cap_chan_seg_sent(struct bt_conn *conn, void *user_data)
@@ -1872,12 +1905,12 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch,
BT_WARN("Unable to send seg %d", err);
atomic_inc(&ch->tx.credits);
/* If the segment is not the original buffer release it since it
* won't be needed anymore.
/* The host takes ownership of the reference in seg when
* bt_l2cap_send_cb is successful. The call returned an error,
* so we must get rid of the reference that was taken in
* l2cap_chan_create_seg.
*/
if (seg != buf) {
net_buf_unref(seg);
}
net_buf_unref(seg);
if (err == -ENOBUFS) {
/* Restore state since segment could not be sent */
@@ -2142,12 +2175,19 @@ static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan,
struct net_buf *buf, uint16_t credits)
{
struct bt_l2cap_le_credits *ev;
uint16_t old_credits;
/* Cap the number of credits given */
if (credits > chan->rx.init_credits) {
credits = chan->rx.init_credits;
}
/* Don't send back more than the initial amount. */
old_credits = atomic_get(&chan->rx.credits);
if (credits + old_credits > chan->rx.init_credits) {
credits = chan->rx.init_credits - old_credits;
}
buf = l2cap_create_le_sig_pdu(buf, BT_L2CAP_LE_CREDITS, get_ident(),
sizeof(*ev));
if (!buf) {
@@ -2180,6 +2220,8 @@ static void l2cap_chan_update_credits(struct bt_l2cap_le_chan *chan,
credits = ((chan->_sdu_len - net_buf_frags_len(buf)) +
(chan->rx.mps - 1)) / chan->rx.mps;
BT_DBG("cred %d old %d", credits, (int)old_credits);
if (credits < old_credits) {
return;
}

View File

@@ -124,13 +124,22 @@ static void purge_buffers(sys_slist_t *list)
buf = (void *)sys_slist_get_not_empty(list);
buf->frags = NULL;
buf->flags &= ~NET_BUF_FRAGS;
net_buf_unref(buf);
}
}
static void purge_seg_buffers(struct net_buf *buf)
{
/* Fragments head has always 2 references: one when allocated, one when becomes
* fragments head.
*/
net_buf_unref(buf);
do {
buf = net_buf_frag_del(NULL, buf);
} while (buf != NULL);
}
/* Intentionally start a little bit late into the ReceiveWindow when
* it's large enough. This may improve reliability with some platforms,
* like the PTS, where the receiver might not have sufficiently compensated
@@ -166,8 +175,10 @@ static void friend_clear(struct bt_mesh_friend *frnd)
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
purge_buffers(&seg->queue);
seg->seg_count = 0U;
if (seg->buf) {
purge_seg_buffers(seg->buf);
seg->seg_count = 0U;
}
}
STRUCT_SECTION_FOREACH(bt_mesh_friend_cb, cb) {
@@ -1053,7 +1064,7 @@ init_friend:
static bool is_seg(struct bt_mesh_friend_seg *seg, uint16_t src, uint16_t seq_zero)
{
struct net_buf *buf = (void *)sys_slist_peek_head(&seg->queue);
struct net_buf *buf = seg->buf;
struct net_buf_simple_state state;
uint16_t buf_seq_zero;
uint16_t buf_src;
@@ -1086,7 +1097,7 @@ static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
return seg;
}
if (!unassigned && !sys_slist_peek_head(&seg->queue)) {
if (!unassigned && !seg->buf) {
unassigned = seg;
}
}
@@ -1121,16 +1132,13 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
return;
}
net_buf_slist_put(&seg->queue, buf);
seg->buf = net_buf_frag_add(seg->buf, buf);
if (type == BT_MESH_FRIEND_PDU_COMPLETE) {
sys_slist_merge_slist(&frnd->queue, &seg->queue);
net_buf_slist_put(&frnd->queue, seg->buf);
frnd->queue_size += seg->seg_count;
seg->seg_count = 0U;
} else {
/* Mark the buffer as having more to come after it */
buf->flags |= NET_BUF_FRAGS;
}
}
@@ -1244,6 +1252,15 @@ static void friend_timeout(struct k_work *work)
return;
}
/* Put next segment to the friend queue. */
if (frnd->last != net_buf_frag_last(frnd->last)) {
struct net_buf *next;
next = net_buf_frag_del(NULL, frnd->last);
net_buf_frag_add(NULL, next);
sys_slist_prepend(&frnd->queue, &next->node);
}
md = (uint8_t)(sys_slist_peek_head(&frnd->queue) != NULL);
update_overwrite(frnd->last, md);
@@ -1252,10 +1269,6 @@ static void friend_timeout(struct k_work *work)
return;
}
/* Clear the flag we use for segment tracking */
frnd->last->flags &= ~NET_BUF_FRAGS;
frnd->last->frags = NULL;
BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x",
frnd->last, frnd->lpn);
frnd->queue_size--;
@@ -1330,16 +1343,11 @@ int bt_mesh_friend_init(void)
for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
int j;
sys_slist_init(&frnd->queue);
k_work_init_delayable(&frnd->timer, friend_timeout);
k_work_init_delayable(&frnd->clear.timer, clear_timeout);
for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
sys_slist_init(&frnd->seg[j].queue);
}
}
return 0;
@@ -1635,11 +1643,16 @@ static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, uint16_t add
frnd->queue_size--;
avail_space++;
pending_segments = (buf->flags & NET_BUF_FRAGS);
if (buf != net_buf_frag_last(buf)) {
struct net_buf *next;
/* Make sure old slist entry state doesn't remain */
buf->frags = NULL;
buf->flags &= ~NET_BUF_FRAGS;
next = net_buf_frag_del(NULL, buf);
net_buf_frag_add(NULL, next);
sys_slist_prepend(&frnd->queue, &next->node);
pending_segments = true;
}
net_buf_unref(buf);
}
@@ -1762,7 +1775,7 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src,
BT_WARN("Clearing incomplete segments for 0x%04x", src);
purge_buffers(&seg->queue);
purge_seg_buffers(seg->buf);
seg->seg_count = 0U;
break;
}

View File

@@ -67,7 +67,10 @@ struct bt_mesh_friend {
struct k_work_delayable timer;
struct bt_mesh_friend_seg {
sys_slist_t queue;
/* First received segment of a segmented message. Rest
* segments are added as net_buf fragments.
*/
struct net_buf *buf;
/* The target number of segments, i.e. not necessarily
* the current number of segments, in the queue. This is

View File

@@ -907,7 +907,11 @@ static inline int send_sf(struct isotp_send_ctx *ctx)
frame.data[index++] = ISOTP_PCI_TYPE_SF | len;
__ASSERT_NO_MSG(len <= ISOTP_CAN_DL - index);
if (len > ISOTP_CAN_DL - index) {
LOG_ERR("SF len does not fit DL");
return -ENOSPC;
}
memcpy(&frame.data[index], data, len);
#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING
@@ -1202,6 +1206,7 @@ static int send(struct isotp_send_ctx *ctx, const struct device *can_dev,
ret = attach_fc_filter(ctx);
if (ret) {
LOG_ERR("Can't attach fc filter: %d", ret);
free_send_ctx(&ctx);
return ret;
}
@@ -1214,6 +1219,7 @@ static int send(struct isotp_send_ctx *ctx, const struct device *can_dev,
ret = send_sf(ctx);
ctx->state = ISOTP_TX_WAIT_FIN;
if (ret) {
free_send_ctx(&ctx);
return ret == CAN_TIMEOUT ?
ISOTP_N_TIMEOUT_A : ISOTP_N_ERROR;
}

View File

@@ -65,8 +65,15 @@ static void release_file_handle(size_t handle)
static bool is_mount_point(const char *path)
{
char dir_path[PATH_MAX];
size_t len;
sprintf(dir_path, "%s", path);
len = strlen(path);
if (len >= sizeof(dir_path)) {
return false;
}
memcpy(dir_path, path, len);
dir_path[len] = '\0';
return strcmp(dirname(dir_path), "/") == 0;
}

View File

@@ -1190,8 +1190,11 @@ void z_log_msg2_init(void)
struct log_msg2 *z_log_msg2_alloc(uint32_t wlen)
{
return (struct log_msg2 *)mpsc_pbuf_alloc(&log_buffer, wlen,
K_MSEC(CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS));
return (struct log_msg2 *)mpsc_pbuf_alloc(
&log_buffer, wlen,
(CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS == -1)
? K_FOREVER
: K_MSEC(CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS));
}
void z_log_msg2_commit(struct log_msg2 *msg)

View File

@@ -17,7 +17,7 @@ config NET_BUF_USER_DATA_SIZE
int "Size of user_data available in every network buffer"
default 24 if MCUMGR_SMP_UDP && MCUMGR_SMP_UDP_IPV6
default 8 if MCUMGR_SMP_UDP && MCUMGR_SMP_UDP_IPV4
default 8 if ((BT || NET_TCP2) && 64BIT) || BT_ISO || MCUMGR_SMP_BT
default 8 if ((BT || NET_TCP2) && 64BIT) || BT_CONN || BT_ISO
default 4
range 4 65535 if BT || NET_TCP2
range 0 65535

View File

@@ -405,7 +405,7 @@ struct net_buf *net_buf_get_debug(struct k_fifo *fifo, k_timeout_t timeout,
struct net_buf *net_buf_get(struct k_fifo *fifo, k_timeout_t timeout)
#endif
{
struct net_buf *buf, *frag;
struct net_buf *buf;
NET_BUF_DBG("%s():%d: fifo %p", func, line, fifo);
@@ -416,18 +416,6 @@ struct net_buf *net_buf_get(struct k_fifo *fifo, k_timeout_t timeout)
NET_BUF_DBG("%s():%d: buf %p fifo %p", func, line, buf, fifo);
/* Get any fragments belonging to this buffer */
for (frag = buf; (frag->flags & NET_BUF_FRAGS); frag = frag->frags) {
frag->frags = k_fifo_get(fifo, K_NO_WAIT);
__ASSERT_NO_MSG(frag->frags);
/* The fragments flag is only for FIFO-internal usage */
frag->flags &= ~NET_BUF_FRAGS;
}
/* Mark the end of the fragment list */
frag->frags = NULL;
return buf;
}
@@ -451,24 +439,19 @@ void net_buf_simple_reserve(struct net_buf_simple *buf, size_t reserve)
void net_buf_slist_put(sys_slist_t *list, struct net_buf *buf)
{
struct net_buf *tail;
unsigned int key;
__ASSERT_NO_MSG(list);
__ASSERT_NO_MSG(buf);
for (tail = buf; tail->frags; tail = tail->frags) {
tail->flags |= NET_BUF_FRAGS;
}
key = irq_lock();
sys_slist_append_list(list, &buf->node, &tail->node);
sys_slist_append(list, &buf->node);
irq_unlock(key);
}
struct net_buf *net_buf_slist_get(sys_slist_t *list)
{
struct net_buf *buf, *frag;
struct net_buf *buf;
unsigned int key;
__ASSERT_NO_MSG(list);
@@ -477,40 +460,15 @@ struct net_buf *net_buf_slist_get(sys_slist_t *list)
buf = (void *)sys_slist_get(list);
irq_unlock(key);
if (!buf) {
return NULL;
}
/* Get any fragments belonging to this buffer */
for (frag = buf; (frag->flags & NET_BUF_FRAGS); frag = frag->frags) {
key = irq_lock();
frag->frags = (void *)sys_slist_get(list);
irq_unlock(key);
__ASSERT_NO_MSG(frag->frags);
/* The fragments flag is only for list-internal usage */
frag->flags &= ~NET_BUF_FRAGS;
}
/* Mark the end of the fragment list */
frag->frags = NULL;
return buf;
}
void net_buf_put(struct k_fifo *fifo, struct net_buf *buf)
{
struct net_buf *tail;
__ASSERT_NO_MSG(fifo);
__ASSERT_NO_MSG(buf);
for (tail = buf; tail->frags; tail = tail->frags) {
tail->flags |= NET_BUF_FRAGS;
}
k_fifo_put_list(fifo, buf, tail);
k_fifo_put(fifo, buf);
}
#if defined(CONFIG_NET_BUF_LOG)

View File

@@ -210,7 +210,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
}
#endif
enum net_verdict net_ipv4_input(struct net_pkt *pkt)
enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback)
{
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
@@ -266,6 +266,19 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt)
net_pkt_update_length(pkt, pkt_len);
}
if (!is_loopback) {
if (net_ipv4_is_addr_loopback(&hdr->dst) ||
net_ipv4_is_addr_loopback(&hdr->src)) {
NET_DBG("DROP: localhost packet");
goto drop;
}
if (net_ipv4_is_my_addr(&hdr->src)) {
NET_DBG("DROP: src addr is %s", "mine");
goto drop;
}
}
if (net_ipv4_is_addr_mcast(&hdr->src)) {
NET_DBG("DROP: src addr is %s", "mcast");
goto drop;

View File

@@ -488,6 +488,11 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback)
NET_DBG("DROP: invalid scope multicast packet");
goto drop;
}
if (net_ipv6_is_my_addr(&hdr->src)) {
NET_DBG("DROP: src addr is %s", "mine");
goto drop;
}
}
/* Check extension headers */

View File

@@ -123,7 +123,7 @@ static inline enum net_verdict process_data(struct net_pkt *pkt,
#endif
#if defined(CONFIG_NET_IPV4)
case 0x40:
return net_ipv4_input(pkt);
return net_ipv4_input(pkt, is_loopback);
#endif
}

View File

@@ -69,12 +69,14 @@ static inline const char *net_context_state(struct net_context *context)
#endif
#if defined(CONFIG_NET_NATIVE)
enum net_verdict net_ipv4_input(struct net_pkt *pkt);
enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback);
enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback);
#else
static inline enum net_verdict net_ipv4_input(struct net_pkt *pkt)
static inline enum net_verdict net_ipv4_input(struct net_pkt *pkt,
bool is_loopback)
{
ARG_UNUSED(pkt);
ARG_UNUSED(is_loopback);
return NET_CONTINUE;
}

View File

@@ -205,8 +205,12 @@ again:
if (info) {
ret = info_len + sizeof(hdr);
ret = MIN(max_len, ret);
memcpy(&copy_to[sizeof(hdr)], info, ret);
if (ret > max_len) {
errno = EMSGSIZE;
return -1;
}
memcpy(&copy_to[sizeof(hdr)], info, info_len);
} else {
ret = 0;
}

View File

@@ -140,7 +140,13 @@ static int cmd_kernel_threads(const struct shell *shell,
shell_print(shell, "Scheduler: %u since last call", sys_clock_elapsed());
shell_print(shell, "Threads:");
k_thread_foreach(shell_tdata_dump, (void *)shell);
/*
* Use the unlocked version as the callback itself might call
* arch_irq_unlock.
*/
k_thread_foreach_unlocked(shell_tdata_dump, (void *)shell);
return 0;
}
@@ -184,7 +190,12 @@ static int cmd_kernel_stacks(const struct shell *shell,
ARG_UNUSED(argc);
ARG_UNUSED(argv);
k_thread_foreach(shell_stack_dump, (void *)shell);
/*
* Use the unlocked version as the callback itself might call
* arch_irq_unlock.
*/
k_thread_foreach_unlocked(shell_stack_dump, (void *)shell);
/* Placeholder logic for interrupt stack until we have better
* kernel support, including dumping arch-specific exception-related

View File

@@ -0,0 +1,21 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set\
the environment variable BSIM_COMPONENTS_PATH to point to its components \
folder. More information can be found in\
https://babblesim.github.io/folder_structure_and_env.html")
endif()
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
project(bsim_test_l2cap_stress)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources} )
zephyr_include_directories(
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
)

View File

@@ -0,0 +1,49 @@
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="L2CAP stress test"
CONFIG_BT_EATT=n
CONFIG_BT_L2CAP_ECRED=n
CONFIG_BT_SMP=y # Next config depends on it
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
# Disable auto-initiated procedures so they don't
# mess with the test's execution.
CONFIG_BT_AUTO_PHY_UPDATE=n
CONFIG_BT_AUTO_DATA_LEN_UPDATE=n
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
# L2CAP MPS
# 23+27+27=77 makes exactly three full packets
CONFIG_BT_L2CAP_TX_MTU=77
# Use this to send L2CAP PDUs without any fragmentation.
# In this particular case, we prefer fragmenting to test that code path.
# CONFIG_BT_BUF_ACL_TX_SIZE=81
# L2CAP PDUs will be fragmented in 3 ACL packets.
CONFIG_BT_BUF_ACL_TX_SIZE=27
CONFIG_BT_BUF_ACL_TX_COUNT=4
# The minimum value for this is
# L2AP MPS + L2CAP header (4)
CONFIG_BT_BUF_ACL_RX_SIZE=81
# Governs BT_CONN_TX_MAX, and so must be >= than the max number of
# peers, since we attempt to send one SDU per peer. The test execution
# is a bit slowed down by having this at the very minimum, but we want
# to keep it that way as to stress the stack as much as possible.
CONFIG_BT_L2CAP_TX_BUF_COUNT=6
CONFIG_BT_CTLR_DATA_LENGTH_MAX=27
CONFIG_BT_CTLR_RX_BUFFERS=10
CONFIG_BT_MAX_CONN=10
CONFIG_LOG=y
CONFIG_ASSERT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_NET_BUF_POOL_USAGE=y

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "common.h"
extern enum bst_result_t bst_result;
void test_init(void)
{
bst_ticker_set_next_tick_absolute(WAIT_TIME);
bst_result = In_progress;
}
void test_tick(bs_time_t HW_device_time)
{
if (bst_result != Passed) {
FAIL("test failed (not passed after %i seconds)\n", WAIT_SECONDS);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Common functions and helpers for L2CAP tests
*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <zephyr/types.h>
#include <sys/util.h>
#include <sys/byteorder.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/l2cap.h>
#include "bs_types.h"
#include "bs_tracing.h"
#include "bstests.h"
#include "bs_pc_backchannel.h"
extern enum bst_result_t bst_result;
#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false
#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true)
#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)false)
#define TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true)
#define WAIT_FOR_FLAG_SET(flag) \
while (!(bool)atomic_get(&flag)) { \
(void)k_sleep(K_MSEC(1)); \
}
#define WAIT_FOR_FLAG_UNSET(flag) \
while ((bool)atomic_get(&flag)) { \
(void)k_sleep(K_MSEC(1)); \
}
#define WAIT_SECONDS 270 /* seconds */
#define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /* microseconds*/
#define FAIL(...) \
do { \
bst_result = Failed; \
bs_trace_error_time_line(__VA_ARGS__); \
} while (0)
#define PASS(...) \
do { \
bst_result = Passed; \
bs_trace_info_time(1, __VA_ARGS__); \
} while (0)
#define ASSERT(expr, ...) if (!(expr)) {FAIL(__VA_ARGS__); }
void test_init(void);
void test_tick(bs_time_t HW_device_time);

View File

@@ -0,0 +1,462 @@
/* main_l2cap_stress.c - Application main entry point */
/*
* Copyright (c) 2022 Nordic Semiconductor
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "bstests.h"
#include "common.h"
#define LOG_MODULE_NAME main
#include <logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);
CREATE_FLAG(is_connected);
CREATE_FLAG(flag_l2cap_connected);
#define NUM_PERIPHERALS 6
#define L2CAP_CHANS NUM_PERIPHERALS
#define INIT_CREDITS 10
#define SDU_NUM 20
#define SDU_LEN 1230
#define NUM_SEGMENTS 10
/* Only one SDU per link will be transmitted at a time */
NET_BUF_POOL_DEFINE(sdu_tx_pool,
CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN),
8, NULL);
NET_BUF_POOL_DEFINE(segment_pool,
/* MTU + 4 l2cap hdr + 4 ACL hdr */
NUM_SEGMENTS, BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
8, NULL);
/* Only one SDU per link will be received at a time */
NET_BUF_POOL_DEFINE(sdu_rx_pool,
CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN),
8, NULL);
static struct bt_l2cap_le_chan l2cap_channels[L2CAP_CHANS];
static struct bt_l2cap_chan *l2cap_chans[L2CAP_CHANS];
static uint8_t tx_data[SDU_LEN];
static uint8_t tx_left[L2CAP_CHANS];
static uint16_t rx_cnt;
static uint8_t disconnect_counter;
int l2cap_chan_send(struct bt_l2cap_chan *chan, uint8_t *data, size_t len)
{
LOG_DBG("chan %p conn %p data %p len %d", chan, chan->conn, data, len);
struct net_buf *buf = net_buf_alloc(&sdu_tx_pool, K_NO_WAIT);
if (buf == NULL) {
FAIL("No more memory\n");
return -ENOMEM;
}
net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE);
net_buf_add_mem(buf, data, len);
int ret = bt_l2cap_chan_send(chan, buf);
if (ret < 0) {
FAIL("L2CAP error %d\n", ret);
net_buf_unref(buf);
}
LOG_DBG("sent %d len %d", ret, len);
return ret;
}
struct net_buf *alloc_seg_cb(struct bt_l2cap_chan *chan)
{
struct net_buf *buf = net_buf_alloc(&segment_pool, K_NO_WAIT);
ASSERT(buf, "Ran out of segment buffers");
return buf;
}
struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan)
{
return net_buf_alloc(&sdu_rx_pool, K_NO_WAIT);
}
static int get_l2cap_chan(struct bt_l2cap_chan *chan)
{
for (int i = 0; i < L2CAP_CHANS; i++) {
if (l2cap_chans[i] == chan) {
return i;
}
}
FAIL("Channel %p not found\n", chan);
return -1;
}
static void register_channel(struct bt_l2cap_chan *chan)
{
int i = get_l2cap_chan(NULL);
l2cap_chans[i] = chan;
}
void sent_cb(struct bt_l2cap_chan *chan)
{
LOG_DBG("%p", chan);
int idx = get_l2cap_chan(chan);
if (tx_left[idx]) {
tx_left[idx]--;
l2cap_chan_send(chan, tx_data, sizeof(tx_data));
} else {
LOG_DBG("Done sending %p", chan->conn);
}
}
int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
LOG_DBG("len %d", buf->len);
rx_cnt++;
/* Verify SDU data matches TX'd data. */
ASSERT(memcmp(buf->data, tx_data, buf->len) == 0, "RX data doesn't match TX");
return 0;
}
void l2cap_chan_connected_cb(struct bt_l2cap_chan *l2cap_chan)
{
struct bt_l2cap_le_chan *chan =
CONTAINER_OF(l2cap_chan, struct bt_l2cap_le_chan, chan);
SET_FLAG(flag_l2cap_connected);
LOG_DBG("%p (tx mtu %d mps %d) (tx mtu %d mps %d)",
l2cap_chan,
chan->tx.mtu,
chan->tx.mps,
chan->rx.mtu,
chan->rx.mps);
register_channel(l2cap_chan);
}
void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *chan)
{
UNSET_FLAG(flag_l2cap_connected);
LOG_DBG("%p", chan);
}
static struct bt_l2cap_chan_ops ops = {
.connected = l2cap_chan_connected_cb,
.disconnected = l2cap_chan_disconnected_cb,
.alloc_buf = alloc_buf_cb,
.alloc_seg = alloc_seg_cb,
.recv = recv_cb,
.sent = sent_cb,
};
struct bt_l2cap_le_chan *get_free_l2cap_le_chan(void)
{
for (int i = 0; i < L2CAP_CHANS; i++) {
struct bt_l2cap_le_chan *le_chan = &l2cap_channels[i];
if (le_chan->chan.state != BT_L2CAP_DISCONNECTED) {
continue;
}
memset(le_chan, 0, sizeof(*le_chan));
return le_chan;
}
return NULL;
}
int server_accept_cb(struct bt_conn *conn, struct bt_l2cap_chan **chan)
{
struct bt_l2cap_le_chan *le_chan = NULL;
le_chan = get_free_l2cap_le_chan();
if (le_chan == NULL) {
return -ENOMEM;
}
memset(le_chan, 0, sizeof(*le_chan));
le_chan->chan.ops = &ops;
le_chan->rx.mtu = SDU_LEN;
le_chan->rx.init_credits = INIT_CREDITS;
le_chan->tx.init_credits = INIT_CREDITS;
*chan = &le_chan->chan;
return 0;
}
static struct bt_l2cap_server test_l2cap_server = {
.accept = server_accept_cb
};
static int l2cap_server_register(bt_security_t sec_level)
{
test_l2cap_server.psm = 0;
test_l2cap_server.sec_level = sec_level;
int err = bt_l2cap_server_register(&test_l2cap_server);
ASSERT(err == 0, "Failed to register l2cap server.");
return test_l2cap_server.psm;
}
static void connected(struct bt_conn *conn, uint8_t conn_err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
if (conn_err) {
FAIL("Failed to connect to %s (%u)", addr, conn_err);
return;
}
LOG_DBG("%s", addr);
SET_FLAG(is_connected);
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_DBG("%p %s (reason 0x%02x)", conn, addr, reason);
UNSET_FLAG(is_connected);
disconnect_counter++;
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};
static void disconnect_device(struct bt_conn *conn, void *data)
{
int err;
SET_FLAG(is_connected);
err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
ASSERT(!err, "Failed to initate disconnect (err %d)", err);
LOG_DBG("Waiting for disconnection...");
WAIT_FOR_FLAG_UNSET(is_connected);
}
#define BT_LE_ADV_CONN_NAME_OT BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \
BT_LE_ADV_OPT_USE_NAME | \
BT_LE_ADV_OPT_ONE_TIME, \
BT_GAP_ADV_FAST_INT_MIN_2, \
BT_GAP_ADV_FAST_INT_MAX_2, NULL)
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
};
static void test_peripheral_main(void)
{
LOG_DBG("*L2CAP STRESS Peripheral started*");
int err;
/* Prepare tx_data */
for (size_t i = 0; i < sizeof(tx_data); i++) {
tx_data[i] = (uint8_t)i;
}
err = bt_enable(NULL);
if (err) {
FAIL("Can't enable Bluetooth (err %d)", err);
return;
}
LOG_DBG("Peripheral Bluetooth initialized.");
LOG_DBG("Connectable advertising...");
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME_OT, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
FAIL("Advertising failed to start (err %d)", err);
return;
}
LOG_DBG("Advertising started.");
LOG_DBG("Peripheral waiting for connection...");
WAIT_FOR_FLAG_SET(is_connected);
LOG_DBG("Peripheral Connected.");
int psm = l2cap_server_register(BT_SECURITY_L1);
LOG_DBG("Registered server PSM %x", psm);
LOG_DBG("Peripheral waiting for transfer completion");
while (rx_cnt < SDU_NUM) {
k_msleep(100);
}
bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device, NULL);
WAIT_FOR_FLAG_UNSET(is_connected);
LOG_INF("Total received: %d", rx_cnt);
PASS("L2CAP STRESS Peripheral passed\n");
}
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
struct net_buf_simple *ad)
{
struct bt_le_conn_param *param;
struct bt_conn *conn;
int err;
err = bt_le_scan_stop();
if (err) {
FAIL("Stop LE scan failed (err %d)", err);
return;
}
char str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(addr, str, sizeof(str));
LOG_DBG("Connecting to %s", str);
param = BT_LE_CONN_PARAM_DEFAULT;
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &conn);
if (err) {
FAIL("Create conn failed (err %d)", err);
return;
}
}
static void connect_peripheral(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_ACTIVE,
.options = BT_LE_SCAN_OPT_NONE,
.interval = BT_GAP_SCAN_FAST_INTERVAL,
.window = BT_GAP_SCAN_FAST_WINDOW,
};
UNSET_FLAG(is_connected);
int err = bt_le_scan_start(&scan_param, device_found);
ASSERT(!err, "Scanning failed to start (err %d)\n", err);
LOG_DBG("Central initiating connection...");
WAIT_FOR_FLAG_SET(is_connected);
}
static void connect_l2cap_channel(struct bt_conn *conn, void *data)
{
int err;
struct bt_l2cap_le_chan *le_chan = get_free_l2cap_le_chan();
ASSERT(le_chan, "No more available channels\n");
le_chan->chan.ops = &ops;
le_chan->rx.mtu = SDU_LEN;
le_chan->rx.init_credits = INIT_CREDITS;
le_chan->tx.init_credits = INIT_CREDITS;
UNSET_FLAG(flag_l2cap_connected);
err = bt_l2cap_chan_connect(conn, &le_chan->chan, 0x0080);
ASSERT(!err, "Error connecting l2cap channel (err %d)\n", err);
WAIT_FOR_FLAG_SET(flag_l2cap_connected);
}
static void test_central_main(void)
{
LOG_DBG("*L2CAP STRESS Central started*");
int err;
/* Prepare tx_data */
for (size_t i = 0; i < sizeof(tx_data); i++) {
tx_data[i] = (uint8_t)i;
}
err = bt_enable(NULL);
ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
LOG_DBG("Central Bluetooth initialized.");
/* Connect all peripherals */
for (int i = 0; i < NUM_PERIPHERALS; i++) {
connect_peripheral();
}
/* Connect L2CAP channels */
LOG_DBG("Connect L2CAP channels");
bt_conn_foreach(BT_CONN_TYPE_LE, connect_l2cap_channel, NULL);
/* Send SDU_NUM SDUs to each peripheral */
for (int i = 0; i < NUM_PERIPHERALS; i++) {
tx_left[i] = SDU_NUM;
l2cap_chan_send(l2cap_chans[i], tx_data, sizeof(tx_data));
}
LOG_DBG("Wait until all transfers are completed.");
int remaining_tx_total;
do {
k_msleep(100);
remaining_tx_total = 0;
for (int i = 0; i < L2CAP_CHANS; i++) {
remaining_tx_total += tx_left[i];
}
} while (remaining_tx_total);
LOG_DBG("Waiting until all peripherals are disconnected..");
while (disconnect_counter < NUM_PERIPHERALS) {
k_msleep(100);
}
LOG_DBG("All peripherals disconnected.");
PASS("L2CAP STRESS Central passed\n");
}
static const struct bst_test_instance test_def[] = {
{
.test_id = "peripheral",
.test_descr = "Peripheral L2CAP STRESS",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = test_peripheral_main
},
{
.test_id = "central",
.test_descr = "Central L2CAP STRESS",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = test_central_main
},
BSTEST_END_MARKER
};
struct bst_test_list *test_main_l2cap_stress_install(struct bst_test_list *tests)
{
return bst_add_tests(tests, test_def);
}
extern struct bst_test_list *test_main_l2cap_stress_install(struct bst_test_list *tests);
bst_test_install_t test_installers[] = {
test_main_l2cap_stress_install,
NULL
};
void main(void)
{
bst_main();
}

View File

@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Copyright (c) 2022 Nordic Semiconductor
# SPDX-License-Identifier: Apache-2.0
# EATT test
simulation_id="l2cap_stress"
verbosity_level=2
process_ids=""; exit_code=0
function Execute(){
if [ ! -f $1 ]; then
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
compile it?)\e[39m"
exit 1
fi
# timeout 30 $@ & process_ids="$process_ids $!"
$@ & process_ids="$process_ids $!"
}
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
#Give a default value to BOARD if it does not have one yet:
BOARD="${BOARD:-nrf52_bsim}"
cd ${BSIM_OUT_PATH}/bin
bsim_exe=./bs_${BOARD}_tests_bluetooth_bsim_bt_bsim_test_l2cap_stress_prj_conf
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -rs=43
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -rs=42
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=2 -testid=peripheral -rs=10
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=3 -testid=peripheral -rs=23
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=4 -testid=peripheral -rs=7884
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=5 -testid=peripheral -rs=230
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=6 -testid=peripheral -rs=9
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=7 -sim_length=270e6 $@
for process_id in $process_ids; do
wait $process_id || let "exit_code=$?"
done
exit $exit_code #the last exit code != 0

View File

@@ -61,6 +61,7 @@ app=tests/bluetooth/bsim_bt/bsim_test_app conf_file=prj_split_low_lat.conf \
compile
app=tests/bluetooth/bsim_bt/bsim_test_multiple compile
app=tests/bluetooth/bsim_bt/bsim_test_advx compile
app=tests/bluetooth/bsim_bt/bsim_test_l2cap_stress compile
app=tests/bluetooth/bsim_bt/bsim_test_iso compile
app=tests/bluetooth/bsim_bt/bsim_test_audio compile
app=tests/bluetooth/bsim_bt/edtt_ble_test_app/hci_test_app \

View File

@@ -440,7 +440,7 @@ static void test_icmpv4_send_echo_req(void)
zassert_true(false, "EchoRequest packet prep failed");
}
if (net_ipv4_input(pkt)) {
if (net_ipv4_input(pkt, false)) {
net_pkt_unref(pkt);
zassert_true(false, "Failed to send");
}
@@ -457,7 +457,7 @@ static void test_icmpv4_send_echo_rep(void)
zassert_true(false, "EchoReply packet prep failed");
}
if (net_ipv4_input(pkt)) {
if (net_ipv4_input(pkt, false)) {
net_pkt_unref(pkt);
zassert_true(false, "Failed to send");
}
@@ -476,7 +476,7 @@ static void test_icmpv4_send_echo_req_opt(void)
zassert_true(false, "EchoRequest with opts packet prep failed");
}
if (net_ipv4_input(pkt)) {
if (net_ipv4_input(pkt, false)) {
net_pkt_unref(pkt);
zassert_true(false, "Failed to send");
}
@@ -492,7 +492,7 @@ static void test_icmpv4_send_echo_req_bad_opt(void)
"EchoRequest with bad opts packet prep failed");
}
if (!net_ipv4_input(pkt)) {
if (!net_ipv4_input(pkt, false)) {
net_pkt_unref(pkt);
zassert_true(false, "Failed to send");
}

View File

@@ -1171,7 +1171,7 @@ static void test_src_localaddr_recv(void)
struct in6_addr localaddr = { { { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0, 0, 0x10 } } };
enum net_verdict verdict;
verdict = recv_msg(&localaddr, &addr);
@@ -1184,7 +1184,7 @@ static void test_dst_localaddr_recv(void)
struct in6_addr localaddr = { { { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0, 0, 0x10 } } };
enum net_verdict verdict;
verdict = recv_msg(&addr, &localaddr);
@@ -1197,7 +1197,7 @@ static void test_dst_iface_scope_mcast_recv(void)
struct in6_addr mcast_iface = { { { 0xff, 0x01, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } } };
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0, 0, 0x10 } } };
enum net_verdict verdict;
verdict = recv_msg(&addr, &mcast_iface);
@@ -1210,7 +1210,7 @@ static void test_dst_zero_scope_mcast_recv(void)
struct in6_addr mcast_zero = { { { 0xff, 0x00, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } } };
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0, 0, 0x10 } } };
enum net_verdict verdict;
verdict = recv_msg(&addr, &mcast_zero);
@@ -1223,7 +1223,7 @@ static void test_dst_site_scope_mcast_recv_drop(void)
struct in6_addr mcast_site = { { { 0xff, 0x05, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } } };
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0, 0, 0x10 } } };
enum net_verdict verdict;
verdict = recv_msg(&addr, &mcast_site);
@@ -1302,7 +1302,7 @@ static void test_dst_site_scope_mcast_recv_ok(void)
struct in6_addr mcast_all_dhcp = { { { 0xff, 0x05, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0x01, 0, 0, 0, 0x03 } } };
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0, 0, 0x10 } } };
enum net_verdict verdict;
struct net_context *ctx;
@@ -1329,7 +1329,7 @@ static void test_dst_org_scope_mcast_recv(void)
struct in6_addr mcast_org = { { { 0xff, 0x08, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } } };
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0, 0, 0x10 } } };
enum net_verdict verdict;
verdict = recv_msg(&addr, &mcast_org);
@@ -1342,7 +1342,7 @@ static void test_dst_iface_scope_mcast_send(void)
struct in6_addr mcast_iface = { { { 0xff, 0x01, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } } };
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0, 0, 0x10 } } };
struct net_if_mcast_addr *maddr;
struct net_context *ctx;
int ret;
@@ -1382,7 +1382,7 @@ static void test_dst_unknown_group_mcast_recv(void)
};
struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT;
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0x10 } } };
struct net_context *ctx;
enum net_verdict verdict;
@@ -1412,7 +1412,7 @@ static void test_dst_unjoined_group_mcast_recv(void)
};
struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT;
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0x10 } } };
struct net_if_mcast_addr *maddr;
struct net_context *ctx;
enum net_verdict verdict;
@@ -1454,7 +1454,7 @@ static void test_dst_is_other_iface_mcast_recv(void)
0x08 } } };
struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT;
struct in6_addr addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0x1 } } };
0, 0, 0, 0, 0, 0x10 } } };
struct net_if_mcast_addr *maddr;
struct net_context *ctx;
enum net_verdict verdict;

View File

@@ -976,7 +976,7 @@ static void test_virtual_recv_data_from_tunnel(int remote_ip,
net_pkt_cursor_init(outer);
if (peer_addr.sa_family == AF_INET) {
verdict = net_ipv4_input(outer);
verdict = net_ipv4_input(outer, false);
} else {
verdict = net_ipv6_input(outer, false);
}