A bug was introduced in the atomic vector feature for blocking netconns
where if we couldn't write the entire vector due to send buffer being
full (write_more is 0), we would not update the vector state and then
when sent_tcp() is called, it would actually re-send the previous vector
and if additional calls were required to finish the write, msg.w.offset
would eventually exceed msg.w.len, This was found by testing "stats"
from the shell and hitting the LWIP_ASSERT in do_writemore() that
checks offset < len
The fix simply updates the vector state after every ERR_OK return from
tcp_write(). While not all cases (non-blocking sockets) need to update
the state in this case, it keeps the logic simple and also makes
debugging simpler because you don't have stale vector state at any
point
This commit adds support to the netconn write APIs to take an input of
vectors instead of a single data pointer
This allows vectors sent on a TCP connection via sendmsg to be treated
atomically. The set of vectors is segmented into as much data as can
fit into the send buffer and then the TCP output function is called
Previously, each vector was passed to netconn_write_partly and tcp_write
segmented it into its own packet, which was then it was sent via
tcp_output (if not Nagleing)
This commit adds vector support to lwip_netconn_do_writemore() which
is the meat of the TCP write functionality from netconn/sockets layer.
A new netconn API netconn_write_vectors_partly() takes a set of vectors
as input and hooks up to do_writemore()
This commit also defines IOV_MAX because we are limited to only
supporting 65535 vectors due to choice of u16_t for the vector count
This commit changes netconn_write_partly to use msg.w.offset to set
bytes_written for both blocking and non-blocking connections
This is correct because msg.w.offset is the canonical output from
the do_write call and in the case that not all bytes were written,
(a bug?) returning the full size to the caller is dangerous
Lastly, this commit adds an assert for the blocking case to sanity
check that all the bytes we requested were written. This will help
catch bugs in do_write
This commit makes a couple of cleanups discussed in patch #8882:
1) msg.w.offset should not be set to 0 in the error case. It is
only valid when err == ERR_OK
2) Remove out-of-date comment which indicated the entire write had
completed (not true for non-blocking write)
This also updates the documentation on offset to include that offset
is only valid when err == ERR_OK
This moves the write_offset variable from struct netconn to struct api_msg
This optimizes the storage by only having the space claimed when it is
needed (during a netconn_write_partly() call) and not throughout the
lifetime of the netconn
This also reduces code space/execution by not having to separately manage
clearing/checking write_offset from the current_msg pointer
Lastly, we also save execution by using msg.w.offset as the output
rather than marshaling the result to msg.w.len. Previously, len was used
as input length of dataptr and output for the write operation.
netconn_write_partly() also has access to msg.w.offset, so we can use
that
So far, the UDP core module implemented only IPv4 multicast support.
This patch extends the module with the features necessary for socket
layers on top to implement IPv6 multicast support as well:
o If a UDP PCB is bound to an IPv6 multicast address, a unicast source
address is selected and used to send the packet instead, as is
required (and was the case for IPv4 multicast already).
o Unlike IPv4's IP_MULTICAST_IF socket option, which takes a source
IPv4 address, the IPV6_MULTICAST_IF socket option (from RFC 3493)
takes an interface identifier to denote the interface to use for
outgoing multicast-destined packets. A new pair of UDP PCB API
calls, udp_[gs]et_multicast_netif_index(), are added to support
this. The new definition "NETIF_NO_INDEX" may be used to indicate
that lwIP should pick an interface instead.
IPv4 socket implementations may now also choose to map the given
source address to an interface index immediately and use the new
facility instead of the old udp_[gs]et_multicast_netif_addr() one.
A side effect of limiting the old facility to IPv4 is that for dual-
stack configurations with multicast support, the UDP PCB size is
reduced by (up to) 16 bytes.
o For configurations that enable loopback interface support, the IPv6
code now also supports multicast loopback (IPV6_MULTICAST_LOOP).
o The LWIP_MULTICAST_TX_OPTIONS opt.h setting now covers both IPv4
and IPv6, and as such is no longer strictly linked to IGMP. It is
therefore placed in its own lwIP options subgroup in opt.h.
The IPV6_MULTICAST_HOPS socket option can already be implemented using
the existing IP_MULTICAST_TTL support, and thus requires no additional
changes. Overall, this patch should not break any existing code.
This commit adds support in if_indextoname() to return ENXIO when
no interface is found. This conforms to the Open Group/RFC 3493
specification
In order to leverage errno set support, the set_errno macro from
sockets.c was moved to sockets_priv.h
This commit introduces a sockets_priv.h header for socket API internal
implementations intended to be used by sockets API C files, but not
applications
This commit moves struct lwip_setgetsockopt_data to the private header
because this is not part of the public sockets API, but needs to be
shared between sockets.c and memp.c
This header lays ground work for sharing other internal sockets types
/macros between API files (sockets.c and if_api.c)
This fixes the following build failure with MSVC 2013:
sockets.c(323): warning C4242: '=' : conversion from 'const u32_t' to 'u8_t', possible loss of data
This casts sin6_scope_id to a u8_t before calling ip6_addr_set_zone()
Couple of more cleanups for task #14314 involving includes:
1) if.h name should match if_api.c due to LwIP convention and history.
Standard if.h include can be used with compatibility header in
posix/net/if.h
2) API header (if.h) should not be included in core code. This include
has been eliminated by moving the definition of IF_NAMESIZE to
netif.h as NETIF_NAMESIZE. This is now the canonical definition
and IF_NAMESIZE just maps to it to provide the standard type
This patch adds full support for IPv6 address scopes, thereby aiming
to be compliant with IPv6 standards in general and RFC 4007 in
particular. The high-level summary is that link-local addresses are
now meaningful only in the context of their own link, guaranteeing
full isolation between links (and their addresses) in this respect.
This isolation even allows multiple interfaces to have the same
link-local addresses locally assigned.
The implementation achieves this by extending the lwIP IPv6 address
structure with a zone field that, for addresses that have a scope,
carries the scope's zone in which that address has meaning. The zone
maps to one or more interfaces. By default, lwIP uses a policy that
provides a 1:1 mapping between links and interfaces, and considers
all other addresses unscoped, corresponding to the default policy
sketched in RFC 4007 Sec. 6. The implementation allows for replacing
the default policy with a custom policy if desired, though.
The lwIP core implementation has been changed to provide somewhat of
a balance between correctness and efficiency on on side, and backward
compatibility on the other. In particular, while the application would
ideally always provide a zone for a scoped address, putting this in as
a requirement would likely break many applications. Instead, the API
accepts both "properly zoned" IPv6 addresses and addresses that, while
scoped, "lack" a zone. lwIP will try to add a zone as soon as possible
for efficiency reasons, in particular from TCP/UDP/RAW PCB bind and
connect calls, but this may fail, and sendto calls may bypass that
anyway. Ultimately, a zone is always added when an IP packet is sent
when needed, because the link-layer lwIP code (and ND6 in particualar)
requires that all addresses be properly zoned for correctness: for
example, to provide isolation between links in the ND6 destination
cache. All this applies to packet output only, because on packet
input, all scoped addresses will be given a zone automatically.
It is also worth remarking that on output, no attempt is made to stop
outgoing packets with addresses for a zone not matching the outgoing
interface. However, unless the application explicitly provides
addresses that will result in such zone violations, the core API
implementation (and the IPv6 routing algorithm in particular) itself
will never take decisions that result in zone violations itself.
This patch adds a new header file, ip6_zone.h, which contains comments
that explain several implementation aspects in a bit more detail.
For now, it is possible to disable scope support by changing the new
LWIP_IPV6_SCOPES configuration option. For users of the core API, it
is important to note that scoped addresses that are locally assigned
to a netif must always have a zone set; the standard netif address
assignment functions always do this on behalf of the caller, though.
Also, core API users will want to enable LWIP_IPV6_SCOPES_DEBUG at
least initially when upgrading, to ensure that all addresses are
properly initialized.
This renames if.c to if_api.c in order to avoid using a common source
file name which may collide with other source files from non-LwIP
projects. See discussion in task #14314