This commit implements a new <AbstractNIC>.ipconfig() function for the NIC
classes that use lwIP, to set and retrieve network configuration for a NIC.
Currently this method supports:
- ipconfig("addr4"): obtain a tuple (addr, netmask) of the currently
configured ipv4 address
- ipconfig("addr6"): obtain a list of tuples (addr, state,
prefered_lifetime, valid_lifetime) of all currently active ipv6
addresses; this includes static, slaac and link-local addresses
- ipconfig("has_dhcp4"): whether ipv4 dhcp has supplied an address
- ipconfig("has_autoconf6"): if there is a valid, non-static ipv6 address
- ipconfig(addr4="1.2.3.4/24"): to set the ipv4 address and netmask
- ipconfig(addr6="2a01::2"): to set a static ipv6 address; note that this
does not configure an interface route, as this does not seem supported by
lwIP
- ipconfig(autoconf6=True): to enable ipv6 network configuration with slaac
- ipconfig(gw4="1.2.3.1"): to set the ipv4 gateway
- ipconfig(dhcp4=True): enable ipv4 dhcp; this sets ipv4 address, netmask,
gateway and a dns server
- ipconfig(dhcp4=False): stops dhcp, releases the ip, and clears the
configured ipv4 address.
- ipconfig(dhcp6=True): enable stateless dhcpv6 to obtain a dns server
There is also a new global configuration function network.ipconfig() that
supports the following:
- network.ipconfig(dns="2a01::2"): set the primary dns server (can be a
ipv4 or ipv6 address)
- network.ipconfig(prefer=6): to prefer ipv6 addresses to be returned as
dns responses (falling back to ipv4 if the host does not have an ipv6
address); note that this does not flush the dns cache, so if a host is
already in the dns cache with its v4 address, subsequent lookups will
return that address even if prefer=6 is set
This interface replaces NIC.ifconfig() completely, and ifconfig() should be
marked as deprecated and removed in a future version.
Signed-off-by: Felix Dörre <felix@dogcraft.de>
The STATIC macro was introduced a very long time ago in commit
d5df6cd44a. The original reason for this was
to have the option to define it to nothing so that all static functions
become global functions and therefore visible to certain debug tools, so
one could do function size comparison and other things.
This STATIC feature is rarely (if ever) used. And with the use of LTO and
heavy inline optimisation, analysing the size of individual functions when
they are not static is not a good representation of the size of code when
fully optimised.
So the macro does not have much use and it's simpler to just remove it.
Then you know exactly what it's doing. For example, newcomers don't have
to learn what the STATIC macro is and why it exists. Reading the code is
also less "loud" with a lowercase static.
One other minor point in favour of removing it, is that it stops bugs with
`STATIC inline`, which should always be `static inline`.
Methodology for this commit was:
1) git ls-files | egrep '\.[ch]$' | \
xargs sed -Ei "s/(^| )STATIC($| )/\1static\2/"
2) Do some manual cleanup in the diff by searching for the word STATIC in
comments and changing those back.
3) "git-grep STATIC docs/", manually fixed those cases.
4) "rg -t python STATIC", manually fixed codegen lines that used STATIC.
This work was funded through GitHub Sponsors.
Signed-off-by: Angus Gratton <angus@redyak.com.au>
Prior to commit 628abf8f25 which added IPv6
support, binding a socket with
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", PORT))
was possible. But, the empty string is not regarded as a valid IP address
by lwip. This commit adds a special case for the empty IP string,
restoring the previous CPython-compatible behaviour.
Signed-off-by: Felix Dörre <felix@dogcraft.de>
With these changes IPv6 works on the rp2 port (and possibly others that use
the lwIP socket implementation).
Things that have been tested and work:
- Neighbour solicitation for v6 link local address.
- Ping of v6 link-local address.
- Receiving a SLAAC address via router advertisement.
- Ping a v6 address allocated via SLAAC.
- Perform an outgoing connection to a routed v6-address (via default
gateway).
- Create a listening IPv6 wildcard socked bound to ::, and trying to access
it via link-local, SLAAC, and IPv4 (to ensure the dual-stack binding
works).
Things that could be improved:
- socket.socket().getaddrinfo only returns the v4 address. It could also
return v6 addresses (getaddrinfo is actively programmed to only return a
single address, and this is the v4-address by default, with fallback to
the v6 address if both are enabled).
Signed-off-by: Felix Dörre <felix@dogcraft.de>
See previous commit for details of these functions. As of this commit,
these still call the old hook macros on all ports.
This work was funded through GitHub Sponsors.
Signed-off-by: Angus Gratton <angus@redyak.com.au>
Updates any includes, and references from Makefiles/CMake.
This essentially reverts what was done long ago in commit
136b5cbd76
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This renames the builtin-modules, such that help('modules') and printing
the module object will show "module" rather than "umodule".
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
The actual underlying error number raised from the lwIP subsystem when
attempting to listen on a socket is swallowed and replaced with an
out-of-memory error which is confusing.
This commit passes the underlying error message from the lwIP subsystem to
the appropriate OSError exception.
Instead of being an explicit field, it's now a slot like all the other
methods.
This is a marginal code size improvement because most types have a make_new
(100/138 on PYBV11), however it improves consistency in how types are
declared, removing the special case for make_new.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
Previously the desired output type was specified. Now make the type part
of the function name. Because this function is used in a few places this
saves code size due to smaller call-site.
This makes `mp_obj_new_str_type_from_vstr` a private function of objstr.c
(which is almost the only place where the output type isn't a compile-time
constant).
This saves ~140 bytes on PYBV11.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This uses MP_REGISTER_ROOT_POINTER() to register lwip_slip_stream
instead of using a conditional inside of mp_state_vm_t.
Signed-off-by: David Lechner <david@pybricks.com>
The following changes are made:
- Guard entire file with MICROPY_PY_LWIP, so it can be included in the
build while still being disabled (for consistency with other extmod
modules).
- Add modlwip.c to list of all extmod source in py/py.mk and
extmod/extmod.cmake so all ports can easily use it.
- Move generic modlwip GIT_SUBMODULES build configuration code from
ports/rp2/CMakeLists.txt to extmod/extmod.cmake, so it can be reused by
other ports.
- Remove now unnecessary inclusion of modlwip.c in EXTMOD_SRC_C in esp8266
port, and in SRC_QSTR in mimxrt port.
Signed-off-by: Damien George <damien@micropython.org>
It's no longer needed because this macro is now processed after
preprocessing the source code via cpp (in the qstr extraction stage), which
means unused MP_REGISTER_MODULE's are filtered out by the preprocessor.
Signed-off-by: Damien George <damien@micropython.org>
This follows the CPython change: https://bugs.python.org/issue21455
Socket listen backlog defaults to 2 if not given, based on most bare metal
targets not having many resources for a large backlog. On UNIX it defaults
to SOMAXCONN or 128, whichever is less.
The correct callback-deregister functions must be called dependent on the
socket type, otherwise resources may not be freed correctly.
Signed-off-by: Damien George <damien@micropython.org>
This commit fixes the cases when a TCP socket is in STATE_NEW,
STATE_LISTENING or STATE_CONNECTING and recv() is called on it. It now
raises ENOTCONN instead of a random error code due to it previously
indexing beyond the start of error_lookup_table[].
Signed-off-by: Damien George <damien@micropython.org>
Fixes UDP non-blocking recv so it returns EAGAIN instead of ETIMEDOUT.
Timeout waiting for incoming data is also improved by replacing 100ms delay
with poll_sockets(), as is done in other parts of this module.
Fixes issue #5759.
POSIX poll should always return POLLERR and POLLHUP in revents, regardless
of whether they were requested in the input events flags.
See issues #4290 and #5172.
POSIX poll should always return POLLERR and POLLHUP in revents, regardless
of whether they were requested in the input events flags.
See issues #4290 and #5172.
The helper function exec_user_callback executes within the context of an
lwIP C callback, and the user (Python) callback to be scheduled may want to
perform further TCP/IP actions, so the latter should be scheduled to run
outside the lwIP context (otherwise it's effectively a "hard IRQ" and such
callbacks have lots of restrictions).
If tcp_write returns ERR_MEM then it's not a fatal error but instead means
the caller should retry the write later on (and this is what lwIP's netconn
API does).
This fixes problems where a TCP send would raise OSError(ENOMEM) in
situations where the TCP/IP stack is under heavy load. See eg issues #1897
and #1971.
In d5f0c87bb9 this call to tcp_poll() was
added to put a timeout on closing TCP sockets. But after calling
tcp_close() the PCB may be freed and therefore invalid, so tcp_poll() can
not be used at that point. As a fix this commit calls tcp_poll() before
closing the TCP PCB. If the PCB is subsequently closed and freed by
tcp_close() or tcp_abort() then the PCB will not be on any active list and
the callback will not be executed, which is the desired behaviour (the
_lwip_tcp_close_poll() callback only needs to be called if the PCB remains
active for longer than the timeout).
Commit 2848a613ac introduced a bug where
lwip_socket_free_incoming() accessed pcb.tcp->state after the PCB was
closed. The state may have changed due to that close call, or the PCB may
be freed and therefore invalid. This commit fixes that by calling
lwip_socket_free_incoming() before the PCB is closed.
Since commit da938a83b5 the tcp_arg() that is
set for the new connection is the new connection itself, and the parent
listening socket is found in the pcb->connected entry.