[PATCHv10 00/15] net/lwip: add lwip library for the network stack

changelog: v10: - fix ping with following tftp command issue with incorrect ping timeout clear. - Makefile on make will init submodules and if needed will do git clone. - wget - some minor code style changes. v9: - added first patch describing git submodule for lwip. So the build procedure is: git submodule init git submodule update make - reworked a little bit dhcp cmd state polling - fixed review comments for v8 v8: - comments for previous review - removed lwip timeout callback pointer - made lwip timeouts works, that also allowed to remove static vars. - setenv for filesize tftp and wget has to be in hex. - Makefile changes always compile it tftp,dns,wget,ping due to it can be used not only by CONFIG_CMD_. - Kconfig changes - simplify lwIP settings and support only one configuration. - tested with mini debian.iso load over http or tftp, mount and boot it (qemu, arm64). v7: - more review fixes. - support of multiply eth devices, were "ethact" selects the active device. v6: - fixed review comments for v5 (thanks Ilias and Simon). v5: - fixed Iliases comments and split big patch on the small ones. v4: - tested with tests/py/ did some minor fixes (out of tree build, variables set after downloads). - accounted review comments for documentation. - implemented dns command - corrected wget command to not use serverip variable and use just url string. v3: - use lwip commands for ping,tftp,wget,dhcp if this patch applied. Drop CONFIG_LIB_LWIP_REPLACE_<COMMAND> option. - docs: use rst variant and drop references to RFC.
Maxim Uvarov (15): submodule: add lwIP as git submodule Makefile: init submodules net/lwip: add doc/develop/net_lwip.rst net/lwip: integrate lwIP library net/lwip: implement dns cmd net/lwip: implement dhcp cmd net/lwip: implement tftp cmd net/lwip: implement wget cmd net/lwip: implement ping cmd net/lwip: add lwIP configuration net/lwip: implement lwIP port to U-Boot net/lwip: update .gitignore with lwIP net/lwip: connection between cmd and lwip apps net/lwip: replace original net commands with lwip net/lwip: split net.h to net.h, arp.h and eth.h
.gitmodules | 3 + Makefile | 5 +- boot/bootmeth_efi.c | 18 +- boot/bootmeth_pxe.c | 21 +- cmd/Makefile | 1 + cmd/net-lwip.c | 286 ++++++++++++++++++++++ cmd/net.c | 86 +------ cmd/pxe.c | 19 +- doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 75 ++++++ include/net.h | 197 +-------------- include/net/arp.h | 7 + include/net/eth.h | 190 +++++++++++++++ include/net/lwip.h | 73 ++++++ include/net/ulwip.h | 64 +++++ net/Kconfig | 3 + net/Makefile | 1 + net/eth-uclass.c | 8 + net/lwip/.gitignore | 8 + net/lwip/Kconfig | 25 ++ net/lwip/Makefile | 70 ++++++ net/lwip/apps/dhcp/lwip-dhcp.c | 85 +++++++ net/lwip/apps/dns/lwip-dns.c | 63 +++++ net/lwip/apps/http/Makefile | 6 + net/lwip/apps/http/lwip-wget.c | 105 ++++++++ net/lwip/apps/ping/Makefile | 12 + net/lwip/apps/ping/lwip_ping.c | 39 +++ net/lwip/apps/ping/lwip_ping.h | 15 ++ net/lwip/apps/ping/ping.h | 27 +++ net/lwip/apps/tftp/Makefile | 7 + net/lwip/apps/tftp/lwip-tftp.c | 129 ++++++++++ net/lwip/lwip-external | 1 + net/lwip/lwipopts.h | 178 ++++++++++++++ net/lwip/port/if.c | 332 ++++++++++++++++++++++++++ net/lwip/port/include/arch/cc.h | 38 +++ net/lwip/port/include/arch/sys_arch.h | 10 + net/lwip/port/include/limits.h | 0 net/lwip/port/sys-arch.c | 13 + net/net.c | 20 +- 39 files changed, 1951 insertions(+), 290 deletions(-) create mode 100644 .gitmodules create mode 100644 cmd/net-lwip.c create mode 100644 doc/develop/net_lwip.rst create mode 100644 include/net/arp.h create mode 100644 include/net/eth.h create mode 100644 include/net/lwip.h create mode 100644 include/net/ulwip.h create mode 100644 net/lwip/.gitignore create mode 100644 net/lwip/Kconfig create mode 100644 net/lwip/Makefile create mode 100644 net/lwip/apps/dhcp/lwip-dhcp.c create mode 100644 net/lwip/apps/dns/lwip-dns.c create mode 100644 net/lwip/apps/http/Makefile create mode 100644 net/lwip/apps/http/lwip-wget.c create mode 100644 net/lwip/apps/ping/Makefile create mode 100644 net/lwip/apps/ping/lwip_ping.c create mode 100644 net/lwip/apps/ping/lwip_ping.h create mode 100644 net/lwip/apps/ping/ping.h create mode 100644 net/lwip/apps/tftp/Makefile create mode 100644 net/lwip/apps/tftp/lwip-tftp.c create mode 160000 net/lwip/lwip-external create mode 100644 net/lwip/lwipopts.h create mode 100644 net/lwip/port/if.c create mode 100644 net/lwip/port/include/arch/cc.h create mode 100644 net/lwip/port/include/arch/sys_arch.h create mode 100644 net/lwip/port/include/limits.h create mode 100644 net/lwip/port/sys-arch.c

add external lwIP library as a git submodule. Use STABLE-2_2_0_RELEASE tag.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- .gitmodules | 3 +++ net/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 net/lwip/lwip-external
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..245ecff585 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lwip"] + path = net/lwip/lwip-external + url = https://git.savannah.nongnu.org/git/lwip.git diff --git a/net/lwip/lwip-external b/net/lwip/lwip-external new file mode 160000 index 0000000000..0a0452b2c3 --- /dev/null +++ b/net/lwip/lwip-external @@ -0,0 +1 @@ +Subproject commit 0a0452b2c39bdd91e252aef045c115f88f6ca773

Hi Maxim,
On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov maxim.uvarov@linaro.org wrote:
add external lwIP library as a git submodule. Use STABLE-2_2_0_RELEASE tag.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
.gitmodules | 3 +++ net/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 net/lwip/lwip-external
I really don't agree with having submodules in U-Boot. It's just a huge hassle that we don't need. We still haven't figured out how to deal with config fragments.
If no one else is interested in maintaining this stack within U-Boot and syncing up every now and then, perhaps we should reconsider bringing this into U-Boot? We would never normally accept such a large body of code without even a MAINTAINERS entry. Without a network maintainer, even the integration layer will struggle to keep up and up-revving won't be possible anyway.
In any case, if we go with lwip, we should copy in just the code that is needed, unchanged,
Regards, Simon

On Tue, Sep 26, 2023 at 05:37:25AM -0600, Simon Glass wrote:
Hi Maxim,
On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov maxim.uvarov@linaro.org wrote:
add external lwIP library as a git submodule. Use STABLE-2_2_0_RELEASE tag.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
.gitmodules | 3 +++ net/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 net/lwip/lwip-external
Do you have comments on the rest of the series?

Hi Tom,
On Tue, 26 Sept 2023 at 07:41, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 05:37:25AM -0600, Simon Glass wrote:
Hi Maxim,
On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov maxim.uvarov@linaro.org wrote:
add external lwIP library as a git submodule. Use STABLE-2_2_0_RELEASE tag.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
.gitmodules | 3 +++ net/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 net/lwip/lwip-external
Do you have comments on the rest of the series?
Not yet, but I should be able to review the rest in a few days. My main comments before were minor - return codes, tests, error checking.
Regards, Simon

On Tue, Sep 26, 2023 at 08:16:35AM -0600, Simon Glass wrote:
Hi Tom,
On Tue, 26 Sept 2023 at 07:41, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 05:37:25AM -0600, Simon Glass wrote:
Hi Maxim,
On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov maxim.uvarov@linaro.org wrote:
add external lwIP library as a git submodule. Use STABLE-2_2_0_RELEASE tag.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
.gitmodules | 3 +++ net/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 net/lwip/lwip-external
Do you have comments on the rest of the series?
Not yet, but I should be able to review the rest in a few days. My main comments before were minor - return codes, tests, error checking.
OK, thanks. I don't know how exactly I want to proceed with the core of lwip itself, but that doesn't block reviewing and testing the rest of it as we'll move forward with it one way or another.

Can somebody help me to understand and reproduce CI errors? I can run locally 'make check' which runs a bunch of local builds with binman and all of them are fine. It looks like some dependency is missing or addition 'git config --global --add safe.directory <path>/net/lwip/lwip-external' is required for the submodule directory.
https://source.denx.de/u-boot/custodians/u-boot-tpm/-/pipelines/17916
Building current source for 1 boards (0 threads, 24 jobs per thread) sandbox: + sandbox_spl +fatal: not a git repository (or any of the parent directories): .git +make[1]: *** [Makefile:1875: initsubmodules] Error 128 +make: *** [Makefile:177: sub-make] Error 2 0 0 1 /1 sandbox_spl Completed: 1 total built, 1 newly), duration 0:00:06, rate 0.17 Traceback (most recent call last): File "/builds/u-boot/custodians/u-boot-tpm/./tools/binman/binman", line 45, in <module> from binman import cmdline File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/cmdline.py", line 11, in <module> from binman import state File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/state.py", line 14, in <module> from dtoc import fdt File "/builds/u-boot/custodians/u-boot-tpm/tools/dtoc/fdt.py", line 14, in <module> from libfdt import QUIET_NOTFOUND ImportError: cannot import name 'QUIET_NOTFOUND' from 'libfdt' (unknown location)
On Tue, 26 Sept 2023 at 20:19, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 08:16:35AM -0600, Simon Glass wrote:
Hi Tom,
On Tue, 26 Sept 2023 at 07:41, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 05:37:25AM -0600, Simon Glass wrote:
Hi Maxim,
On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov maxim.uvarov@linaro.org
wrote:
add external lwIP library as a git submodule. Use STABLE-2_2_0_RELEASE tag.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
.gitmodules | 3 +++ net/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 net/lwip/lwip-external
Do you have comments on the rest of the series?
Not yet, but I should be able to review the rest in a few days. My main comments before were minor - return codes, tests, error checking.
OK, thanks. I don't know how exactly I want to proceed with the core of lwip itself, but that doesn't block reviewing and testing the rest of it as we'll move forward with it one way or another.
-- Tom

I found what was missing. (reproduced with CI docker.)
On Mon, 2 Oct 2023 at 12:34, Maxim Uvarov maxim.uvarov@linaro.org wrote:
Can somebody help me to understand and reproduce CI errors? I can run locally 'make check' which runs a bunch of local builds with binman and all of them are fine. It looks like some dependency is missing or addition 'git config --global --add safe.directory <path>/net/lwip/lwip-external' is required for the submodule directory.
https://source.denx.de/u-boot/custodians/u-boot-tpm/-/pipelines/17916
Building current source for 1 boards (0 threads, 24 jobs per thread) sandbox: + sandbox_spl +fatal: not a git repository (or any of the parent directories): .git +make[1]: *** [Makefile:1875: initsubmodules] Error 128 +make: *** [Makefile:177: sub-make] Error 2 0 0 1 /1 sandbox_spl Completed: 1 total built, 1 newly), duration 0:00:06, rate 0.17 Traceback (most recent call last): File "/builds/u-boot/custodians/u-boot-tpm/./tools/binman/binman", line 45, in <module> from binman import cmdline File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/cmdline.py", line 11, in <module> from binman import state File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/state.py", line 14, in <module> from dtoc import fdt File "/builds/u-boot/custodians/u-boot-tpm/tools/dtoc/fdt.py", line 14, in <module> from libfdt import QUIET_NOTFOUND ImportError: cannot import name 'QUIET_NOTFOUND' from 'libfdt' (unknown location)
On Tue, 26 Sept 2023 at 20:19, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 08:16:35AM -0600, Simon Glass wrote:
Hi Tom,
On Tue, 26 Sept 2023 at 07:41, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 05:37:25AM -0600, Simon Glass wrote:
Hi Maxim,
On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov <
maxim.uvarov@linaro.org> wrote:
add external lwIP library as a git submodule. Use STABLE-2_2_0_RELEASE tag.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
.gitmodules | 3 +++ net/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 net/lwip/lwip-external
Do you have comments on the rest of the series?
Not yet, but I should be able to review the rest in a few days. My main comments before were minor - return codes, tests, error checking.
OK, thanks. I don't know how exactly I want to proceed with the core of lwip itself, but that doesn't block reviewing and testing the rest of it as we'll move forward with it one way or another.
-- Tom

Hi Maxim,
On Mon, 2 Oct 2023 at 05:23, Maxim Uvarov maxim.uvarov@linaro.org wrote:
I found what was missing. (reproduced with CI docker.)
How about adding a script that copies in the lwip code needed for U-Boot, that you (or whoever the maintainer is) can run each quarter?
Alternatively, I think just sending a patch with the code would be helpful, so we can see what you are wanting to include.
Regards, Simon
On Mon, 2 Oct 2023 at 12:34, Maxim Uvarov maxim.uvarov@linaro.org wrote:
Can somebody help me to understand and reproduce CI errors? I can run locally 'make check' which runs a bunch of local builds with binman and all of them are fine. It looks like some dependency is missing or addition 'git config --global --add safe.directory <path>/net/lwip/lwip-external' is required for the submodule directory.
https://source.denx.de/u-boot/custodians/u-boot-tpm/-/pipelines/17916
Building current source for 1 boards (0 threads, 24 jobs per thread) sandbox: + sandbox_spl +fatal: not a git repository (or any of the parent directories): .git +make[1]: *** [Makefile:1875: initsubmodules] Error 128 +make: *** [Makefile:177: sub-make] Error 2 0 0 1 /1 sandbox_spl Completed: 1 total built, 1 newly), duration 0:00:06, rate 0.17 Traceback (most recent call last): File "/builds/u-boot/custodians/u-boot-tpm/./tools/binman/binman", line 45, in <module> from binman import cmdline File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/cmdline.py", line 11, in <module> from binman import state File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/state.py", line 14, in <module> from dtoc import fdt File "/builds/u-boot/custodians/u-boot-tpm/tools/dtoc/fdt.py", line 14, in <module> from libfdt import QUIET_NOTFOUND ImportError: cannot import name 'QUIET_NOTFOUND' from 'libfdt' (unknown location)
On Tue, 26 Sept 2023 at 20:19, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 08:16:35AM -0600, Simon Glass wrote:
Hi Tom,
On Tue, 26 Sept 2023 at 07:41, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 05:37:25AM -0600, Simon Glass wrote:
Hi Maxim,
On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov maxim.uvarov@linaro.org wrote: > > add external lwIP library as a git submodule. > Use STABLE-2_2_0_RELEASE tag. > > Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org > --- > .gitmodules | 3 +++ > net/lwip/lwip-external | 1 + > 2 files changed, 4 insertions(+) > create mode 100644 .gitmodules > create mode 160000 net/lwip/lwip-external
Do you have comments on the rest of the series?
Not yet, but I should be able to review the rest in a few days. My main comments before were minor - return codes, tests, error checking.
OK, thanks. I don't know how exactly I want to proceed with the core of lwip itself, but that doesn't block reviewing and testing the rest of it as we'll move forward with it one way or another.
-- Tom

On Mon, 2 Oct 2023 at 20:46, Simon Glass sjg@google.com wrote:
Hi Maxim,
On Mon, 2 Oct 2023 at 05:23, Maxim Uvarov maxim.uvarov@linaro.org wrote:
I found what was missing. (reproduced with CI docker.)
How about adding a script that copies in the lwip code needed for U-Boot, that you (or whoever the maintainer is) can run each quarter?
Alternatively, I think just sending a patch with the code would be helpful, so we can see what you are wanting to include.
Regards, Simon
Hello Simon,
That might also work. lwIP is a little bit special library which we can not just connect as an external library from the repo, because it has platform implementation specifics (U-Boot here). At this time I'm trying to pass all CI tests. And even if they pass for me locally CI has some interesting combinations where the test fails and I'm not even sure that it's related to lwip code. Once CI will pass all the things I want to take more attention on submodule support or patch support. I really hope that submodule will work for us, but that also will require Makefile and CI changes.
However, review of lwIP code here might be helpful. But I think the mailing list will not allow me to send such a big patch, and it's almost impossible to do a review project in one email. I guess it's better to do a git clone https://git.savannah.nongnu.org/git/lwip.git and see what is there.
BR, Maxim.
On Mon, 2 Oct 2023 at 12:34, Maxim Uvarov maxim.uvarov@linaro.org
wrote:
Can somebody help me to understand and reproduce CI errors? I can run
locally 'make check' which runs a bunch of local builds with binman and all of them are fine.
It looks like some dependency is missing or addition 'git config
--global --add safe.directory <path>/net/lwip/lwip-external' is required for the submodule directory.
https://source.denx.de/u-boot/custodians/u-boot-tpm/-/pipelines/17916
Building current source for 1 boards (0 threads, 24 jobs per thread) sandbox: + sandbox_spl +fatal: not a git repository (or any of the parent directories): .git +make[1]: *** [Makefile:1875: initsubmodules] Error 128 +make: *** [Makefile:177: sub-make] Error 2 0 0 1 /1 sandbox_spl Completed: 1 total built, 1 newly), duration 0:00:06, rate 0.17 Traceback (most recent call last): File "/builds/u-boot/custodians/u-boot-tpm/./tools/binman/binman",
line 45, in <module>
from binman import cmdline
File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/cmdline.py",
line 11, in <module>
from binman import state
File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/state.py",
line 14, in <module>
from dtoc import fdt
File "/builds/u-boot/custodians/u-boot-tpm/tools/dtoc/fdt.py", line
14, in <module>
from libfdt import QUIET_NOTFOUND
ImportError: cannot import name 'QUIET_NOTFOUND' from 'libfdt' (unknown
location)
On Tue, 26 Sept 2023 at 20:19, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 08:16:35AM -0600, Simon Glass wrote:
Hi Tom,
On Tue, 26 Sept 2023 at 07:41, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 05:37:25AM -0600, Simon Glass wrote: > Hi Maxim, > > On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov <
maxim.uvarov@linaro.org> wrote:
> > > > add external lwIP library as a git submodule. > > Use STABLE-2_2_0_RELEASE tag. > > > > Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org > > --- > > .gitmodules | 3 +++ > > net/lwip/lwip-external | 1 + > > 2 files changed, 4 insertions(+) > > create mode 100644 .gitmodules > > create mode 160000 net/lwip/lwip-external
Do you have comments on the rest of the series?
Not yet, but I should be able to review the rest in a few days. My main comments before were minor - return codes, tests, error
checking.
OK, thanks. I don't know how exactly I want to proceed with the core
of
lwip itself, but that doesn't block reviewing and testing the rest of
it
as we'll move forward with it one way or another.
-- Tom

On Wed, Oct 04, 2023 at 01:52:53PM +0600, Maxim Uvarov wrote:
On Mon, 2 Oct 2023 at 20:46, Simon Glass sjg@google.com wrote:
Hi Maxim,
On Mon, 2 Oct 2023 at 05:23, Maxim Uvarov maxim.uvarov@linaro.org wrote:
I found what was missing. (reproduced with CI docker.)
How about adding a script that copies in the lwip code needed for U-Boot, that you (or whoever the maintainer is) can run each quarter?
Alternatively, I think just sending a patch with the code would be helpful, so we can see what you are wanting to include.
Regards, Simon
Hello Simon,
That might also work. lwIP is a little bit special library which we can not just connect as an external library from the repo, because it has platform implementation specifics (U-Boot here). At this time I'm trying to pass all CI tests. And even if they pass for me locally CI has some interesting combinations where the test fails and I'm not even sure that it's related to lwip code. Once CI will pass all the things I want to take more attention on submodule support or patch support. I really hope that submodule will work for us, but that also will require Makefile and CI changes.
However, review of lwIP code here might be helpful. But I think the mailing list will not allow me to send such a big patch, and it's almost impossible to do a review project in one email. I guess it's better to do a git clone https://git.savannah.nongnu.org/git/lwip.git and see what is there.
Yes, the mailing list will hold the message for moderation until I, or one of the other people with the password approve it. That's not a consideration for how we handle the initial lwip integration. It does need to be a "just the import" patch as there's no real way to review the code itself.

Hi Maxim,
On Wed, 4 Oct 2023 at 01:53, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Mon, 2 Oct 2023 at 20:46, Simon Glass sjg@google.com wrote:
Hi Maxim,
On Mon, 2 Oct 2023 at 05:23, Maxim Uvarov maxim.uvarov@linaro.org wrote:
I found what was missing. (reproduced with CI docker.)
How about adding a script that copies in the lwip code needed for U-Boot, that you (or whoever the maintainer is) can run each quarter?
Alternatively, I think just sending a patch with the code would be helpful, so we can see what you are wanting to include.
Regards, Simon
Hello Simon,
That might also work. lwIP is a little bit special library which we can not just connect as an external library from the repo, because it has platform implementation specifics (U-Boot here).
Do you mean that it has an adaptation layer that we are using? I'm not sure what you are getting at.
At this time I'm trying to pass all CI tests. And even if they pass for me locally CI has some interesting combinations where the test fails and I'm not even sure that it's related to lwip code. Once CI will pass all the things I want to take more attention on submodule support or patch support. I really hope that submodule will work for us, but that also will require Makefile and CI changes.
I just hit a roadblock with submodules at the weekend. They are not properly integrated into git (git fetch, git rebase, etc.). Perhaps they will never be.
However, review of lwIP code here might be helpful. But I think the mailing list will not allow me to send such a big patch, and it's almost impossible to do a review project in one email.
It just gets held up, but is released by Tom.
Yes, the email piece has its limits. Also I'm not sure how useful it is to review the lwip code, unless we actually plan to submit fixes upstream.
I guess it's better to do a git clone https://git.savannah.nongnu.org/git/lwip.git and see what is there.
OK.
Regards, Simon
BR, Maxim.
On Mon, 2 Oct 2023 at 12:34, Maxim Uvarov maxim.uvarov@linaro.org wrote:
Can somebody help me to understand and reproduce CI errors? I can run locally 'make check' which runs a bunch of local builds with binman and all of them are fine. It looks like some dependency is missing or addition 'git config --global --add safe.directory <path>/net/lwip/lwip-external' is required for the submodule directory.
https://source.denx.de/u-boot/custodians/u-boot-tpm/-/pipelines/17916
Building current source for 1 boards (0 threads, 24 jobs per thread) sandbox: + sandbox_spl +fatal: not a git repository (or any of the parent directories): .git +make[1]: *** [Makefile:1875: initsubmodules] Error 128 +make: *** [Makefile:177: sub-make] Error 2 0 0 1 /1 sandbox_spl Completed: 1 total built, 1 newly), duration 0:00:06, rate 0.17 Traceback (most recent call last): File "/builds/u-boot/custodians/u-boot-tpm/./tools/binman/binman", line 45, in <module> from binman import cmdline File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/cmdline.py", line 11, in <module> from binman import state File "/builds/u-boot/custodians/u-boot-tpm/tools/binman/state.py", line 14, in <module> from dtoc import fdt File "/builds/u-boot/custodians/u-boot-tpm/tools/dtoc/fdt.py", line 14, in <module> from libfdt import QUIET_NOTFOUND ImportError: cannot import name 'QUIET_NOTFOUND' from 'libfdt' (unknown location)
On Tue, 26 Sept 2023 at 20:19, Tom Rini trini@konsulko.com wrote:
On Tue, Sep 26, 2023 at 08:16:35AM -0600, Simon Glass wrote:
Hi Tom,
On Tue, 26 Sept 2023 at 07:41, Tom Rini trini@konsulko.com wrote: > > On Tue, Sep 26, 2023 at 05:37:25AM -0600, Simon Glass wrote: > > Hi Maxim, > > > > On Tue, 26 Sept 2023 at 03:43, Maxim Uvarov maxim.uvarov@linaro.org wrote: > > > > > > add external lwIP library as a git submodule. > > > Use STABLE-2_2_0_RELEASE tag. > > > > > > Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org > > > --- > > > .gitmodules | 3 +++ > > > net/lwip/lwip-external | 1 + > > > 2 files changed, 4 insertions(+) > > > create mode 100644 .gitmodules > > > create mode 160000 net/lwip/lwip-external > > Do you have comments on the rest of the series?
Not yet, but I should be able to review the rest in a few days. My main comments before were minor - return codes, tests, error checking.
OK, thanks. I don't know how exactly I want to proceed with the core of lwip itself, but that doesn't block reviewing and testing the rest of it as we'll move forward with it one way or another.
-- Tom

Make the make command automatically clone git submodules.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index 9be24c4ec6..3a3cda2365 100644 --- a/Makefile +++ b/Makefile @@ -1871,6 +1871,9 @@ endef include/config/uboot.release: include/config/auto.conf FORCE $(call filechk,uboot.release)
+initsubmodules: + @git submodule init + @git submodule update
# Things we need to do before we recursively start building the kernel # or the modules are listed in "prepare". @@ -1895,7 +1898,7 @@ ifneq ($(KBUILD_SRC),) endif
# prepare2 creates a makefile if using a separate output directory -prepare2: prepare3 outputmakefile cfg +prepare2: prepare3 outputmakefile cfg initsubmodules
prepare1: prepare2 $(version_h) $(timestamp_h) $(dt_h) $(env_h) \ include/config/auto.conf

Add initial documentation of lwIP network IP stack integration to the U-Boot (net_lwip.rst).
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org --- doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 75 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 doc/develop/net_lwip.rst
diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 5b230d0321..4764990f25 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -48,6 +48,7 @@ Implementation spl falcon uefi/index + net_lwip vbe version
diff --git a/doc/develop/net_lwip.rst b/doc/develop/net_lwip.rst new file mode 100644 index 0000000000..a77ab60d0f --- /dev/null +++ b/doc/develop/net_lwip.rst @@ -0,0 +1,75 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +lwIP IP stack integration for U-Boot +==================================== + +Intro +----- + +lwIP is a library implementing network protocols, which is commonly used +on embedded devices. + +https://savannah.nongnu.org/projects/lwip/ +lwIP license: +lwIP is licensed under a BSD-style license: http://lwip.wikia.com/wiki/License. + +Main features include: + +* Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE + +* DHCP client, DNS client (incl. mDNS hostname resolver), + AutoIP/APIPA (Zeroconf), SNMP agent (v1, v2c, v3, private MIB support + & MIB compiler) + +* APIs: specialized APIs for enhanced performance, optional Berkeley-alike + socket API + +* Extended features: IP forwarding over multiple network interfaces, TCP + congestion control, RTT estimation and fast recovery/fast retransmit + +* Addon applications: HTTP(S) server, SNTP client, SMTP(S) client, ping, + NetBIOS nameserver, mDNS responder, MQTT client, TFTP server + +U-Boot implementation details +----------------------------- + +1. In general we can build lwIP as a library and link it against U-Boot or + compile it in the U-Boot tree in the same way as other U-Boot files. There + are few reasons why second variant was selected: lwIP is very customizable + with defines for features, memory size, types of allocation, some internal + types and platform specific code. It turned out easier to enable/disable + debug which is also done with defines, and is needed periodically. + +2. lwIP has 2 APIs - raw mode and sequential (as lwIP names it, or socket API + as we name it in Linux). For now only raw API is supported. + +In raw IP mode a callback function for RX path is registered and will be called +when packet is passed to the IP stack and is ready for the application. + +One example is the unmodified working ping example from lwip sources which +registered the callback: + +.. code-block:: c + + ping_pcb = raw_new(IP_PROTO_ICMP); + raw_recv(ping_pcb, ping_recv, NULL); <- ping_recv is app callback. + raw_bind(ping_pcb, IP_ADDR_ANY) + +3. Input and output + +RX packet path is injected to U-Boot eth_rx() polling loop and TX patch is in +eth_send() accordingly. That way we can leave the driver code unmodified and +consume packets once they are ready. So we do not touch any drivers code and +just eat packets when they are ready. + +U-Boot lwIP Applications +======================== + +.. kernel-doc:: include/net/lwip.h + :internal: + +lwIP API to control polling loop +================================ + +.. kernel-doc:: include/net/ulwip.h + :internal:

Define Makefile and Kconfig to build lwIP inside the U-Boot. We compile lwIP the same as the main code, plus we can do optimization for size at compile time with disabling not needed debug asserts, or not used protocols. So we can tune lwIP configuration specially for U-Boot environments.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- net/Kconfig | 3 +++ net/Makefile | 1 + net/lwip/Kconfig | 25 ++++++++++++++++++ net/lwip/Makefile | 64 +++++++++++++++++++++++++++++++++++++++++++++++ net/net.c | 20 ++++++++++++++- 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 net/lwip/Kconfig create mode 100644 net/lwip/Makefile
diff --git a/net/Kconfig b/net/Kconfig index 4215889127..34c1e43c87 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -5,9 +5,12 @@ menuconfig NET bool "Networking support" default y + imply LWIP
if NET
+source net/lwip/Kconfig + config ARP_TIMEOUT int "Milliseconds before trying ARP again" default 5000 diff --git a/net/Makefile b/net/Makefile index 3e2d061338..61930c244e 100644 --- a/net/Makefile +++ b/net/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_PROT_UDP) += udp.o obj-$(CONFIG_PROT_TCP) += tcp.o obj-$(CONFIG_CMD_WGET) += wget.o +obj-$(CONFIG_LWIP) += lwip/
# Disable this warning as it is triggered by: # sprintf(buf, index ? "foo%d" : "foo", index) diff --git a/net/lwip/Kconfig b/net/lwip/Kconfig new file mode 100644 index 0000000000..19f987a074 --- /dev/null +++ b/net/lwip/Kconfig @@ -0,0 +1,25 @@ +menu "lwIP" +config LWIP + bool "Support LWIP library" + help + Enable the lwIP library code with + all dependencies (commands are implemented with lwIP + library. This option is automatically enabled if CONFIG_NET=y. + lwIP library (https://git.savannah.nongnu.org/git/lwip.git) provides + network stack and application code for U-Boot commands. + Please see doc/develop/net_lwip.rst for more details. + +menu "LWIP options" + +config LWIP_LIB_DEBUG + bool "enable debug" + default n + +config LWIP_LIB_NOASSERT + bool "disable asserts" + default y + help + Disabling asserts reduces binary size by 16k. +endmenu + +endmenu diff --git a/net/lwip/Makefile b/net/lwip/Makefile new file mode 100644 index 0000000000..3fd5d34564 --- /dev/null +++ b/net/lwip/Makefile @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip + +obj-$(CONFIG_NET) += lwip-external/src/core/init.o \ + lwip-external/src/core/def.o \ + lwip-external/src/core/dns.o \ + lwip-external/src/core/inet_chksum.o \ + lwip-external/src/core/ip.o \ + lwip-external/src/core/mem.o \ + lwip-external/src/core/memp.o \ + lwip-external/src/core/netif.o \ + lwip-external/src/core/pbuf.o \ + lwip-external/src/core/raw.o \ + lwip-external/src/core/stats.o \ + lwip-external/src/core/sys.o \ + lwip-external/src/core/altcp.o \ + lwip-external/src/core/altcp_alloc.o \ + lwip-external/src/core/altcp_tcp.o \ + lwip-external/src/core/tcp.o \ + lwip-external/src/core/tcp_in.o \ + lwip-external/src/core/tcp_out.o \ + lwip-external/src/core/timeouts.o \ + lwip-external/src/core/udp.o + +# IPv4 +obj-$(CONFIG_NET) += lwip-external/src/core/ipv4/acd.o \ + lwip-external/src/core/ipv4/autoip.o \ + lwip-external/src/core/ipv4/dhcp.o \ + lwip-external/src/core/ipv4/etharp.o \ + lwip-external/src/core/ipv4/icmp.o \ + lwip-external/src/core/ipv4/igmp.o \ + lwip-external/src/core/ipv4/ip4_frag.o \ + lwip-external/src/core/ipv4/ip4.o \ + lwip-external/src/core/ipv4/ip4_addr.o +# IPv6 +obj-$(CONFIG_NET) += lwip-external/src/core/ipv6/dhcp6.o \ + lwip-external/src/core/ipv6/ethip6.o \ + lwip-external/src/core/ipv6/icmp6.o \ + lwip-external/src/core/ipv6/inet6.o \ + lwip-external/src/core/ipv6/ip6.o \ + lwip-external/src/core/ipv6/ip6_addr.o \ + lwip-external/src/core/ipv6/ip6_frag.o \ + lwip-external/src/core/ipv6/mld6.o \ + lwip-external/src/core/ipv6/nd6.o +# API +obj-$(CONFIG_NET) += lwip-external/src/api/api_lib.o \ + lwip-external/src/api/api_msg.o \ + lwip-external/src/api/err.o \ + lwip-external/src/api/if_api.o \ + lwip-external/src/api/netbuf.o \ + lwip-external/src/api/netdb.o \ + lwip-external/src/api/netifapi.o \ + lwip-external/src/api/sockets.o \ + lwip-external/src/api/tcpip.o + +# Netdevs +obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o + +obj-$(CONFIG_NET) += port/if.o +obj-$(CONFIG_NET) += port/sys-arch.o diff --git a/net/net.c b/net/net.c index 43abbac7c3..d9e566081c 100644 --- a/net/net.c +++ b/net/net.c @@ -125,6 +125,7 @@ #endif #include "dhcpv6.h" #include "net_rand.h" +#include <net/ulwip.h>
/** BOOTP EXTENTIONS **/
@@ -452,7 +453,9 @@ int net_loop(enum proto_t protocol) #endif
bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start"); - net_init(); + if (!ulwip_enabled() || !ulwip_in_loop()) + net_init(); + if (eth_is_on_demand_init()) { eth_halt(); eth_set_current(); @@ -649,6 +652,16 @@ restart: */ eth_rx();
+ if (ulwip_enabled()) { + net_set_state(NETLOOP_CONTINUE); + if (!ulwip_in_loop()) { + if (ulwip_app_get_err()) + net_set_state(NETLOOP_FAIL); + else + net_set_state(NETLOOP_SUCCESS); + goto done; + } + } /* * Abort if ctrl-c was pressed. */ @@ -1213,6 +1226,11 @@ void net_process_received_packet(uchar *in_packet, int len) if (len < ETHER_HDR_SIZE) return;
+ if (ulwip_enabled()) { + ulwip_poll(); + return; + } + #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) if (push_packet) { (*push_packet)(in_packet, len);

U-Boot recently got support for an alternative network stack using LWIP. Replace dns command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 19 +++++++++++ net/lwip/Makefile | 2 ++ net/lwip/apps/dns/lwip-dns.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 include/net/lwip.h create mode 100644 net/lwip/apps/dns/lwip-dns.c
diff --git a/include/net/lwip.h b/include/net/lwip.h new file mode 100644 index 0000000000..ab3db1a214 --- /dev/null +++ b/include/net/lwip.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); + +/** + * ulwip_dns() - creates the DNS request to resolve a domain host name + * + * This function creates the DNS request to resolve a domain host name. Function + * can return immediately if previous request was cached or it might require + * entering the polling loop for a request to a remote server. + * + * @name: dns name to resolve + * @varname: (optional) U-Boot variable name to store the result + * Returns: ERR_OK(0) for fetching entry from the cache + * -EINPROGRESS success, can go to the polling loop + * Other value < 0, if error + */ +int ulwip_dns(char *name, char *varname); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 3fd5d34564..5d8d5527c6 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o
obj-$(CONFIG_NET) += port/if.o obj-$(CONFIG_NET) += port/sys-arch.o + +obj-y += apps/dns/lwip-dns.o diff --git a/net/lwip/apps/dns/lwip-dns.c b/net/lwip/apps/dns/lwip-dns.c new file mode 100644 index 0000000000..3ee6e24ef4 --- /dev/null +++ b/net/lwip/apps/dns/lwip-dns.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include <common.h> +#include <command.h> +#include <console.h> + +#include <lwip/dns.h> +#include <lwip/ip_addr.h> + +#include <net/ulwip.h> + +static void dns_found_cb(const char *name, const ip_addr_t *ipaddr, void *callback_arg) +{ + char *varname = (char *)callback_arg; + char *ipstr = ip4addr_ntoa(ipaddr); + + if (varname) + env_set(varname, ipstr); + log_info("resolved %s to %s\n", name, ipstr); + ulwip_exit(0); +} + +int ulwip_dns(char *name, char *varname) +{ + int err; + ip_addr_t ipaddr; /* not used */ + ip_addr_t dns1; + ip_addr_t dns2; + char *dnsenv = env_get("dnsip"); + char *dns2env = env_get("dnsip2"); + + if (!dnsenv && !dns2env) { + log_err("nameserver is not set with dnsip and dnsip2 vars\n"); + return -ENOENT; + } + + if (!dnsenv) + log_warning("dnsip var is not set\n"); + if (!dns2env) + log_warning("dnsip2 var is not set\n"); + + dns_init(); + + if (ipaddr_aton(dnsenv, &dns1)) + dns_setserver(0, &dns1); + + if (dns2env && ipaddr_aton(dns2env, &dns2)) + dns_setserver(1, &dns2); + + err = dns_gethostbyname(name, &ipaddr, dns_found_cb, varname); + if (err == ERR_OK) + dns_found_cb(name, &ipaddr, varname); + + /* convert lwIP ERR_INPROGRESS to U-Boot -EINPROGRESS */ + if (err == ERR_INPROGRESS) + err = -EINPROGRESS; + + return err; +}

U-Boot recently got support for an alternative network stack using LWIP. Replace dhcp command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 12 +++++ net/lwip/Makefile | 1 + net/lwip/apps/dhcp/lwip-dhcp.c | 85 ++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 net/lwip/apps/dhcp/lwip-dhcp.c
diff --git a/include/net/lwip.h b/include/net/lwip.h index ab3db1a214..6a8fcef392 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -17,3 +17,15 @@ int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, * Other value < 0, if error */ int ulwip_dns(char *name, char *varname); + +/** + * ulwip_dhcp() - create the DHCP request to obtain IP address. + * + * This function creates the DHCP request to obtain IP address. If DHCP server + * returns file name, this file will be downloaded with tftp. After this + * function you need to invoke the polling loop to process network communication. + * + * Returns: 0 if success + * Other value < 0, if error +*/ +int ulwip_dhcp(void); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 5d8d5527c6..a3a33b7f71 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -63,4 +63,5 @@ obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o obj-$(CONFIG_NET) += port/if.o obj-$(CONFIG_NET) += port/sys-arch.o
+obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o diff --git a/net/lwip/apps/dhcp/lwip-dhcp.c b/net/lwip/apps/dhcp/lwip-dhcp.c new file mode 100644 index 0000000000..f0b0e26f6e --- /dev/null +++ b/net/lwip/apps/dhcp/lwip-dhcp.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include <common.h> +#include <command.h> +#include <console.h> + +#include <lwip/dhcp.h> +#include <lwip/prot/dhcp.h> +#include "lwip/timeouts.h" + +#include <net/eth.h> +#include <net/ulwip.h> + +#define DHCP_TMO_TIME 500 /* poll for DHCP state change */ +#define DHCP_TMO_NUM 10 /* number of tries */ + +typedef struct dhcp_priv { + int num_tries; + struct netif *netif; +} dhcp_priv; + +static void dhcp_tmo(void *arg) +{ + struct dhcp_priv *dpriv = (struct dhcp_priv *)arg; + struct netif *netif = dpriv->netif; + struct dhcp *dhcp; + + dhcp = netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP); + if (!dhcp) + return; + + if (dhcp->state == DHCP_STATE_BOUND) { + int err = 0; + + err -= env_set("bootfile", dhcp->boot_file_name); + err -= env_set("ipaddr", ip4addr_ntoa(&dhcp->offered_ip_addr)); + err -= env_set("netmask", ip4addr_ntoa(&dhcp->offered_sn_mask)); + err -= env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr)); + if (err) + log_err("error update envs\n"); + log_info("DHCP client bound to address %s\n", ip4addr_ntoa(&dhcp->offered_ip_addr)); + free(dpriv); + ulwip_exit(err); + return; + } + + dpriv->num_tries--; + if (dpriv->num_tries < 0) { + log_err("DHCP client timeout\n"); + free(dpriv); + ulwip_exit(-1); + return; + } + + sys_timeout(DHCP_TMO_TIME, dhcp_tmo, dpriv); +} + +int ulwip_dhcp(void) +{ + struct netif *netif; + int eth_idx; + struct dhcp_priv *dpriv; + + dpriv = malloc(sizeof(struct dhcp_priv)); + if (!dpriv) + return -EPERM; + + eth_idx = eth_get_dev_index(); + if (eth_idx < 0) + return -EPERM; + + netif = netif_get_by_index(eth_idx + 1); + if (!netif) + return -ENOENT; + + dpriv->num_tries = DHCP_TMO_NUM; + dpriv->netif = netif; + sys_timeout(DHCP_TMO_TIME, dhcp_tmo, dpriv); + + return dhcp_start(netif) ? 0 : -EPERM; +}

Hi Maxim,
On Tue, 26 Sept 2023 at 03:44, Maxim Uvarov maxim.uvarov@linaro.org wrote:
U-Boot recently got support for an alternative network stack using LWIP. Replace dhcp command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
include/net/lwip.h | 12 +++++ net/lwip/Makefile | 1 + net/lwip/apps/dhcp/lwip-dhcp.c | 85 ++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 net/lwip/apps/dhcp/lwip-dhcp.c
Reviewed-by: Simon Glass sjg@chromium.org with nits
diff --git a/include/net/lwip.h b/include/net/lwip.h index ab3db1a214..6a8fcef392 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -17,3 +17,15 @@ int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc,
Other value < 0, if error
*/ int ulwip_dns(char *name, char *varname);
+/**
- ulwip_dhcp() - create the DHCP request to obtain IP address.
- This function creates the DHCP request to obtain IP address. If DHCP server
- returns file name, this file will be downloaded with tftp. After this
- function you need to invoke the polling loop to process network communication.
- Returns: 0 if success
Other value < 0, if error
+*/ +int ulwip_dhcp(void); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 5d8d5527c6..a3a33b7f71 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -63,4 +63,5 @@ obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o obj-$(CONFIG_NET) += port/if.o obj-$(CONFIG_NET) += port/sys-arch.o
+obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o diff --git a/net/lwip/apps/dhcp/lwip-dhcp.c b/net/lwip/apps/dhcp/lwip-dhcp.c new file mode 100644 index 0000000000..f0b0e26f6e --- /dev/null +++ b/net/lwip/apps/dhcp/lwip-dhcp.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0
+/*
- (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org
- */
+#include <common.h> +#include <command.h> +#include <console.h>
+#include <lwip/dhcp.h> +#include <lwip/prot/dhcp.h> +#include "lwip/timeouts.h"
+#include <net/eth.h> +#include <net/ulwip.h>
+#define DHCP_TMO_TIME 500 /* poll for DHCP state change */ +#define DHCP_TMO_NUM 10 /* number of tries */
+typedef struct dhcp_priv {
can you drop typedef?
int num_tries;
struct netif *netif;
+} dhcp_priv;
+static void dhcp_tmo(void *arg) +{
struct dhcp_priv *dpriv = (struct dhcp_priv *)arg;
struct netif *netif = dpriv->netif;
struct dhcp *dhcp;
dhcp = netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
if (!dhcp)
return;
if (dhcp->state == DHCP_STATE_BOUND) {
int err = 0;
err -= env_set("bootfile", dhcp->boot_file_name);
err -= env_set("ipaddr", ip4addr_ntoa(&dhcp->offered_ip_addr));
err -= env_set("netmask", ip4addr_ntoa(&dhcp->offered_sn_mask));
err -= env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr));
if (err)
log_err("error update envs\n");
but don't you need to return the effort? How does a script know it failed?
I think this function need an error return...if that is not possible then you need to stash the error somehow so you can report it when needed.
log_info("DHCP client bound to address %s\n", ip4addr_ntoa(&dhcp->offered_ip_addr));
free(dpriv);
ulwip_exit(err);
return;
}
dpriv->num_tries--;
if (dpriv->num_tries < 0) {
log_err("DHCP client timeout\n");
free(dpriv);
ulwip_exit(-1);
return;
}
sys_timeout(DHCP_TMO_TIME, dhcp_tmo, dpriv);
+}
+int ulwip_dhcp(void) +{
struct netif *netif;
int eth_idx;
struct dhcp_priv *dpriv;
dpriv = malloc(sizeof(struct dhcp_priv));
if (!dpriv)
return -EPERM;
-ENOMEM
eth_idx = eth_get_dev_index();
if (eth_idx < 0)
return -EPERM;
netif = netif_get_by_index(eth_idx + 1);
if (!netif)
return -ENOENT;
dpriv->num_tries = DHCP_TMO_NUM;
dpriv->netif = netif;
sys_timeout(DHCP_TMO_TIME, dhcp_tmo, dpriv);
return dhcp_start(netif) ? 0 : -EPERM;
Why -EPERM? Is it a permission error? Can we not get a real error number?
+}
2.30.2
Regards, SImon

U-Boot recently got support for an alternative network stack using LWIP. Replace tftp command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 13 ++++ net/lwip/Makefile | 1 + net/lwip/apps/tftp/Makefile | 7 ++ net/lwip/apps/tftp/lwip-tftp.c | 129 +++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 net/lwip/apps/tftp/Makefile create mode 100644 net/lwip/apps/tftp/lwip-tftp.c
diff --git a/include/net/lwip.h b/include/net/lwip.h index 6a8fcef392..11389bb038 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -29,3 +29,16 @@ int ulwip_dns(char *name, char *varname); * Other value < 0, if error */ int ulwip_dhcp(void); + +/** + * ulwip_tftp() - load file with tftp + * + * Load file with tftp to specific address + * + * @addr: Address to store downloaded file + * @filename: File name on remote tftp server to download + * + * + * Returns: 0 if success, !0 if error + */ +int ulwip_tftp(ulong addr, const char *filename); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index a3a33b7f71..b348e5ca31 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -65,3 +65,4 @@ obj-$(CONFIG_NET) += port/sys-arch.o
obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o +obj-y += apps/tftp/ diff --git a/net/lwip/apps/tftp/Makefile b/net/lwip/apps/tftp/Makefile new file mode 100644 index 0000000000..c3ad3c6353 --- /dev/null +++ b/net/lwip/apps/tftp/Makefile @@ -0,0 +1,7 @@ +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include/lwip/apps +ccflags-y += -I$(srctree)/net/lwip/lwip-external/contrib/examples/tftp/ + +obj-y += ../../lwip-external/src/apps/tftp/tftp.o +obj-y += lwip-tftp.o diff --git a/net/lwip/apps/tftp/lwip-tftp.c b/net/lwip/apps/tftp/lwip-tftp.c new file mode 100644 index 0000000000..56eed3030b --- /dev/null +++ b/net/lwip/apps/tftp/lwip-tftp.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include <common.h> +#include <command.h> +#include <console.h> +#include <bootstage.h> + +#include "tftp_client.h" +#include "tftp_server.h" +#include <tftp_example.h> + +#include <string.h> + +#include <net/ulwip.h> + +static ulong daddr; +static ulong size; + +static void *tftp_open(const char *fname, const char *mode, u8_t is_write) +{ + return NULL; +} + +static void tftp_close(void *handle) +{ + log_info("\ndone\n"); + log_info("Bytes transferred = %ld (0x%lx hex)\n", size, size); + + bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done"); + if (env_set_hex("filesize", size)) { + log_err("filesize not updated\n"); + ulwip_exit(-1); + return; + } + ulwip_exit(0); +} + +static int tftp_read(void *handle, void *buf, int bytes) +{ + return 0; +} + +static int tftp_write(void *handle, struct pbuf *p) +{ + struct pbuf *q; + + for (q = p; q != NULL; q = q->next) { + memcpy((void *)daddr, q->payload, q->len); + daddr += q->len; + size += q->len; + log_info("#"); + } + + return 0; +} + +static void tftp_error(void *handle, int err, const char *msg, int size) +{ + char message[100]; + + memset(message, 0, sizeof(message)); + memcpy(message, msg, LWIP_MIN(sizeof(message) - 1, (size_t)size)); + + log_info("TFTP error: %d (%s)", err, message); +} + +static const struct tftp_context tftp = { + tftp_open, + tftp_close, + tftp_read, + tftp_write, + tftp_error +}; + +int ulwip_tftp(ulong addr, char *fname) +{ + void *f = (void *)0x1; /* unused fake file handle*/ + err_t err; + ip_addr_t srv; + int ret; + char *server_ip; + + if (!fname || addr == 0) + return CMD_RET_FAILURE; + + size = 0; + daddr = addr; + server_ip = env_get("serverip"); + if (!server_ip) { + log_err("error: serverip variable has to be set\n"); + return CMD_RET_FAILURE; + } + + ret = ipaddr_aton(server_ip, &srv); + if (!ret) { + log_err("error: ipaddr_aton\n"); + return CMD_RET_FAILURE; + } + + log_info("TFTP from server %s; our IP address is %s\n", + server_ip, env_get("ipaddr")); + log_info("Filename '%s'.\n", fname); + log_info("Load address: 0x%lx\n", daddr); + log_info("Loading:"); + + bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start"); + + err = tftp_init_client(&tftp); + if (!(err == ERR_OK || err == ERR_USE)) + log_err("tftp_init_client err: %d\n", err); + + err = tftp_get(f, &srv, TFTP_PORT, fname, TFTP_MODE_OCTET); + /* might return different errors, like routing problems */ + if (err != ERR_OK) { + log_err("tftp_get err=%d\n", err); + return CMD_RET_FAILURE; + } + + if (env_set_hex("fileaddr", addr)) { + log_err("fileaddr not updated\n"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +}

U-Boot recently got support for an alternative network stack using LWIP. Replace wget command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 14 +++++ net/lwip/Makefile | 1 + net/lwip/apps/http/Makefile | 6 ++ net/lwip/apps/http/lwip-wget.c | 105 +++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 net/lwip/apps/http/Makefile create mode 100644 net/lwip/apps/http/lwip-wget.c
diff --git a/include/net/lwip.h b/include/net/lwip.h index 11389bb038..85f08343fd 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -42,3 +42,17 @@ int ulwip_dhcp(void); * Returns: 0 if success, !0 if error */ int ulwip_tftp(ulong addr, const char *filename); + +/** + * ulwip_wget() - creates the HTTP request to download file + * + * This function creates the HTTP request to download file from url to the address + * specified in parameters. After this function you need to invoke the polling + * loop to process network communication. + * + * + * @addr: start address to download result + * @url: url in format http://host/url + * Returns: 0 for success, !0 if error + */ +int ulwip_wget(ulong addr, char *url); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index b348e5ca31..61042862e1 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -66,3 +66,4 @@ obj-$(CONFIG_NET) += port/sys-arch.o obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o obj-y += apps/tftp/ +obj-y += apps/http/ diff --git a/net/lwip/apps/http/Makefile b/net/lwip/apps/http/Makefile new file mode 100644 index 0000000000..ac0b3ede0d --- /dev/null +++ b/net/lwip/apps/http/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include/lwip/apps + +obj-$(CONFIG_CMD_WGET) += ../../lwip-external/src/apps/http/http_client.o +obj-$(CONFIG_CMD_WGET) += lwip-wget.o diff --git a/net/lwip/apps/http/lwip-wget.c b/net/lwip/apps/http/lwip-wget.c new file mode 100644 index 0000000000..7a7cc3273d --- /dev/null +++ b/net/lwip/apps/http/lwip-wget.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include <common.h> +#include <command.h> +#include <console.h> +#include <vsprintf.h> + +#include "http_client.h" +#include <net/ulwip.h> + +static ulong daddr; +static httpc_connection_t settings; + +#define SERVER_NAME_SIZE 200 +#define HTTP_PORT_DEFAULT 80 + +static err_t httpc_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *pbuf, + err_t unused_err) +{ + struct pbuf *buf; + + if (!pbuf) + return ERR_BUF; + + for (buf = pbuf; buf != NULL; buf = buf->next) { + memcpy((void *)daddr, buf->payload, buf->len); + log_debug("downloaded chunk size %d, to addr 0x%lx\n", + buf->len, daddr); + daddr += buf->len; + } + + altcp_recved(pcb, pbuf->tot_len); + pbuf_free(pbuf); + return ERR_OK; +} + +static void httpc_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, + u32_t srv_res, err_t err) +{ + if (httpc_result == HTTPC_RESULT_OK) { + log_info("\n%d bytes successfully downloaded.\n", rx_content_len); + env_set_hex("filesize", rx_content_len); + ulwip_exit(0); + } else { + log_err("\nhttp eroror: %d\n", httpc_result); + ulwip_exit(-1); + } +} + +/* http://hostname/url */ +static int parse_url(char *url, char *host, u16 *port) +{ + char *p, *pp; + + p = strstr(url, "http://"); + if (!p) + return -ENOENT; + + p += strlen("http://"); + + /* parse hostname */ + pp = strchr(p, '/'); + if (!pp) + return -ENOENT; + + if (p + SERVER_NAME_SIZE <= pp) + return -ENOENT; + + memcpy(host, p, pp - p); + host[pp - p + 1] = '\0'; + *port = HTTP_PORT_DEFAULT; + + return 0; +} + +int ulwip_wget(ulong addr, char *url) +{ + err_t err; + u16 port; + char server_name[SERVER_NAME_SIZE]; + httpc_state_t *connection; + + daddr = addr; + + err = parse_url(url, server_name, &port); + if (err) + return -ENOENT; + + log_info("downloading %s to addr 0x%lx\n", url, addr); + memset(&settings, 0, sizeof(settings)); + settings.result_fn = httpc_result; + err = httpc_get_file_dns(server_name, port, url, &settings, + httpc_recv, NULL, &connection); + if (err != ERR_OK) + return -EPERM; + + if (env_set_hex("fileaddr", addr)) + return -EACCES; + + return 0; +}

On Tue, 26 Sept 2023 at 03:45, Maxim Uvarov maxim.uvarov@linaro.org wrote:
U-Boot recently got support for an alternative network stack using LWIP. Replace wget command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
include/net/lwip.h | 14 +++++ net/lwip/Makefile | 1 + net/lwip/apps/http/Makefile | 6 ++ net/lwip/apps/http/lwip-wget.c | 105 +++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 net/lwip/apps/http/Makefile create mode 100644 net/lwip/apps/http/lwip-wget.c
Reviewed-by: Simon Glass sjg@chromium.org

U-Boot recently got support for an alternative network stack using LWIP. Replace ping command with the LWIP variant while keeping the output and error messages identical. ping uses lwIP contrib/apps/ping/ping.c code. Custom timeout is used to get an error message on not modified example.
There is pending lwip patch: https://lists.nongnu.org/archive/html/lwip-devel/2023-09/msg00004.html https://savannah.nongnu.org/bugs/?64697 Once applied, more clean way can be used, to unset pending timers and exit from the ping application: net/lwip/apps/ping/ping.h: #define PING_RESULT(cond) { \ .. - raw_remove(pcb); \ + ping_destroy(); \
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 15 +++++++++++++ net/lwip/Makefile | 1 + net/lwip/apps/ping/Makefile | 12 +++++++++++ net/lwip/apps/ping/lwip_ping.c | 39 ++++++++++++++++++++++++++++++++++ net/lwip/apps/ping/lwip_ping.h | 15 +++++++++++++ net/lwip/apps/ping/ping.h | 27 +++++++++++++++++++++++ 6 files changed, 109 insertions(+) create mode 100644 net/lwip/apps/ping/Makefile create mode 100644 net/lwip/apps/ping/lwip_ping.c create mode 100644 net/lwip/apps/ping/lwip_ping.h create mode 100644 net/lwip/apps/ping/ping.h
diff --git a/include/net/lwip.h b/include/net/lwip.h index 85f08343fd..1e92f9871c 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -2,6 +2,8 @@
int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]);
/** * ulwip_dns() - creates the DNS request to resolve a domain host name @@ -56,3 +58,16 @@ int ulwip_tftp(ulong addr, const char *filename); * Returns: 0 for success, !0 if error */ int ulwip_wget(ulong addr, char *url); + +/** + * ulwip_ping - create the ping request + * + * This function creates the ping for address provided in parameters. + * After this function you need to invoke the polling + * loop to process network communication. + * + * + * @ping_addr: IP address to ping + * Returns: 0 for success, !0 if error +*/ +int ulwip_ping(char *ping_addr); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 61042862e1..5839d125c2 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -67,3 +67,4 @@ obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o obj-y += apps/tftp/ obj-y += apps/http/ +obj-y += apps/ping/ diff --git a/net/lwip/apps/ping/Makefile b/net/lwip/apps/ping/Makefile new file mode 100644 index 0000000000..e567c0dc3e --- /dev/null +++ b/net/lwip/apps/ping/Makefile @@ -0,0 +1,12 @@ +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip +ccflags-y += -I$(obj) + +# ping.c includes "ping.h", copy it to local directory, to override ping.h +.PHONY: $(obj)/ping.c +$(obj)/ping.o: $(obj)/ping.c +$(obj)/ping.c: + cp $(srctree)/net/lwip/lwip-external/contrib/apps/ping/ping.c $(obj)/ping.c + +obj-y += ping.o +obj-y += lwip_ping.o diff --git a/net/lwip/apps/ping/lwip_ping.c b/net/lwip/apps/ping/lwip_ping.c new file mode 100644 index 0000000000..ba02e7ed47 --- /dev/null +++ b/net/lwip/apps/ping/lwip_ping.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/timeouts.h" +#include <linux/errno.h> +#include "ping.h" +#include "lwip_ping.h" + +#define PING_WAIT_MS 5000 + +static ip_addr_t ip_target; + +void ping_tmo(void *arg) +{ + log_err("ping_tmo: ping failed; host %s is not alive\n", + ipaddr_ntoa(&ip_target)); + ulwip_exit(1); +} + +int ulwip_ping(char *ping_addr) +{ + int err; + + err = ipaddr_aton(ping_addr, &ip_target); + if (!err) + return -ENOENT; + + sys_timeout(PING_WAIT_MS, ping_tmo, NULL); + + ping_init(&ip_target); + ping_send_now(); + + return 0; +} diff --git a/net/lwip/apps/ping/lwip_ping.h b/net/lwip/apps/ping/lwip_ping.h new file mode 100644 index 0000000000..0374f07d9e --- /dev/null +++ b/net/lwip/apps/ping/lwip_ping.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#ifndef LWIP_PING_H +#define LWIP_PING_H + +#include <lwip/ip_addr.h> + +void ping_raw_init(void); +void ping_send_now(void); + +#endif /* LWIP_PING_H */ diff --git a/net/lwip/apps/ping/ping.h b/net/lwip/apps/ping/ping.h new file mode 100644 index 0000000000..5dd631f2f7 --- /dev/null +++ b/net/lwip/apps/ping/ping.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <net/ulwip.h> +#include "lwip/ip_addr.h" + +void ping_tmo(void *arg); + +#define LWIP_DEBUG 1 /* ping_time is under ifdef*/ +#define PING_RESULT(cond) { \ + if (cond == 1) { \ + printf("host %s a alive\n", ipaddr_ntoa(addr)); \ + printf(" %"U32_F" ms\n", (sys_now() - ping_time)); \ + raw_remove(pcb); \ + sys_untimeout(ping_tmo, NULL); \ + sys_check_timeouts(); \ + ulwip_exit(0); \ + } else { \ + printf("ping failed; host %s in not alive\n",\ + ipaddr_ntoa(addr)); \ + raw_remove(pcb); \ + sys_untimeout(ping_tmo, NULL); \ + sys_check_timeouts(); \ + ulwip_exit(-1); \ + } \ + } while (0); + +void ping_init(const ip_addr_t *ping_addr);

lwip configuration can be tuned with header file.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- net/lwip/lwipopts.h | 178 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 net/lwip/lwipopts.h
diff --git a/net/lwip/lwipopts.h b/net/lwip/lwipopts.h new file mode 100644 index 0000000000..731da30baa --- /dev/null +++ b/net/lwip/lwipopts.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#ifndef LWIP_LWIPOPTS_H +#define LWIP_LWIPOPTS_H + +#include "lwipopts.h" + +#if defined(CONFIG_LWIP_LIB_DEBUG) +#define LWIP_DEBUG 1 +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_ON +#define NETIF_DEBUG LWIP_DBG_ON +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_ON +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_ON +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_ON +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_ON +#define AUTOIP_DEBUG LWIP_DBG_ON +#define DNS_DEBUG LWIP_DBG_ON +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#else +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#endif +#define LWIP_TESTMODE 0 + +#if defined(CONFIG_LWIP_LIB_NOASSERT) +#define LWIP_NOASSERT 1 +#define LWIP_ASSERT(message, assertion) +#endif + +#include "lwip/debug.h" + +#define SYS_LIGHTWEIGHT_PROT 0 +#define NO_SYS 1 + +#define LWIP_IPV6 0 + +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 + +#define MEMP_NUM_PBUF 4 +#define MEMP_NUM_RAW_PCB 2 +#define MEMP_NUM_UDP_PCB 4 +#define MEMP_NUM_TCP_PCB 2 +#define MEMP_NUM_TCP_PCB_LISTEN 2 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_REASSDATA 1 +#define MEMP_NUM_ARP_QUEUE 2 +#define MEMP_NUM_SYS_TIMEOUT 4 +#define MEMP_NUM_NETBUF 2 +#define MEMP_NUM_NETCONN 32 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define PBUF_POOL_SIZE 8 + +#define LWIP_ARP 1 +#define ARP_TABLE_SIZE 10 +#define ARP_QUEUEING 1 + +#define IP_FORWARD 0 +#define IP_OPTIONS_ALLOWED 1 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 +#define IP_REASS_MAXAGE 3 +#define IP_REASS_MAX_PBUFS 4 +#define IP_FRAG_USES_STATIC_BUF 0 + +#define IP_DEFAULT_TTL 255 + +#define LWIP_ICMP 1 + +#define LWIP_RAW 1 + +#define LWIP_DHCP 1 +#define LWIP_DHCP_BOOTP_FILE 1 +#define LWIP_DHCP_DOES_ACD_CHECK 0 + +#define LWIP_AUTOIP 0 + +#define LWIP_SNMP 0 + +#define LWIP_IGMP 0 + +#define LWIP_DNS 1 + +#define LWIP_UDP 1 + +#define LWIP_TCP 1 + +#define LWIP_LISTEN_BACKLOG 0 + +#define PBUF_LINK_HLEN 14 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS + 40 + PBUF_LINK_HLEN) + +#define LWIP_HAVE_LOOPIF 0 + +#define LWIP_NETCONN 0 +#define LWIP_DISABLE_MEMP_SANITY_CHECKS 1 + +#define LWIP_SOCKET 0 +#define SO_REUSE 0 + +#define LWIP_STATS 0 + +#define PPP_SUPPORT 0 + +#define LWIP_TCPIP_CORE_LOCKING 0 + +#define LWIP_NETIF_LOOPBACK 1 + +/* use malloc instead of pool */ +#define MEMP_MEM_MALLOC 1 +#define MEMP_MEM_INIT 1 +#define MEM_LIBC_MALLOC 1 + +#endif /* LWIP_LWIPOPTS_H */

On Tue, 26 Sept 2023 at 03:45, Maxim Uvarov maxim.uvarov@linaro.org wrote:
lwip configuration can be tuned with header file.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
net/lwip/lwipopts.h | 178 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 net/lwip/lwipopts.h
Reviewed-by: Simon Glass sjg@chromium.org

Implement port of lwIP stack to the U-Boot. lwIP is well known full IP stack which provides wide functionality, various examples, API closer to linux userland. Rich debug printing and possibility to run lwIP apps under linux make it easier to develop and debug apps. U-Boot implementation keeps the original file structure widely used for lwIP ports. (i.e. port/if.c port/sys-arch.c). That should allow us to easy port apps to or from U-Boot. Multiply ethernet devices are supported and "ethact" env variable chooses the active device. Having a rich IP stack inside U-Boot will allow us to have such applications as http or https clients.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- net/eth-uclass.c | 8 + net/lwip/port/if.c | 332 ++++++++++++++++++++++++++ net/lwip/port/include/arch/cc.h | 38 +++ net/lwip/port/include/arch/sys_arch.h | 10 + net/lwip/port/include/limits.h | 0 net/lwip/port/sys-arch.c | 13 + 6 files changed, 401 insertions(+) create mode 100644 net/lwip/port/if.c create mode 100644 net/lwip/port/include/arch/cc.h create mode 100644 net/lwip/port/include/arch/sys_arch.h create mode 100644 net/lwip/port/include/limits.h create mode 100644 net/lwip/port/sys-arch.c
diff --git a/net/eth-uclass.c b/net/eth-uclass.c index c393600fab..6625f6d8a5 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -32,6 +32,7 @@ DECLARE_GLOBAL_DATA_PTR; struct eth_device_priv { enum eth_state_t state; bool running; + ulwip ulwip; };
/** @@ -347,6 +348,13 @@ int eth_init(void) return ret; }
+struct ulwip *eth_lwip_priv(struct udevice *current) +{ + struct eth_device_priv *priv = dev_get_uclass_priv(current); + + return &priv->ulwip; +} + void eth_halt(void) { struct udevice *current; diff --git a/net/lwip/port/if.c b/net/lwip/port/if.c new file mode 100644 index 0000000000..0025b1273f --- /dev/null +++ b/net/lwip/port/if.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include <common.h> +#include <command.h> +#include <net/eth.h> +#include <dm/device.h> +#include <dm/uclass-id.h> +#include <dm/uclass.h> +#include "lwip/debug.h" +#include "lwip/arch.h" +#include "netif/etharp.h" +#include "lwip/stats.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/ethip6.h" +#include "lwip/timeouts.h" + +#include "lwip/ip.h" + +/* + * MAC_ADDR_STRLEN: length of mac address string + */ +#define MAC_ADDR_STRLEN 17 + +int ulwip_enabled(void) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return 0; + + ulwip = eth_lwip_priv(udev); + return ulwip->init_done; +} + +int ulwip_in_loop(void) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return 0; + + sys_check_timeouts(); + + ulwip = eth_lwip_priv(udev); + return ulwip->loop; +} + +void ulwip_loop_set(int loop) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return; + + ulwip = eth_lwip_priv(udev); + ulwip->loop = loop; +} + +void ulwip_exit(int err) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return; + + ulwip = eth_lwip_priv(udev); + ulwip->loop = 0; + ulwip->err = err; +} + +int ulwip_app_get_err(void) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return 0; + + ulwip = eth_lwip_priv(udev); + return ulwip->err; +} + +typedef struct { +} ulwip_if_t; + +static struct pbuf *low_level_input(void) +{ + struct pbuf *p, *q; + u16_t len = net_rx_packet_len; + uchar *data = net_rx_packet; + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (!p) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + return NULL; + } + + for (q = p; q != NULL; q = q->next) { + memcpy(q->payload, data, q->len); + data += q->len; + } + + LINK_STATS_INC(link.recv); + + return p; +} + +void ulwip_poll(void) +{ + struct pbuf *p; + int err; + struct netif *netif; + int eth_idx; + + eth_idx = eth_get_dev_index(); + if (eth_idx < 0) { + log_err("no eth idx\n"); + return; + } + + netif = netif_get_by_index(eth_idx + 1); + if (!netif) { + log_err("!netif\n"); + return; + } + + p = low_level_input(); + if (!p) { + log_err("no mem\n"); + return; + } + + /* ethernet_input always returns ERR_OK */ + err = ethernet_input(p, netif); + if (err) + log_err("ip4_input err %d\n", err); +} + +static int ethernetif_input(struct pbuf *p, struct netif *netif) +{ + struct ethernetif *ethernetif; + + ethernetif = netif->state; + + /* move received packet into a new pbuf */ + p = low_level_input(); + + /* if no packet could be read, silently ignore this */ + if (p) { + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("%s: IP input error\n", __func__)); + pbuf_free(p); + p = NULL; + } + } + + return 0; +} + +static err_t low_level_output(struct netif *netif, struct pbuf *p) +{ + int err; + + /* switch dev to active state */ + eth_init_state_only(); + + err = eth_send(p->payload, p->len); + if (err) { + log_err("eth_send error %d\n", err); + return ERR_ABRT; + } + return ERR_OK; +} + +err_t ulwip_if_init(struct netif *netif) +{ + ulwip_if_t *uif; + struct ulwip *ulwip; + + uif = malloc(sizeof(ulwip_if_t)); + if (!uif) { + log_err("uif: out of memory\n"); + return ERR_MEM; + } + netif->state = uif; + +#if defined(CONFIG_LWIP_LIB_DEBUG) + log_info(" MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", + netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], + netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]); + log_info(" NAME: %s\n", netif->name); +#endif +#if LWIP_IPV4 + netif->output = etharp_output; +#endif +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif + + netif->linkoutput = low_level_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + + ulwip = eth_lwip_priv(eth_get_dev()); + ulwip->init_done = 1; + + return ERR_OK; +} + +int ulwip_init(void) +{ + ip4_addr_t ipaddr, netmask, gw; + struct netif *unetif; + struct ulwip *ulwip; + struct udevice *udev; + int ret; + unsigned char env_enetaddr[ARP_HLEN]; + const struct udevice *dev; + struct uclass *uc; + + ret = eth_init(); + if (ret) { + log_err("eth_init error %d\n", ret); + return ERR_IF; + } + + udev = eth_get_dev(); + if (!udev) { + log_err("no active eth device\n"); + return ERR_IF; + } + + eth_set_current(); + + ulwip = eth_lwip_priv(udev); + if (ulwip->init_done) { + log_info("init already done for %s\n", udev->name); + return CMD_RET_SUCCESS; + } + + uclass_id_foreach_dev(UCLASS_ETH, dev, uc) { + char ipstr[IP4ADDR_STRLEN_MAX]; + char maskstr[IP4ADDR_STRLEN_MAX]; + char gwstr[IP4ADDR_STRLEN_MAX]; + char hwstr[MAC_ADDR_STRLEN]; + + eth_env_get_enetaddr_by_index("eth", dev_seq(dev), env_enetaddr); + log_info("eth%d: %s %pM %s\n", dev_seq(dev), dev->name, env_enetaddr, + udev == dev ? "active" : ""); + + unetif = malloc(sizeof(struct netif)); + if (!unetif) + return ERR_MEM; + memset(unetif, 0, sizeof(struct netif)); + + ip4_addr_set_zero(&gw); + ip4_addr_set_zero(&ipaddr); + ip4_addr_set_zero(&netmask); + + if (dev_seq(dev) == 0) { + snprintf(ipstr, IP4ADDR_STRLEN_MAX, "ipaddr"); + snprintf(maskstr, IP4ADDR_STRLEN_MAX, "netmask"); + snprintf(gwstr, IP4ADDR_STRLEN_MAX, "gw"); + } else { + snprintf(ipstr, IP4ADDR_STRLEN_MAX, "ipaddr%d", dev_seq(dev)); + snprintf(maskstr, IP4ADDR_STRLEN_MAX, "netmask%d", dev_seq(dev)); + snprintf(gwstr, IP4ADDR_STRLEN_MAX, "gw%d", dev_seq(dev)); + } + snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", env_enetaddr); + snprintf(unetif->name, 2, "%d", dev_seq(dev)); + + string_to_enetaddr(hwstr, unetif->hwaddr); + unetif->hwaddr_len = ETHARP_HWADDR_LEN; + + ipaddr_aton(env_get(ipstr), &ipaddr); + ipaddr_aton(env_get(maskstr), &netmask); + + if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) { + log_info("Starting lwIP\n "); + log_info(" netdev: %s\n", dev->name); + log_info(" IP: %s\n", ip4addr_ntoa(&ipaddr)); + log_info(" GW: %s\n", ip4addr_ntoa(&gw)); + log_info(" mask: %s\n", ip4addr_ntoa(&netmask)); + } + +#if LWIP_IPV6 +#define MAC_FROM_48_BIT 1 + netif_create_ip6_linklocal_address(unetif, MAC_FROM_48_BIT); + log_info(" IPv6: %s\n", ip6addr_ntoa(netif_ip6_addr(unetif, 0))); +#endif /* LWIP_IPV6 */ + + if (!netif_add(unetif, &ipaddr, &netmask, &gw, + unetif, ulwip_if_init, ethernetif_input)) { + log_err("err: netif_add failed!\n"); + free(unetif); + return ERR_IF; + } + + netif_set_up(unetif); + netif_set_link_up(unetif); + } + + if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) { + log_info("Initialized LWIP stack\n"); + } + return CMD_RET_SUCCESS; +} + +/* placeholder, not used now */ +void ulwip_destroy(void) +{ +} diff --git a/net/lwip/port/include/arch/cc.h b/net/lwip/port/include/arch/cc.h new file mode 100644 index 0000000000..23fd51c308 --- /dev/null +++ b/net/lwip/port/include/arch/cc.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#ifndef LWIP_ARCH_CC_H +#define LWIP_ARCH_CC_H + +#include <linux/types.h> +#include <linux/kernel.h> +#include <vsprintf.h> +#include <rand.h> + +#define LWIP_ERRNO_INCLUDE <errno.h> + +#define LWIP_ERRNO_STDINCLUDE 1 +#define LWIP_NO_UNISTD_H 1 +#define LWIP_TIMEVAL_PRIVATE 1 + +#define LWIP_RAND() ((u32_t)rand()) + +/* different handling for unit test, normally not needed */ +#ifdef LWIP_NOASSERT_ON_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + handler; }} while (0) +#endif + +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS + +#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion "%s" failed at line %d in %s\n", \ + x, __LINE__, __FILE__); } while (0) + +#define atoi(str) (int)dectoul(str, NULL) + +#define LWIP_ERR_T int + +#endif /* LWIP_ARCH_CC_H */ diff --git a/net/lwip/port/include/arch/sys_arch.h b/net/lwip/port/include/arch/sys_arch.h new file mode 100644 index 0000000000..87a3fb66d1 --- /dev/null +++ b/net/lwip/port/include/arch/sys_arch.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#ifndef LWIP_ARCH_SYS_ARCH_H +#define LWIP_ARCH_SYS_ARCH_H + +#endif /* LWIP_ARCH_SYS_ARCH_H */ diff --git a/net/lwip/port/include/limits.h b/net/lwip/port/include/limits.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/net/lwip/port/sys-arch.c b/net/lwip/port/sys-arch.c new file mode 100644 index 0000000000..68476d16e8 --- /dev/null +++ b/net/lwip/port/sys-arch.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include <common.h> +#include "lwip/opt.h" + +u32_t sys_now(void) +{ + return get_timer(0); +}

ignore lwIP library code and reused files from the lwIP.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- net/lwip/.gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 net/lwip/.gitignore
diff --git a/net/lwip/.gitignore b/net/lwip/.gitignore new file mode 100644 index 0000000000..7b5dacce90 --- /dev/null +++ b/net/lwip/.gitignore @@ -0,0 +1,8 @@ +lwip-external +apps/ping/ping.c +apps/http/http_client.c +apps/http/http_client.h +apps/tftp/tftp.c +apps/tftp/tftp_client.h +apps/tftp/tftp_common.h +apps/tftp/tftp_example.h

On Tue, 26 Sept 2023 at 03:45, Maxim Uvarov maxim.uvarov@linaro.org wrote:
ignore lwIP library code and reused files from the lwIP.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
net/lwip/.gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 net/lwip/.gitignore
Reviewed-by: Simon Glass sjg@chromium.org

Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- cmd/Makefile | 1 + cmd/net-lwip.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 cmd/net-lwip.c
diff --git a/cmd/Makefile b/cmd/Makefile index 9bebf321c3..6ab6b16aab 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -128,6 +128,7 @@ endif obj-$(CONFIG_CMD_MUX) += mux.o obj-$(CONFIG_CMD_NAND) += nand.o obj-$(CONFIG_CMD_NET) += net.o +obj-$(CONFIG_CMD_NET) += net-lwip.o obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o obj-$(CONFIG_CMD_ONENAND) += onenand.o obj-$(CONFIG_CMD_OSD) += osd.o diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c new file mode 100644 index 0000000000..90a18fb789 --- /dev/null +++ b/cmd/net-lwip.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Maxim Uvarov, maxim.uvarov@linaro.org + */ + +#include <common.h> +#include <command.h> +#include <console.h> +#include <display_options.h> +#include <memalign.h> +#include <net.h> +#include <image.h> + +#include "net/lwip.h" +#include "net/ulwip.h" + +static int do_lwip_init(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + if (!ulwip_init()) + return CMD_RET_SUCCESS; + return CMD_RET_FAILURE; +} + +static void ulwip_timeout_handler(void) +{ + eth_halt(); + net_set_state(NETLOOP_FAIL); /* we did not get the reply */ + ulwip_loop_set(0); +} + +int ulwip_loop(void) +{ + int ret = CMD_RET_FAILURE; + + ulwip_loop_set(1); + if (!net_loop(LWIP)) + ret = CMD_RET_SUCCESS; + ulwip_loop_set(0); + return ret; +} + +#if defined(CONFIG_CMD_PING) +int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + log_info("Using %s device\n", eth_get_name()); + log_info("pinging addr: %s\n", argv[1]); + + if (ulwip_ping(argv[1])) { + printf("ping init fail\n"); + return CMD_RET_FAILURE; + } + + return ulwip_loop(); +} +#endif /* CONFIG_CMD_PING */ + +#if defined(CONFIG_CMD_WGET) +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + char *url; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + url = argv[1]; + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = ulwip_wget(image_load_addr, url); + if (ret) { + log_err("lwip_wget err %d\n", ret); + return CMD_RET_FAILURE; + } + + + return ulwip_loop(); +} +#endif + +#if defined(CONFIG_CMD_TFTPBOOT) +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + char *filename; + ulong addr; + char *end; + int ret; + + switch (argc) { + case 1: + filename = env_get("bootfile"); + break; + case 2: + /* + * Only one arg - accept two forms: + * Just load address, or just boot file name. The latter + * form must be written in a format which can not be + * mis-interpreted as a valid number. + */ + addr = hextoul(argv[1], &end); + if (end == (argv[1] + strlen(argv[1]))) { + image_load_addr = addr; + filename = env_get("bootfile"); + } else { + filename = argv[1]; + } + break; + case 3: + image_load_addr = hextoul(argv[1], NULL); + filename = argv[2]; + break; + default: + return CMD_RET_USAGE; + } + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = ulwip_tftp(image_load_addr, filename); + if (ret) + return ret; + + return ulwip_loop(); +} +#endif /* CONFIG_CMD_TFTPBOOT */ + +#if defined(CONFIG_CMD_DHCP) +int do_lwip_dhcp(void) +{ + int ret; + char *filename; + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = ulwip_dhcp(); + + net_set_timeout_handler(20000UL, ulwip_timeout_handler); + + ulwip_loop(); + if (IS_ENABLED(CONFIG_CMD_TFTPBOOT)) { + filename = env_get("bootfile"); + if (!filename) { + log_notice("no bootfile\n"); + return CMD_RET_SUCCESS; + } + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + net_set_timeout_handler(20000UL, ulwip_timeout_handler); + ulwip_tftp(image_load_addr, filename); + + ret = ulwip_loop(); + } + + return ret; +} + +static int _do_lwip_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_lwip_dhcp(); +} +#endif /* CONFIG_CMD_DHCP */ + +#if defined(CONFIG_CMD_DNS) +int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret; + char *name; + char *varname; + + if (argc == 1) + return CMD_RET_USAGE; + + name = argv[1]; + + if (argc == 3) + varname = argv[2]; + else + varname = NULL; + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = ulwip_dns(name, varname); + if (ret == 0) + return CMD_RET_SUCCESS; + if (ret != -EINPROGRESS) + return CMD_RET_FAILURE; + + net_set_timeout_handler(1000UL, ulwip_timeout_handler); + + return ulwip_loop(); +} +#endif /* CONFIG_CMD_DNS */ + +static struct cmd_tbl cmds[] = { + U_BOOT_CMD_MKENT(init, 1, 0, do_lwip_init, + "initialize lwip stack", ""), +#if defined(CONFIG_CMD_PING) + U_BOOT_CMD_MKENT(ping, 2, 0, do_lwip_ping, + "send ICMP ECHO_REQUEST to network host", + "pingAddress"), +#endif +#if defined(CONFIG_CMD_WGET) + U_BOOT_CMD_MKENT(wget, 2, 0, do_lwip_wget, "", ""), +#endif +#if defined(CONFIG_CMD_TFTPBOOT) + U_BOOT_CMD_MKENT(tftp, 3, 0, do_lwip_tftp, + "boot image via network using TFTP protocol\n", + "[loadAddress] [[hostIPaddr:]bootfilename]"), +#endif +#if defined(CONFIG_CMD_DHCP) + U_BOOT_CMD_MKENT(dhcp, 1, 0, _do_lwip_dhcp, + "boot image via network using DHCP/TFTP protocol", + ""), +#endif +#if defined(CONFIG_CMD_DNS) + U_BOOT_CMD_MKENT(dns, 3, 0, do_lwip_dns, + "lookup dns name [and store address at variable]", + ""), +#endif +}; + +static int do_ops(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct cmd_tbl *cp; + + cp = find_cmd_tbl(argv[1], cmds, ARRAY_SIZE(cmds)); + + argc--; + argv++; + + if (cp == NULL || argc > cp->maxargs) + return CMD_RET_USAGE; + if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) + return CMD_RET_SUCCESS; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD( + lwip, 4, 1, do_ops, + "LWIP sub system", + "init - init LWIP\n" + "ping addr - pingAddress\n" + "wget http://IPadress/url/%5Cn" + "tftp [loadAddress] [[hostIPaddr:]bootfilename]\n" + "dhcp - boot image via network using DHCP/TFTP protocol\n" + );

On Tue, 26 Sept 2023 at 03:45, Maxim Uvarov maxim.uvarov@linaro.org wrote:
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
cmd/Makefile | 1 + cmd/net-lwip.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 cmd/net-lwip.c
Reviewed-by: Simon Glass sjg@chromium.org

Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86 +++++---------------------------------------- cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index ae936c8daa..52399d627c 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -20,6 +20,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/lwip.h> +#include <net/ulwip.h> #include <pxe_utils.h> #include <linux/sizes.h>
@@ -319,9 +321,7 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
static int distro_efi_read_bootflow_net(struct bootflow *bflow) { - char file_addr[17], fname[256]; - char *tftp_argv[] = {"tftp", file_addr, fname, NULL}; - struct cmd_tbl cmdtp = {}; /* dummy */ + char fname[256]; const char *addr_str, *fdt_addr_str; int ret, arch, size; ulong addr, fdt_addr; @@ -368,7 +368,6 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!fdt_addr_str) return log_msg_ret("fdt", -EINVAL); fdt_addr = hextoul(fdt_addr_str, NULL); - sprintf(file_addr, "%lx", fdt_addr);
/* We only allow the first prefix with PXE */ ret = distro_efi_get_fdt_name(fname, sizeof(fname), 0); @@ -379,7 +378,16 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM);
- if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) { + ret = ulwip_init(); + if (ret) + return log_msg_ret("ulwip_init", ret); + + ret = ulwip_tftp(fdt_addr, fname); + if (ret) + return log_msg_ret("ulwip_tftp", ret); + + ret = ulwip_loop(); + if (!ret) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else { diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 8d489a11aa..fc6aabaa18 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -21,6 +21,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/ulwip.h> +#include <net/lwip.h> #include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path, @@ -116,18 +118,21 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep) { - char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; - struct pxe_context *ctx = dev_get_priv(dev); - char file_addr[17]; ulong size; int ret;
- sprintf(file_addr, "%lx", addr); - tftp_argv[1] = file_addr; - tftp_argv[2] = (void *)file_path; + ret = ulwip_init(); + if (ret) + return log_msg_ret("ulwip_init", ret); + + ret = ulwip_tftp(addr, file_path); + if (ret) + return log_msg_ret("ulwip_tftp", ret); + + ret = ulwip_loop(); + if (ret) + return log_msg_ret("ulwip_loop", ret);
- if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv)) - return -ENOENT; ret = pxe_get_file_size(&size); if (ret) return log_msg_ret("tftp", ret); diff --git a/cmd/net.c b/cmd/net.c index d407d8320a..dc5a114309 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -22,6 +22,7 @@ #include <net/udp.h> #include <net/sntp.h> #include <net/ncsi.h> +#include <net/lwip.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
@@ -40,19 +41,9 @@ U_BOOT_CMD( #endif
#ifdef CONFIG_CMD_TFTPBOOT -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{ - int ret; - - bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start"); - ret = netboot_common(TFTPGET, cmdtp, argc, argv); - bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done"); - return ret; -} - #if IS_ENABLED(CONFIG_IPV6) U_BOOT_CMD( - tftpboot, 4, 1, do_tftpb, + tftpboot, 4, 1, do_lwip_tftp, "boot image via network using TFTP protocol\n" "To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed " "with [] brackets", @@ -60,7 +51,7 @@ U_BOOT_CMD( ); #else U_BOOT_CMD( - tftpboot, 3, 1, do_tftpb, + tftpboot, 3, 1, do_lwip_tftp, "load file via network using TFTP protocol", "[loadAddress] [[hostIPaddr:]bootfilename]" ); @@ -139,7 +130,7 @@ U_BOOT_CMD(dhcp6, 3, 1, do_dhcp6, static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - return netboot_common(DHCP, cmdtp, argc, argv); + return do_lwip_dhcp(); }
U_BOOT_CMD( @@ -196,13 +187,11 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_WGET) -static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) -{ - return netboot_common(WGET, cmdtp, argc, argv); -} +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]);
U_BOOT_CMD( - wget, 3, 1, do_wget, + wget, 3, 1, do_lwip_wget, "boot image via network using HTTP protocol", "[loadAddress] [[hostIPaddr:]path and image name]" ); @@ -456,28 +445,8 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, }
#if defined(CONFIG_CMD_PING) -static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - if (argc < 2) - return CMD_RET_USAGE; - - net_ping_ip = string_to_ip(argv[1]); - if (net_ping_ip.s_addr == 0) - return CMD_RET_USAGE; - - if (net_loop(PING) < 0) { - printf("ping failed; host %s is not alive\n", argv[1]); - return CMD_RET_FAILURE; - } - - printf("host %s is alive\n", argv[1]); - - return CMD_RET_SUCCESS; -} - U_BOOT_CMD( - ping, 2, 1, do_ping, + ping, 2, 1, do_lwip_ping, "send ICMP ECHO_REQUEST to network host", "pingAddress" ); @@ -601,45 +570,8 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_DNS) -int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{ - if (argc == 1) - return CMD_RET_USAGE; - - /* - * We should check for a valid hostname: - * - Each label must be between 1 and 63 characters long - * - the entire hostname has a maximum of 255 characters - * - only the ASCII letters 'a' through 'z' (case-insensitive), - * the digits '0' through '9', and the hyphen - * - cannot begin or end with a hyphen - * - no other symbols, punctuation characters, or blank spaces are - * permitted - * but hey - this is a minimalist implmentation, so only check length - * and let the name server deal with things. - */ - if (strlen(argv[1]) >= 255) { - printf("dns error: hostname too long\n"); - return CMD_RET_FAILURE; - } - - net_dns_resolve = argv[1]; - - if (argc == 3) - net_dns_env_var = argv[2]; - else - net_dns_env_var = NULL; - - if (net_loop(DNS) < 0) { - printf("dns lookup of %s failed, check setup\n", argv[1]); - return CMD_RET_FAILURE; - } - - return CMD_RET_SUCCESS; -} - U_BOOT_CMD( - dns, 3, 1, do_dns, + dns, 3, 1, do_lwip_dns, "lookup the IP of a hostname", "hostname [envvar]" ); diff --git a/cmd/pxe.c b/cmd/pxe.c index 677142520b..d44df428d2 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -8,6 +8,7 @@ #include <command.h> #include <fs.h> #include <net.h> +#include <net/lwip.h> #include <net6.h> #include <malloc.h>
@@ -29,21 +30,19 @@ const char *pxe_default_paths[] = { static int do_get_tftp(struct pxe_context *ctx, const char *file_path, char *file_addr, ulong *sizep) { - char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; + ulong addr; + char *end; int ret; - int num_args;
- tftp_argv[1] = file_addr; - tftp_argv[2] = (void *)file_path; + addr = hextoul(file_addr, &end); + if (ctx->use_ipv6) { - tftp_argv[3] = USE_IP6_CMD_PARAM; - num_args = 4; - } else { - num_args = 3; + /* @todo: check and fix me, here */ }
- if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv)) - return -ENOENT; + ret = ulwip_tftp(addr, file_path); + if (ret) + return log_msg_ret("tftp", ret);
ret = pxe_get_file_size(sizep); if (ret) diff --git a/include/net.h b/include/net.h index e254df7d7f..de7baeb121 100644 --- a/include/net.h +++ b/include/net.h @@ -54,8 +54,10 @@ struct in_addr { __be32 s_addr; };
+int do_lwip_dhcp(void); + /** - * do_tftpb - Run the tftpboot command + * do_lwip_tftp - Run the tftpboot command * * @cmdtp: Command information for tftpboot * @flag: Command flags (CMD_FLAG_...) @@ -63,7 +65,7 @@ struct in_addr { * @argv: List of arguments * Return: result (see enum command_ret_t) */ -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
/** * dhcp_run() - Run DHCP on the current ethernet device @@ -514,7 +516,7 @@ extern int net_restart_wrap; /* Tried all network devices */ enum proto_t { BOOTP, RARP, ARP, TFTPGET, DHCP, DHCP6, PING, PING6, DNS, NFS, CDP, NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT_UDP, FASTBOOT_TCP, - WOL, UDP, NCSI, WGET, RS + WOL, UDP, NCSI, WGET, RS, LWIP };
extern char net_boot_file_name[1024];/* Boot File name */ diff --git a/include/net/ulwip.h b/include/net/ulwip.h new file mode 100644 index 0000000000..8eac7aa130 --- /dev/null +++ b/include/net/ulwip.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/** + * ulwip_init() - initialize lwIP network stack + * + * @return 0 if success, !0 if error + */ +int ulwip_init(void); + +/** + * ulwip_enabled() - check if lwIP network stack was initialized + * + * @return 1 lwip initialized, 0 if not yet initialized + */ +int ulwip_enabled(void); + +/** + * ulwip_in_loop() - lwIP controls packet net loop + * + * @return 1 lwIP owns packet loop, 0 lwip does not own packet loop + */ +int ulwip_in_loop(void); + +/** + * ulwip_loop_set() - make loop to be used by lwIP + * + * Function is used to make lwIP control network pool. + * + * @loop: 1. Rx packets go to lwIP 2. Rx packets go to the original stack. + */ +void ulwip_loop_set(int loop); + +/** + * ulwip_exit() - exit from lwIP with a return code + * + * Exit from lwIP application back to the U-Boot with specific error code. + * + * @err: Error code to return + */ +void ulwip_exit(int err); + +/** + * ulwip_poll() - polling function to feed lwIP with ethernet packet + * + * Function takes network packet and passes it to lwIP network stack + */ +void ulwip_poll(void); + +/** + * ulwip_app_get_err() - return error code from lwIP application + * + * @return error code + */ +int ulwip_app_get_err(void); + +/** + * ulwip_loop() - enter to packet polling loop + * + * When lwIP application did it's initialization stage, then it needs to enter + * to packet polling loop to grab rx packets. + * + * Returns: 0 if success, !0 if error + */ +int ulwip_loop(void);

On Tue, 26 Sept 2023 at 03:46, Maxim Uvarov maxim.uvarov@linaro.org wrote:
Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86 +++++---------------------------------------- cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
Reviewed-by: Simon Glass sjg@chromium.org
I don't really understand the error handling. I'm not sure why we have void functions everywhere?

On 2023-09-26 2:41 a.m., Maxim Uvarov wrote:
Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarovmaxim.uvarov@linaro.org
boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86 +++++---------------------------------------- cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index ae936c8daa..52399d627c 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -20,6 +20,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/lwip.h> +#include <net/ulwip.h> #include <pxe_utils.h> #include <linux/sizes.h>
@@ -319,9 +321,7 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
static int distro_efi_read_bootflow_net(struct bootflow *bflow) {
- char file_addr[17], fname[256];
- char *tftp_argv[] = {"tftp", file_addr, fname, NULL};
- struct cmd_tbl cmdtp = {}; /* dummy */
- char fname[256]; const char *addr_str, *fdt_addr_str; int ret, arch, size; ulong addr, fdt_addr;
@@ -368,7 +368,6 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!fdt_addr_str) return log_msg_ret("fdt", -EINVAL); fdt_addr = hextoul(fdt_addr_str, NULL);
sprintf(file_addr, "%lx", fdt_addr);
/* We only allow the first prefix with PXE */ ret = distro_efi_get_fdt_name(fname, sizeof(fname), 0);
@@ -379,7 +378,16 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM);
- if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) {
- ret = ulwip_init();
- if (ret)
return log_msg_ret("ulwip_init", ret);
- ret = ulwip_tftp(fdt_addr, fname);
- if (ret)
return log_msg_ret("ulwip_tftp", ret);
- ret = ulwip_loop();
- if (!ret) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else {
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 8d489a11aa..fc6aabaa18 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -21,6 +21,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/ulwip.h> +#include <net/lwip.h> #include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path, @@ -116,18 +118,21 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep) {
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
struct pxe_context *ctx = dev_get_priv(dev);
char file_addr[17]; ulong size; int ret;
sprintf(file_addr, "%lx", addr);
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
- ret = ulwip_init();
- if (ret)
return log_msg_ret("ulwip_init", ret);
- ret = ulwip_tftp(addr, file_path);
- if (ret)
return log_msg_ret("ulwip_tftp", ret);
- ret = ulwip_loop();
- if (ret)
return log_msg_ret("ulwip_loop", ret);
- if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
ret = pxe_get_file_size(&size); if (ret) return log_msg_ret("tftp", ret);return -ENOENT;
diff --git a/cmd/net.c b/cmd/net.c index d407d8320a..dc5a114309 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -22,6 +22,7 @@ #include <net/udp.h> #include <net/sntp.h> #include <net/ncsi.h> +#include <net/lwip.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
@@ -40,19 +41,9 @@ U_BOOT_CMD( #endif
#ifdef CONFIG_CMD_TFTPBOOT -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{
- int ret;
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
- ret = netboot_common(TFTPGET, cmdtp, argc, argv);
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
- return ret;
-}
- #if IS_ENABLED(CONFIG_IPV6) U_BOOT_CMD(
- tftpboot, 4, 1, do_tftpb,
- tftpboot, 4, 1, do_lwip_tftp,
It looks like LWIP doesn't support TFTP with IPv6 addressing. Perhaps we need to fall back onto the existing TFTP implementation until LWIP supports it?
Note, that currently, IPv6 TFTP is enabled using the "-ipv6" argument. The intention is that netboot_common() sees the argument and sets the "use_ip6" variable. It looks like the new implementation in do_lwip_tftp() doesn't re-use the argument parsing in netboot_common() and that it doesn't handle the addition of the "-ipv6" flag.
I support the addition of LWIP, but I'm concerned about how abrupt changes like this one will be for existing users. The underlying stack will change, with no easy way for the user to revert to the previous stack. Has there been any discussion about preserving the existing functionality, with an option to enable/disable LWIP stack?This would give the community time to transition/validate LWIP before deprecating the old u-boot networking stack.
"boot image via network using TFTP protocol\n" "To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed " "with [] brackets", @@ -60,7 +51,7 @@ U_BOOT_CMD( ); #else U_BOOT_CMD(
- tftpboot, 3, 1, do_tftpb,
- tftpboot, 3, 1, do_lwip_tftp, "load file via network using TFTP protocol", "[loadAddress] [[hostIPaddr:]bootfilename]" );
@@ -139,7 +130,7 @@ U_BOOT_CMD(dhcp6, 3, 1, do_dhcp6, static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) {
- return netboot_common(DHCP, cmdtp, argc, argv);
return do_lwip_dhcp(); }
U_BOOT_CMD(
@@ -196,13 +187,11 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_WGET) -static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) -{
- return netboot_common(WGET, cmdtp, argc, argv);
-} +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
U_BOOT_CMD(
- wget, 3, 1, do_wget,
- wget, 3, 1, do_lwip_wget, "boot image via network using HTTP protocol", "[loadAddress] [[hostIPaddr:]path and image name]" );
@@ -456,28 +445,8 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, }
#if defined(CONFIG_CMD_PING) -static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
-{
- if (argc < 2)
return CMD_RET_USAGE;
- net_ping_ip = string_to_ip(argv[1]);
- if (net_ping_ip.s_addr == 0)
return CMD_RET_USAGE;
- if (net_loop(PING) < 0) {
printf("ping failed; host %s is not alive\n", argv[1]);
return CMD_RET_FAILURE;
- }
- printf("host %s is alive\n", argv[1]);
- return CMD_RET_SUCCESS;
-}
- U_BOOT_CMD(
- ping, 2, 1, do_ping,
- ping, 2, 1, do_lwip_ping, "send ICMP ECHO_REQUEST to network host", "pingAddress" );
@@ -601,45 +570,8 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_DNS) -int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{
- if (argc == 1)
return CMD_RET_USAGE;
- /*
* We should check for a valid hostname:
* - Each label must be between 1 and 63 characters long
* - the entire hostname has a maximum of 255 characters
* - only the ASCII letters 'a' through 'z' (case-insensitive),
* the digits '0' through '9', and the hyphen
* - cannot begin or end with a hyphen
* - no other symbols, punctuation characters, or blank spaces are
* permitted
* but hey - this is a minimalist implmentation, so only check length
* and let the name server deal with things.
*/
- if (strlen(argv[1]) >= 255) {
printf("dns error: hostname too long\n");
return CMD_RET_FAILURE;
- }
- net_dns_resolve = argv[1];
- if (argc == 3)
net_dns_env_var = argv[2];
- else
net_dns_env_var = NULL;
- if (net_loop(DNS) < 0) {
printf("dns lookup of %s failed, check setup\n", argv[1]);
return CMD_RET_FAILURE;
- }
- return CMD_RET_SUCCESS;
-}
- U_BOOT_CMD(
- dns, 3, 1, do_dns,
- dns, 3, 1, do_lwip_dns, "lookup the IP of a hostname", "hostname [envvar]" );
diff --git a/cmd/pxe.c b/cmd/pxe.c index 677142520b..d44df428d2 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -8,6 +8,7 @@ #include <command.h> #include <fs.h> #include <net.h> +#include <net/lwip.h> #include <net6.h> #include <malloc.h>
@@ -29,21 +30,19 @@ const char *pxe_default_paths[] = { static int do_get_tftp(struct pxe_context *ctx, const char *file_path, char *file_addr, ulong *sizep) {
- char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
- ulong addr;
- char *end; int ret;
int num_args;
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
- addr = hextoul(file_addr, &end);
- if (ctx->use_ipv6) {
tftp_argv[3] = USE_IP6_CMD_PARAM;
num_args = 4;
- } else {
num_args = 3;
/* @todo: check and fix me, here */
Again, looks like LWIP doesn't support IPv6 addressing, we may want to fall back on existing TFTP implementation here.
}
- if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv))
return -ENOENT;
ret = ulwip_tftp(addr, file_path);
if (ret)
return log_msg_ret("tftp", ret);
ret = pxe_get_file_size(sizep); if (ret)
diff --git a/include/net.h b/include/net.h index e254df7d7f..de7baeb121 100644 --- a/include/net.h +++ b/include/net.h @@ -54,8 +54,10 @@ struct in_addr { __be32 s_addr; };
+int do_lwip_dhcp(void);
- /**
- do_tftpb - Run the tftpboot command
- do_lwip_tftp - Run the tftpboot command
- @cmdtp: Command information for tftpboot
- @flag: Command flags (CMD_FLAG_...)
@@ -63,7 +65,7 @@ struct in_addr {
- @argv: List of arguments
- Return: result (see enum command_ret_t)
*/ -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
/**
- dhcp_run() - Run DHCP on the current ethernet device
@@ -514,7 +516,7 @@ extern int net_restart_wrap; /* Tried all network devices */ enum proto_t { BOOTP, RARP, ARP, TFTPGET, DHCP, DHCP6, PING, PING6, DNS, NFS, CDP, NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT_UDP, FASTBOOT_TCP,
- WOL, UDP, NCSI, WGET, RS
WOL, UDP, NCSI, WGET, RS, LWIP };
extern char net_boot_file_name[1024];/* Boot File name */
diff --git a/include/net/ulwip.h b/include/net/ulwip.h new file mode 100644 index 0000000000..8eac7aa130 --- /dev/null +++ b/include/net/ulwip.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */
+/**
- ulwip_init() - initialize lwIP network stack
- @return 0 if success, !0 if error
- */
+int ulwip_init(void);
+/**
- ulwip_enabled() - check if lwIP network stack was initialized
- @return 1 lwip initialized, 0 if not yet initialized
- */
+int ulwip_enabled(void);
+/**
- ulwip_in_loop() - lwIP controls packet net loop
- @return 1 lwIP owns packet loop, 0 lwip does not own packet loop
- */
+int ulwip_in_loop(void);
+/**
- ulwip_loop_set() - make loop to be used by lwIP
- Function is used to make lwIP control network pool.
- @loop: 1. Rx packets go to lwIP 2. Rx packets go to the original stack.
- */
+void ulwip_loop_set(int loop);
+/**
- ulwip_exit() - exit from lwIP with a return code
- Exit from lwIP application back to the U-Boot with specific error code.
- @err: Error code to return
- */
+void ulwip_exit(int err);
+/**
- ulwip_poll() - polling function to feed lwIP with ethernet packet
- Function takes network packet and passes it to lwIP network stack
- */
+void ulwip_poll(void);
+/**
- ulwip_app_get_err() - return error code from lwIP application
- @return error code
- */
+int ulwip_app_get_err(void);
+/**
- ulwip_loop() - enter to packet polling loop
- When lwIP application did it's initialization stage, then it needs to enter
- to packet polling loop to grab rx packets.
- Returns: 0 if success, !0 if error
- */
+int ulwip_loop(void);

On Tue, Oct 3, 2023 at 6:58 PM Sean Edmond seanedmond@linux.microsoft.com wrote:
On 2023-09-26 2:41 a.m., Maxim Uvarov wrote:
Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86 +++++---------------------------------------- cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index ae936c8daa..52399d627c 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -20,6 +20,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/lwip.h> +#include <net/ulwip.h> #include <pxe_utils.h> #include <linux/sizes.h>
@@ -319,9 +321,7 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
static int distro_efi_read_bootflow_net(struct bootflow *bflow) {
- char file_addr[17], fname[256];
- char *tftp_argv[] = {"tftp", file_addr, fname, NULL};
- struct cmd_tbl cmdtp = {}; /* dummy */
- char fname[256]; const char *addr_str, *fdt_addr_str; int ret, arch, size; ulong addr, fdt_addr;
@@ -368,7 +368,6 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!fdt_addr_str) return log_msg_ret("fdt", -EINVAL); fdt_addr = hextoul(fdt_addr_str, NULL);
sprintf(file_addr, "%lx", fdt_addr);
/* We only allow the first prefix with PXE */ ret = distro_efi_get_fdt_name(fname, sizeof(fname), 0);
@@ -379,7 +378,16 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM);
- if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) {
- ret = ulwip_init();
- if (ret)
- return log_msg_ret("ulwip_init", ret);
- ret = ulwip_tftp(fdt_addr, fname);
- if (ret)
- return log_msg_ret("ulwip_tftp", ret);
- ret = ulwip_loop();
- if (!ret) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else {
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 8d489a11aa..fc6aabaa18 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -21,6 +21,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/ulwip.h> +#include <net/lwip.h> #include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path, @@ -116,18 +118,21 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep) {
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
struct pxe_context *ctx = dev_get_priv(dev);
char file_addr[17]; ulong size; int ret;
sprintf(file_addr, "%lx", addr);
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
- ret = ulwip_init();
- if (ret)
- return log_msg_ret("ulwip_init", ret);
- ret = ulwip_tftp(addr, file_path);
- if (ret)
- return log_msg_ret("ulwip_tftp", ret);
- ret = ulwip_loop();
- if (ret)
- return log_msg_ret("ulwip_loop", ret);
- if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
- return -ENOENT; ret = pxe_get_file_size(&size); if (ret) return log_msg_ret("tftp", ret);
diff --git a/cmd/net.c b/cmd/net.c index d407d8320a..dc5a114309 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -22,6 +22,7 @@ #include <net/udp.h> #include <net/sntp.h> #include <net/ncsi.h> +#include <net/lwip.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
@@ -40,19 +41,9 @@ U_BOOT_CMD( #endif
#ifdef CONFIG_CMD_TFTPBOOT -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{
- int ret;
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
- ret = netboot_common(TFTPGET, cmdtp, argc, argv);
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
- return ret;
-}
#if IS_ENABLED(CONFIG_IPV6) U_BOOT_CMD(
- tftpboot, 4, 1, do_tftpb,
- tftpboot, 4, 1, do_lwip_tftp,
It looks like LWIP doesn't support TFTP with IPv6 addressing. Perhaps we need to fall back onto the existing TFTP implementation until LWIP supports it?
Is it that LWIP upstream doesn't support IPv6 with TFTP or it just hasn't been dealt with in this patch set? If the former might be useful to reference details.
Note, that currently, IPv6 TFTP is enabled using the "-ipv6" argument. The intention is that netboot_common() sees the argument and sets the "use_ip6" variable. It looks like the new implementation in do_lwip_tftp() doesn't re-use the argument parsing in netboot_common() and that it doesn't handle the addition of the "-ipv6" flag.
Is there a reason why there's a need of an explicit argument for IPv6? I would have thought if there was a local IPv6 address assigned that you would automatically try IPv6 and if it fails for back to v4, or even better do a DNS lookup and use what ever gets returned. Having to know what to use by manually specifying a parameter doesn't sound like a great user experience, what's the use case?
I support the addition of LWIP, but I'm concerned about how abrupt changes like this one will be for existing users. The underlying stack will change, with no easy way for the user to revert to the previous stack. Has there been any discussion about preserving the existing functionality, with an option to enable/disable LWIP stack? This would give the community time to transition/validate LWIP before deprecating the old u-boot networking stack.
The problem is how long do we maintain dual stacks, do we default to which one, when do we switch the defaults, how long do we wait to remove the stack and the maintenance burden on the small amount of maintainers?
"boot image via network using TFTP protocol\n" "To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed " "with [] brackets", @@ -60,7 +51,7 @@ U_BOOT_CMD( ); #else U_BOOT_CMD(
- tftpboot, 3, 1, do_tftpb,
- tftpboot, 3, 1, do_lwip_tftp, "load file via network using TFTP protocol", "[loadAddress] [[hostIPaddr:]bootfilename]"
); @@ -139,7 +130,7 @@ U_BOOT_CMD(dhcp6, 3, 1, do_dhcp6, static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) {
- return netboot_common(DHCP, cmdtp, argc, argv);
- return do_lwip_dhcp();
}
U_BOOT_CMD( @@ -196,13 +187,11 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_WGET) -static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) -{
- return netboot_common(WGET, cmdtp, argc, argv);
-} +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[]);
U_BOOT_CMD(
- wget, 3, 1, do_wget,
- wget, 3, 1, do_lwip_wget, "boot image via network using HTTP protocol", "[loadAddress] [[hostIPaddr:]path and image name]"
); @@ -456,28 +445,8 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, }
#if defined(CONFIG_CMD_PING) -static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[])
-{
- if (argc < 2)
- return CMD_RET_USAGE;
- net_ping_ip = string_to_ip(argv[1]);
- if (net_ping_ip.s_addr == 0)
- return CMD_RET_USAGE;
- if (net_loop(PING) < 0) {
- printf("ping failed; host %s is not alive\n", argv[1]);
- return CMD_RET_FAILURE;
- }
- printf("host %s is alive\n", argv[1]);
- return CMD_RET_SUCCESS;
-}
U_BOOT_CMD(
- ping, 2, 1, do_ping,
- ping, 2, 1, do_lwip_ping, "send ICMP ECHO_REQUEST to network host", "pingAddress"
); @@ -601,45 +570,8 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_DNS) -int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{
- if (argc == 1)
- return CMD_RET_USAGE;
- /*
- We should check for a valid hostname:
- Each label must be between 1 and 63 characters long
- the entire hostname has a maximum of 255 characters
- only the ASCII letters 'a' through 'z' (case-insensitive),
- the digits '0' through '9', and the hyphen
- cannot begin or end with a hyphen
- no other symbols, punctuation characters, or blank spaces are
- permitted
- but hey - this is a minimalist implmentation, so only check length
- and let the name server deal with things.
- */
- if (strlen(argv[1]) >= 255) {
- printf("dns error: hostname too long\n");
- return CMD_RET_FAILURE;
- }
- net_dns_resolve = argv[1];
- if (argc == 3)
- net_dns_env_var = argv[2];
- else
- net_dns_env_var = NULL;
- if (net_loop(DNS) < 0) {
- printf("dns lookup of %s failed, check setup\n", argv[1]);
- return CMD_RET_FAILURE;
- }
- return CMD_RET_SUCCESS;
-}
U_BOOT_CMD(
- dns, 3, 1, do_dns,
- dns, 3, 1, do_lwip_dns, "lookup the IP of a hostname", "hostname [envvar]"
); diff --git a/cmd/pxe.c b/cmd/pxe.c index 677142520b..d44df428d2 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -8,6 +8,7 @@ #include <command.h> #include <fs.h> #include <net.h> +#include <net/lwip.h> #include <net6.h> #include <malloc.h>
@@ -29,21 +30,19 @@ const char *pxe_default_paths[] = { static int do_get_tftp(struct pxe_context *ctx, const char *file_path, char *file_addr, ulong *sizep) {
- char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
- ulong addr;
- char *end; int ret;
int num_args;
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
- addr = hextoul(file_addr, &end);
- if (ctx->use_ipv6) {
- tftp_argv[3] = USE_IP6_CMD_PARAM;
- num_args = 4;
- } else {
- num_args = 3;
- /* @todo: check and fix me, here */
Again, looks like LWIP doesn't support IPv6 addressing, we may want to fall back on existing TFTP implementation here.
}
- if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv))
- return -ENOENT;
ret = ulwip_tftp(addr, file_path);
if (ret)
return log_msg_ret("tftp", ret);
ret = pxe_get_file_size(sizep); if (ret)
diff --git a/include/net.h b/include/net.h index e254df7d7f..de7baeb121 100644 --- a/include/net.h +++ b/include/net.h @@ -54,8 +54,10 @@ struct in_addr { __be32 s_addr; };
+int do_lwip_dhcp(void);
/**
- do_tftpb - Run the tftpboot command
- do_lwip_tftp - Run the tftpboot command
- @cmdtp: Command information for tftpboot
- @flag: Command flags (CMD_FLAG_...)
@@ -63,7 +65,7 @@ struct in_addr {
- @argv: List of arguments
- Return: result (see enum command_ret_t)
*/ -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
/**
- dhcp_run() - Run DHCP on the current ethernet device
@@ -514,7 +516,7 @@ extern int net_restart_wrap; /* Tried all network devices */ enum proto_t { BOOTP, RARP, ARP, TFTPGET, DHCP, DHCP6, PING, PING6, DNS, NFS, CDP, NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT_UDP, FASTBOOT_TCP,
- WOL, UDP, NCSI, WGET, RS
- WOL, UDP, NCSI, WGET, RS, LWIP
};
extern char net_boot_file_name[1024];/* Boot File name */ diff --git a/include/net/ulwip.h b/include/net/ulwip.h new file mode 100644 index 0000000000..8eac7aa130 --- /dev/null +++ b/include/net/ulwip.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */
+/**
- ulwip_init() - initialize lwIP network stack
- @return 0 if success, !0 if error
- */
+int ulwip_init(void);
+/**
- ulwip_enabled() - check if lwIP network stack was initialized
- @return 1 lwip initialized, 0 if not yet initialized
- */
+int ulwip_enabled(void);
+/**
- ulwip_in_loop() - lwIP controls packet net loop
- @return 1 lwIP owns packet loop, 0 lwip does not own packet loop
- */
+int ulwip_in_loop(void);
+/**
- ulwip_loop_set() - make loop to be used by lwIP
- Function is used to make lwIP control network pool.
- @loop: 1. Rx packets go to lwIP 2. Rx packets go to the original stack.
- */
+void ulwip_loop_set(int loop);
+/**
- ulwip_exit() - exit from lwIP with a return code
- Exit from lwIP application back to the U-Boot with specific error code.
- @err: Error code to return
- */
+void ulwip_exit(int err);
+/**
- ulwip_poll() - polling function to feed lwIP with ethernet packet
- Function takes network packet and passes it to lwIP network stack
- */
+void ulwip_poll(void);
+/**
- ulwip_app_get_err() - return error code from lwIP application
- @return error code
- */
+int ulwip_app_get_err(void);
+/**
- ulwip_loop() - enter to packet polling loop
- When lwIP application did it's initialization stage, then it needs to enter
- to packet polling loop to grab rx packets.
- Returns: 0 if success, !0 if error
- */
+int ulwip_loop(void);

On 2023-10-03 2:58 p.m., Peter Robinson wrote:
On Tue, Oct 3, 2023 at 6:58 PM Sean Edmond seanedmond@linux.microsoft.com wrote:
On 2023-09-26 2:41 a.m., Maxim Uvarov wrote:
Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarovmaxim.uvarov@linaro.org
boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86 +++++---------------------------------------- cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index ae936c8daa..52399d627c 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -20,6 +20,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/lwip.h> +#include <net/ulwip.h> #include <pxe_utils.h> #include <linux/sizes.h>
@@ -319,9 +321,7 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
static int distro_efi_read_bootflow_net(struct bootflow *bflow) {
- char file_addr[17], fname[256];
- char *tftp_argv[] = {"tftp", file_addr, fname, NULL};
- struct cmd_tbl cmdtp = {}; /* dummy */
- char fname[256]; const char *addr_str, *fdt_addr_str; int ret, arch, size; ulong addr, fdt_addr;
@@ -368,7 +368,6 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!fdt_addr_str) return log_msg_ret("fdt", -EINVAL); fdt_addr = hextoul(fdt_addr_str, NULL);
sprintf(file_addr, "%lx", fdt_addr);
/* We only allow the first prefix with PXE */ ret = distro_efi_get_fdt_name(fname, sizeof(fname), 0);
@@ -379,7 +378,16 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM);
- if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) {
- ret = ulwip_init();
- if (ret)
- return log_msg_ret("ulwip_init", ret);
- ret = ulwip_tftp(fdt_addr, fname);
- if (ret)
- return log_msg_ret("ulwip_tftp", ret);
- ret = ulwip_loop();
- if (!ret) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else {
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 8d489a11aa..fc6aabaa18 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -21,6 +21,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/ulwip.h> +#include <net/lwip.h> #include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path, @@ -116,18 +118,21 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep) {
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
struct pxe_context *ctx = dev_get_priv(dev);
char file_addr[17]; ulong size; int ret;
sprintf(file_addr, "%lx", addr);
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
- ret = ulwip_init();
- if (ret)
- return log_msg_ret("ulwip_init", ret);
- ret = ulwip_tftp(addr, file_path);
- if (ret)
- return log_msg_ret("ulwip_tftp", ret);
- ret = ulwip_loop();
- if (ret)
- return log_msg_ret("ulwip_loop", ret);
- if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
- return -ENOENT; ret = pxe_get_file_size(&size); if (ret) return log_msg_ret("tftp", ret);
diff --git a/cmd/net.c b/cmd/net.c index d407d8320a..dc5a114309 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -22,6 +22,7 @@ #include <net/udp.h> #include <net/sntp.h> #include <net/ncsi.h> +#include <net/lwip.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
@@ -40,19 +41,9 @@ U_BOOT_CMD( #endif
#ifdef CONFIG_CMD_TFTPBOOT -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{
- int ret;
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
- ret = netboot_common(TFTPGET, cmdtp, argc, argv);
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
- return ret;
-}
- #if IS_ENABLED(CONFIG_IPV6) U_BOOT_CMD(
- tftpboot, 4, 1, do_tftpb,
- tftpboot, 4, 1, do_lwip_tftp,
It looks like LWIP doesn't support TFTP with IPv6 addressing. Perhaps we need to fall back onto the existing TFTP implementation until LWIP supports it?
Is it that LWIP upstream doesn't support IPv6 with TFTP or it just hasn't been dealt with in this patch set? If the former might be useful to reference details.
Apologies for the misleading comment, LWIP does support IPv6 addressing, it just hasn't been dealt with in this patch.
Note, that currently, IPv6 TFTP is enabled using the "-ipv6" argument. The intention is that netboot_common() sees the argument and sets the "use_ip6" variable. It looks like the new implementation in do_lwip_tftp() doesn't re-use the argument parsing in netboot_common() and that it doesn't handle the addition of the "-ipv6" flag.
Is there a reason why there's a need of an explicit argument for IPv6? I would have thought if there was a local IPv6 address assigned that you would automatically try IPv6 and if it fails for back to v4, or even better do a DNS lookup and use what ever gets returned. Having to know what to use by manually specifying a parameter doesn't sound like a great user experience, what's the use case?
This how IPv6 was added to the TFTP commands in the initial patch series. I added the "-ipv6" argument to the PXE commands. At the time it was accepted that explicit selection was required. In our case, we try IPv4 and then fallback to IPv6. For example:
< Try IPv4 > setenv autoload no; dhcp; pxe get; pxe boot; < If IPv4 fails try IPv6 > dhcp6; pxe get -ipv6; pxe boot -ipv6;
TFTP could intelligently select based on the environment variables. So, we could try IPv4 first if env variable "serverip" is set, otherwise try IPv6 if env variable "serverip6" is set. This would make things easier to use and would simplify the code. It's not clear why the "-ipv6" argument was used for the TFTP commands in the first place... I'm guessing it was to provide more control to the user.
I support the addition of LWIP, but I'm concerned about how abrupt changes like this one will be for existing users. The underlying stack will change, with no easy way for the user to revert to the previous stack. Has there been any discussion about preserving the existing functionality, with an option to enable/disable LWIP stack? This would give the community time to transition/validate LWIP before deprecating the old u-boot networking stack.
The problem is how long do we maintain dual stacks, do we default to which one, when do we switch the defaults, how long do we wait to remove the stack and the maintenance burden on the small amount of maintainers?
"boot image via network using TFTP protocol\n" "To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed " "with [] brackets", @@ -60,7 +51,7 @@ U_BOOT_CMD( ); #else U_BOOT_CMD(
- tftpboot, 3, 1, do_tftpb,
- tftpboot, 3, 1, do_lwip_tftp, "load file via network using TFTP protocol", "[loadAddress] [[hostIPaddr:]bootfilename]" );
@@ -139,7 +130,7 @@ U_BOOT_CMD(dhcp6, 3, 1, do_dhcp6, static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) {
- return netboot_common(DHCP, cmdtp, argc, argv);
return do_lwip_dhcp(); }
U_BOOT_CMD(
@@ -196,13 +187,11 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_WGET) -static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) -{
- return netboot_common(WGET, cmdtp, argc, argv);
-} +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
U_BOOT_CMD(
- wget, 3, 1, do_wget,
- wget, 3, 1, do_lwip_wget, "boot image via network using HTTP protocol", "[loadAddress] [[hostIPaddr:]path and image name]" );
@@ -456,28 +445,8 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, }
#if defined(CONFIG_CMD_PING) -static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[])
-{
- if (argc < 2)
- return CMD_RET_USAGE;
- net_ping_ip = string_to_ip(argv[1]);
- if (net_ping_ip.s_addr == 0)
- return CMD_RET_USAGE;
- if (net_loop(PING) < 0) {
- printf("ping failed; host %s is not alive\n", argv[1]);
- return CMD_RET_FAILURE;
- }
- printf("host %s is alive\n", argv[1]);
- return CMD_RET_SUCCESS;
-}
- U_BOOT_CMD(
- ping, 2, 1, do_ping,
- ping, 2, 1, do_lwip_ping, "send ICMP ECHO_REQUEST to network host", "pingAddress" );
@@ -601,45 +570,8 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_DNS) -int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{
- if (argc == 1)
- return CMD_RET_USAGE;
- /*
- We should check for a valid hostname:
- Each label must be between 1 and 63 characters long
- the entire hostname has a maximum of 255 characters
- only the ASCII letters 'a' through 'z' (case-insensitive),
- the digits '0' through '9', and the hyphen
- cannot begin or end with a hyphen
- no other symbols, punctuation characters, or blank spaces are
- permitted
- but hey - this is a minimalist implmentation, so only check length
- and let the name server deal with things.
- */
- if (strlen(argv[1]) >= 255) {
- printf("dns error: hostname too long\n");
- return CMD_RET_FAILURE;
- }
- net_dns_resolve = argv[1];
- if (argc == 3)
- net_dns_env_var = argv[2];
- else
- net_dns_env_var = NULL;
- if (net_loop(DNS) < 0) {
- printf("dns lookup of %s failed, check setup\n", argv[1]);
- return CMD_RET_FAILURE;
- }
- return CMD_RET_SUCCESS;
-}
- U_BOOT_CMD(
- dns, 3, 1, do_dns,
- dns, 3, 1, do_lwip_dns, "lookup the IP of a hostname", "hostname [envvar]" );
diff --git a/cmd/pxe.c b/cmd/pxe.c index 677142520b..d44df428d2 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -8,6 +8,7 @@ #include <command.h> #include <fs.h> #include <net.h> +#include <net/lwip.h> #include <net6.h> #include <malloc.h>
@@ -29,21 +30,19 @@ const char *pxe_default_paths[] = { static int do_get_tftp(struct pxe_context *ctx, const char *file_path, char *file_addr, ulong *sizep) {
- char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
- ulong addr;
- char *end; int ret;
int num_args;
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
- addr = hextoul(file_addr, &end);
- if (ctx->use_ipv6) {
- tftp_argv[3] = USE_IP6_CMD_PARAM;
- num_args = 4;
- } else {
- num_args = 3;
- /* @todo: check and fix me, here */
Again, looks like LWIP doesn't support IPv6 addressing, we may want to fall back on existing TFTP implementation here.
}
- if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv))
- return -ENOENT;
ret = ulwip_tftp(addr, file_path);
if (ret)
return log_msg_ret("tftp", ret);
ret = pxe_get_file_size(sizep); if (ret)
diff --git a/include/net.h b/include/net.h index e254df7d7f..de7baeb121 100644 --- a/include/net.h +++ b/include/net.h @@ -54,8 +54,10 @@ struct in_addr { __be32 s_addr; };
+int do_lwip_dhcp(void);
- /**
- do_tftpb - Run the tftpboot command
- do_lwip_tftp - Run the tftpboot command
- @cmdtp: Command information for tftpboot
- @flag: Command flags (CMD_FLAG_...)
@@ -63,7 +65,7 @@ struct in_addr {
- @argv: List of arguments
- Return: result (see enum command_ret_t)
*/ -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
/**
- dhcp_run() - Run DHCP on the current ethernet device
@@ -514,7 +516,7 @@ extern int net_restart_wrap; /* Tried all network devices */ enum proto_t { BOOTP, RARP, ARP, TFTPGET, DHCP, DHCP6, PING, PING6, DNS, NFS, CDP, NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT_UDP, FASTBOOT_TCP,
- WOL, UDP, NCSI, WGET, RS
WOL, UDP, NCSI, WGET, RS, LWIP };
extern char net_boot_file_name[1024];/* Boot File name */
diff --git a/include/net/ulwip.h b/include/net/ulwip.h new file mode 100644 index 0000000000..8eac7aa130 --- /dev/null +++ b/include/net/ulwip.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */
+/**
- ulwip_init() - initialize lwIP network stack
- @return 0 if success, !0 if error
- */
+int ulwip_init(void);
+/**
- ulwip_enabled() - check if lwIP network stack was initialized
- @return 1 lwip initialized, 0 if not yet initialized
- */
+int ulwip_enabled(void);
+/**
- ulwip_in_loop() - lwIP controls packet net loop
- @return 1 lwIP owns packet loop, 0 lwip does not own packet loop
- */
+int ulwip_in_loop(void);
+/**
- ulwip_loop_set() - make loop to be used by lwIP
- Function is used to make lwIP control network pool.
- @loop: 1. Rx packets go to lwIP 2. Rx packets go to the original stack.
- */
+void ulwip_loop_set(int loop);
+/**
- ulwip_exit() - exit from lwIP with a return code
- Exit from lwIP application back to the U-Boot with specific error code.
- @err: Error code to return
- */
+void ulwip_exit(int err);
+/**
- ulwip_poll() - polling function to feed lwIP with ethernet packet
- Function takes network packet and passes it to lwIP network stack
- */
+void ulwip_poll(void);
+/**
- ulwip_app_get_err() - return error code from lwIP application
- @return error code
- */
+int ulwip_app_get_err(void);
+/**
- ulwip_loop() - enter to packet polling loop
- When lwIP application did it's initialization stage, then it needs to enter
- to packet polling loop to grab rx packets.
- Returns: 0 if success, !0 if error
- */
+int ulwip_loop(void);

Hi Sean,
On Tue, 3 Oct 2023 at 11:58, Sean Edmond seanedmond@linux.microsoft.com wrote:
On 2023-09-26 2:41 a.m., Maxim Uvarov wrote:
Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarovmaxim.uvarov@linaro.org
boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86 +++++---------------------------------------- cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index ae936c8daa..52399d627c 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -20,6 +20,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/lwip.h> +#include <net/ulwip.h> #include <pxe_utils.h> #include <linux/sizes.h>
@@ -319,9 +321,7 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
static int distro_efi_read_bootflow_net(struct bootflow *bflow) {
char file_addr[17], fname[256];
char *tftp_argv[] = {"tftp", file_addr, fname, NULL};
struct cmd_tbl cmdtp = {}; /* dummy */
char fname[256]; const char *addr_str, *fdt_addr_str; int ret, arch, size; ulong addr, fdt_addr;
@@ -368,7 +368,6 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!fdt_addr_str) return log_msg_ret("fdt", -EINVAL); fdt_addr = hextoul(fdt_addr_str, NULL);
sprintf(file_addr, "%lx", fdt_addr); /* We only allow the first prefix with PXE */ ret = distro_efi_get_fdt_name(fname, sizeof(fname), 0);
@@ -379,7 +378,16 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM);
if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) {
ret = ulwip_init();
if (ret)
return log_msg_ret("ulwip_init", ret);
ret = ulwip_tftp(fdt_addr, fname);
if (ret)
return log_msg_ret("ulwip_tftp", ret);
ret = ulwip_loop();
if (!ret) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else {
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 8d489a11aa..fc6aabaa18 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -21,6 +21,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/ulwip.h> +#include <net/lwip.h> #include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path, @@ -116,18 +118,21 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep) {
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
struct pxe_context *ctx = dev_get_priv(dev);
char file_addr[17]; ulong size; int ret;
sprintf(file_addr, "%lx", addr);
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
ret = ulwip_init();
if (ret)
return log_msg_ret("ulwip_init", ret);
ret = ulwip_tftp(addr, file_path);
if (ret)
return log_msg_ret("ulwip_tftp", ret);
ret = ulwip_loop();
if (ret)
return log_msg_ret("ulwip_loop", ret);
if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
return -ENOENT; ret = pxe_get_file_size(&size); if (ret) return log_msg_ret("tftp", ret);
diff --git a/cmd/net.c b/cmd/net.c index d407d8320a..dc5a114309 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -22,6 +22,7 @@ #include <net/udp.h> #include <net/sntp.h> #include <net/ncsi.h> +#include <net/lwip.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
@@ -40,19 +41,9 @@ U_BOOT_CMD( #endif
#ifdef CONFIG_CMD_TFTPBOOT -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{
int ret;
bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
ret = netboot_common(TFTPGET, cmdtp, argc, argv);
bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
return ret;
-}
- #if IS_ENABLED(CONFIG_IPV6) U_BOOT_CMD(
tftpboot, 4, 1, do_tftpb,
tftpboot, 4, 1, do_lwip_tftp,
It looks like LWIP doesn't support TFTP with IPv6 addressing. Perhaps we need to fall back onto the existing TFTP implementation until LWIP supports it?
Note, that currently, IPv6 TFTP is enabled using the "-ipv6" argument. The intention is that netboot_common() sees the argument and sets the "use_ip6" variable. It looks like the new implementation in do_lwip_tftp() doesn't re-use the argument parsing in netboot_common() and that it doesn't handle the addition of the "-ipv6" flag.
I support the addition of LWIP, but I'm concerned about how abrupt changes like this one will be for existing users. The underlying stack will change, with no easy way for the user to revert to the previous stack. Has there been any discussion about preserving the existing functionality, with an option to enable/disable LWIP stack?This would give the community time to transition/validate LWIP before deprecating the old u-boot networking stack.
IPv6 is news to me...and surprising.
Regards, Simon

On Wed, 4 Oct 2023 at 08:12, Simon Glass sjg@google.com wrote:
Hi Sean,
On Tue, 3 Oct 2023 at 11:58, Sean Edmond seanedmond@linux.microsoft.com wrote:
On 2023-09-26 2:41 a.m., Maxim Uvarov wrote:
Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarovmaxim.uvarov@linaro.org
boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86
+++++----------------------------------------
cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index ae936c8daa..52399d627c 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -20,6 +20,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/lwip.h> +#include <net/ulwip.h> #include <pxe_utils.h> #include <linux/sizes.h>
@@ -319,9 +321,7 @@ static int distro_efi_try_bootflow_files(struct
udevice *dev,
static int distro_efi_read_bootflow_net(struct bootflow *bflow) {
char file_addr[17], fname[256];
char *tftp_argv[] = {"tftp", file_addr, fname, NULL};
struct cmd_tbl cmdtp = {}; /* dummy */
char fname[256]; const char *addr_str, *fdt_addr_str; int ret, arch, size; ulong addr, fdt_addr;
@@ -368,7 +368,6 @@ static int distro_efi_read_bootflow_net(struct
bootflow *bflow)
if (!fdt_addr_str) return log_msg_ret("fdt", -EINVAL); fdt_addr = hextoul(fdt_addr_str, NULL);
sprintf(file_addr, "%lx", fdt_addr); /* We only allow the first prefix with PXE */ ret = distro_efi_get_fdt_name(fname, sizeof(fname), 0);
@@ -379,7 +378,16 @@ static int distro_efi_read_bootflow_net(struct
bootflow *bflow)
if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM);
if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) {
ret = ulwip_init();
if (ret)
return log_msg_ret("ulwip_init", ret);
ret = ulwip_tftp(fdt_addr, fname);
if (ret)
return log_msg_ret("ulwip_tftp", ret);
ret = ulwip_loop();
if (!ret) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else {
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 8d489a11aa..fc6aabaa18 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -21,6 +21,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/ulwip.h> +#include <net/lwip.h> #include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char
*file_path,
@@ -116,18 +118,21 @@ static int extlinux_pxe_read_file(struct udevice
*dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
{
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
struct pxe_context *ctx = dev_get_priv(dev);
char file_addr[17]; ulong size; int ret;
sprintf(file_addr, "%lx", addr);
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
ret = ulwip_init();
if (ret)
return log_msg_ret("ulwip_init", ret);
ret = ulwip_tftp(addr, file_path);
if (ret)
return log_msg_ret("ulwip_tftp", ret);
ret = ulwip_loop();
if (ret)
return log_msg_ret("ulwip_loop", ret);
if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
return -ENOENT; ret = pxe_get_file_size(&size); if (ret) return log_msg_ret("tftp", ret);
diff --git a/cmd/net.c b/cmd/net.c index d407d8320a..dc5a114309 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -22,6 +22,7 @@ #include <net/udp.h> #include <net/sntp.h> #include <net/ncsi.h> +#include <net/lwip.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char
- const []);
@@ -40,19 +41,9 @@ U_BOOT_CMD( #endif
#ifdef CONFIG_CMD_TFTPBOOT -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const
argv[])
-{
int ret;
bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
ret = netboot_common(TFTPGET, cmdtp, argc, argv);
bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
return ret;
-}
- #if IS_ENABLED(CONFIG_IPV6) U_BOOT_CMD(
tftpboot, 4, 1, do_tftpb,
tftpboot, 4, 1, do_lwip_tftp,
It looks like LWIP doesn't support TFTP with IPv6 addressing. Perhaps we need to fall back onto the existing TFTP implementation until LWIP supports it?
Note, that currently, IPv6 TFTP is enabled using the "-ipv6" argument. The intention is that netboot_common() sees the argument and sets the "use_ip6" variable. It looks like the new implementation in do_lwip_tftp() doesn't re-use the argument parsing in netboot_common() and that it doesn't handle the addition of the "-ipv6" flag.
I support the addition of LWIP, but I'm concerned about how abrupt changes like this one will be for existing users. The underlying stack will change, with no easy way for the user to revert to the previous stack. Has there been any discussion about preserving the existing functionality, with an option to enable/disable LWIP stack?This would give the community time to transition/validate LWIP before deprecating the old u-boot networking stack.
IPv6 is news to me...and surprising.
Regards, Simon
For this time I enabled only ipv4 in lwip U-boot implementation and planned to keep the original ping6 dhcp6 tftp6 on first submission. After the first ipv4 lwip patches can be merged I planned to work on ipv6 support. I think it will require more time for the test environment to be set up, then actually enabling ipv6 in the configuration header. lwIP can work in dual stack mode. But I'm not sure that example applications support ipv6 at this time.
BR, Maxim.

Am 4. Oktober 2023 10:29:54 MESZ schrieb Maxim Uvarov maxim.uvarov@linaro.org:
On Wed, 4 Oct 2023 at 08:12, Simon Glass sjg@google.com wrote:
Hi Sean,
On Tue, 3 Oct 2023 at 11:58, Sean Edmond seanedmond@linux.microsoft.com wrote:
On 2023-09-26 2:41 a.m., Maxim Uvarov wrote:
Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarovmaxim.uvarov@linaro.org
boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86
+++++----------------------------------------
cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index ae936c8daa..52399d627c 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -20,6 +20,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/lwip.h> +#include <net/ulwip.h> #include <pxe_utils.h> #include <linux/sizes.h>
@@ -319,9 +321,7 @@ static int distro_efi_try_bootflow_files(struct
udevice *dev,
static int distro_efi_read_bootflow_net(struct bootflow *bflow) {
char file_addr[17], fname[256];
char *tftp_argv[] = {"tftp", file_addr, fname, NULL};
struct cmd_tbl cmdtp = {}; /* dummy */
char fname[256]; const char *addr_str, *fdt_addr_str; int ret, arch, size; ulong addr, fdt_addr;
@@ -368,7 +368,6 @@ static int distro_efi_read_bootflow_net(struct
bootflow *bflow)
if (!fdt_addr_str) return log_msg_ret("fdt", -EINVAL); fdt_addr = hextoul(fdt_addr_str, NULL);
sprintf(file_addr, "%lx", fdt_addr); /* We only allow the first prefix with PXE */ ret = distro_efi_get_fdt_name(fname, sizeof(fname), 0);
@@ -379,7 +378,16 @@ static int distro_efi_read_bootflow_net(struct
bootflow *bflow)
if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM);
if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) {
ret = ulwip_init();
if (ret)
return log_msg_ret("ulwip_init", ret);
ret = ulwip_tftp(fdt_addr, fname);
if (ret)
return log_msg_ret("ulwip_tftp", ret);
ret = ulwip_loop();
if (!ret) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else {
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 8d489a11aa..fc6aabaa18 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -21,6 +21,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/ulwip.h> +#include <net/lwip.h> #include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char
*file_path,
@@ -116,18 +118,21 @@ static int extlinux_pxe_read_file(struct udevice
*dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
{
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
struct pxe_context *ctx = dev_get_priv(dev);
char file_addr[17]; ulong size; int ret;
sprintf(file_addr, "%lx", addr);
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
ret = ulwip_init();
if (ret)
return log_msg_ret("ulwip_init", ret);
ret = ulwip_tftp(addr, file_path);
if (ret)
return log_msg_ret("ulwip_tftp", ret);
ret = ulwip_loop();
if (ret)
return log_msg_ret("ulwip_loop", ret);
if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
return -ENOENT; ret = pxe_get_file_size(&size); if (ret) return log_msg_ret("tftp", ret);
diff --git a/cmd/net.c b/cmd/net.c index d407d8320a..dc5a114309 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -22,6 +22,7 @@ #include <net/udp.h> #include <net/sntp.h> #include <net/ncsi.h> +#include <net/lwip.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char
- const []);
@@ -40,19 +41,9 @@ U_BOOT_CMD( #endif
#ifdef CONFIG_CMD_TFTPBOOT -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const
argv[])
-{
int ret;
bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
ret = netboot_common(TFTPGET, cmdtp, argc, argv);
bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
return ret;
-}
- #if IS_ENABLED(CONFIG_IPV6) U_BOOT_CMD(
tftpboot, 4, 1, do_tftpb,
tftpboot, 4, 1, do_lwip_tftp,
It looks like LWIP doesn't support TFTP with IPv6 addressing. Perhaps we need to fall back onto the existing TFTP implementation until LWIP supports it?
Note, that currently, IPv6 TFTP is enabled using the "-ipv6" argument. The intention is that netboot_common() sees the argument and sets the "use_ip6" variable. It looks like the new implementation in do_lwip_tftp() doesn't re-use the argument parsing in netboot_common() and that it doesn't handle the addition of the "-ipv6" flag.
I support the addition of LWIP, but I'm concerned about how abrupt changes like this one will be for existing users. The underlying stack will change, with no easy way for the user to revert to the previous stack. Has there been any discussion about preserving the existing functionality, with an option to enable/disable LWIP stack?This would give the community time to transition/validate LWIP before deprecating the old u-boot networking stack.
IPv6 is news to me...and surprising.
Regards, Simon
For this time I enabled only ipv4 in lwip U-boot implementation and planned to keep the original ping6 dhcp6 tftp6 on first submission. After the first ipv4 lwip patches can be merged I planned to work on ipv6 support. I think it will require more time for the test environment to be set up, then actually enabling ipv6 in the configuration header. lwIP can work in dual stack mode. But I'm not sure that example applications support ipv6 at this time.
All lwIP example apps building on UDP or TCP should support IPv6 just fine. Ping is of course a special case in that it uses a different protocol for IPv6 and IPv4 and no one has bothered yet to port it to IPv6. That's the reason it remained in contrib/apps instead of src/apps.
Aside from DNS, we do not have built in a fallback mechanism from IPv6 to IPv4 or the other way around, so that would have to be coded by the application (U-Boot command in this case).
Regards, Simon

current net.h has ethernet and protocol definitions. Protocol definitions overlap with lwIP protocol definitions and net.h can not be included from lwIP code. Splitting on logical blocks makes that work.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net.h | 189 +-------------------------------------------- include/net/arp.h | 7 ++ include/net/eth.h | 190 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 185 deletions(-) create mode 100644 include/net/arp.h create mode 100644 include/net/eth.h
diff --git a/include/net.h b/include/net.h index de7baeb121..780c51fab9 100644 --- a/include/net.h +++ b/include/net.h @@ -20,6 +20,7 @@ #include <time.h> #include <linux/if_ether.h> #include <rand.h> +#include <net/arp.h>
struct bd_info; struct cmd_tbl; @@ -30,25 +31,6 @@ struct udevice; #define DEBUG_NET_PKT 0 /* Packets on info on the network at large */ #define DEBUG_INT_STATE 0 /* Internal network state changes */
-/* - * The number of receive packet buffers, and the required packet buffer - * alignment in memory. - * - */ -#define PKTBUFSRX CONFIG_SYS_RX_ETH_BUFFER -#define PKTALIGN ARCH_DMA_MINALIGN - -/* Number of packets processed together */ -#define ETH_PACKETS_BATCH_RECV 32 - -/* ARP hardware address length */ -#define ARP_HLEN 6 -/* - * The size of a MAC address in string form, each digit requires two chars - * and five separator characters to form '00:00:00:00:00:00'. - */ -#define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1) - /* IPv4 addresses are always 32 bits in size */ struct in_addr { __be32 s_addr; @@ -112,150 +94,7 @@ typedef void rxhand_icmp_f(unsigned type, unsigned code, unsigned dport, */ typedef void thand_f(void);
-enum eth_state_t { - ETH_STATE_INIT, - ETH_STATE_PASSIVE, - ETH_STATE_ACTIVE -}; - -/** - * struct eth_pdata - Platform data for Ethernet MAC controllers - * - * @iobase: The base address of the hardware registers - * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env - * @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_... - * @max_speed: Maximum speed of Ethernet connection supported by MAC - * @priv_pdata: device specific plat - */ -struct eth_pdata { - phys_addr_t iobase; - unsigned char enetaddr[ARP_HLEN]; - int phy_interface; - int max_speed; - void *priv_pdata; -}; - -enum eth_recv_flags { - /* - * Check hardware device for new packets (otherwise only return those - * which are already in the memory buffer ready to process) - */ - ETH_RECV_CHECK_DEVICE = 1 << 0, -}; - -/** - * struct eth_ops - functions of Ethernet MAC controllers - * - * start: Prepare the hardware to send and receive packets - * send: Send the bytes passed in "packet" as a packet on the wire - * recv: Check if the hardware received a packet. If so, set the pointer to the - * packet buffer in the packetp parameter. If not, return an error or 0 to - * indicate that the hardware receive FIFO is empty. If 0 is returned, the - * network stack will not process the empty packet, but free_pkt() will be - * called if supplied - * free_pkt: Give the driver an opportunity to manage its packet buffer memory - * when the network stack is finished processing it. This will only be - * called when no error was returned from recv - optional - * stop: Stop the hardware from looking for packets - may be called even if - * state == PASSIVE - * mcast: Join or leave a multicast group (for TFTP) - optional - * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux - * on some platforms like ARM). This function expects the - * eth_pdata::enetaddr field to be populated. The method can - * return -ENOSYS to indicate that this is not implemented for - this hardware - optional. - * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a - * ROM on the board. This is how the driver should expose it - * to the network stack. This function should fill in the - * eth_pdata::enetaddr field - optional - * set_promisc: Enable or Disable promiscuous mode - * get_sset_count: Number of statistics counters - * get_string: Names of the statistic counters - * get_stats: The values of the statistic counters - */ -struct eth_ops { - int (*start)(struct udevice *dev); - int (*send)(struct udevice *dev, void *packet, int length); - int (*recv)(struct udevice *dev, int flags, uchar **packetp); - int (*free_pkt)(struct udevice *dev, uchar *packet, int length); - void (*stop)(struct udevice *dev); - int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); - int (*write_hwaddr)(struct udevice *dev); - int (*read_rom_hwaddr)(struct udevice *dev); - int (*set_promisc)(struct udevice *dev, bool enable); - int (*get_sset_count)(struct udevice *dev); - void (*get_strings)(struct udevice *dev, u8 *data); - void (*get_stats)(struct udevice *dev, u64 *data); -}; - -#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops) - -struct udevice *eth_get_dev(void); /* get the current device */ -/* - * The devname can be either an exact name given by the driver or device tree - * or it can be an alias of the form "eth%d" - */ -struct udevice *eth_get_dev_by_name(const char *devname); -unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ - -/* Used only when NetConsole is enabled */ -int eth_is_active(struct udevice *dev); /* Test device for active state */ -int eth_init_state_only(void); /* Set active state */ -void eth_halt_state_only(void); /* Set passive state */ - -int eth_initialize(void); /* Initialize network subsystem */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */ - -int eth_get_dev_index(void); /* get the device index */ - -/** - * eth_env_set_enetaddr_by_index() - set the MAC address environment variable - * - * This sets up an environment variable with the given MAC address (@enetaddr). - * The environment variable to be set is defined by <@base_name><@index>addr. - * If @index is 0 it is omitted. For common Ethernet this means ethaddr, - * eth1addr, etc. - * - * @base_name: Base name for variable, typically "eth" - * @index: Index of interface being updated (>=0) - * @enetaddr: Pointer to MAC address to put into the variable - * Return: 0 if OK, other value on error - */ -int eth_env_set_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); - - -/* - * Initialize USB ethernet device with CONFIG_DM_ETH - * Returns: - * 0 is success, non-zero is error status. - */ -int usb_ether_init(void); - -/* - * Get the hardware address for an ethernet interface . - * Args: - * base_name - base name for device (normally "eth") - * index - device index number (0 for first) - * enetaddr - returns 6 byte hardware address - * Returns: - * Return true if the address is valid. - */ -int eth_env_get_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); - -int eth_init(void); /* Initialize the device */ -int eth_send(void *packet, int length); /* Send a packet */ - -#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) -int eth_receive(void *packet, int length); /* Receive a packet*/ -extern void (*push_packet)(void *packet, int length); -#endif -int eth_rx(void); /* Check for received packets */ -void eth_halt(void); /* stop SCC */ -const char *eth_get_name(void); /* get name of current device */ -int eth_mcast_join(struct in_addr mcast_addr, int join); +#include <net/eth.h>
/**********************************************************************/ /* @@ -495,16 +334,6 @@ extern char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN]; /* Our root path */ /* Indicates whether the pxe path prefix / config file was specified in dhcp option */ extern char *pxelinux_configfile; /** END OF BOOTP EXTENTIONS **/ -extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet address */ -extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet address */ -extern struct in_addr net_ip; /* Our IP addr (0 = unknown) */ -extern struct in_addr net_server_ip; /* Server IP addr (0 = unknown) */ -extern uchar *net_tx_packet; /* THE transmit packet */ -extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ -extern uchar *net_rx_packet; /* Current receive packet */ -extern int net_rx_packet_len; /* Current rx packet length */ -extern const u8 net_bcast_ethaddr[ARP_HLEN]; /* Ethernet broadcast address */ -extern const u8 net_null_ethaddr[ARP_HLEN];
#define VLAN_NONE 4095 /* untagged */ #define VLAN_IDMASK 0x0fff /* mask of valid vlan id */ @@ -557,6 +386,8 @@ extern struct in_addr net_ntp_server; /* the ip address to NTP */ extern int net_ntp_time_offset; /* offset time from UTC */ #endif
+int eth_mcast_join(struct in_addr mcast_addr, int join); + /* Initialize the network adapter */ int net_init(void); int net_loop(enum proto_t); @@ -827,18 +658,6 @@ static inline void net_random_ethaddr(uchar *addr) addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ }
-/** - * string_to_enetaddr() - Parse a MAC address - * - * Convert a string MAC address - * - * Implemented in lib/net_utils.c (built unconditionally) - * - * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit - * hex value - * @enetaddr: Place to put MAC address (6 bytes) - */ -void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
/* Convert an IP address to a string */ void ip_to_string(struct in_addr x, char *s); diff --git a/include/net/arp.h b/include/net/arp.h new file mode 100644 index 0000000000..f614f0ef78 --- /dev/null +++ b/include/net/arp.h @@ -0,0 +1,7 @@ +/* ARP hardware address length */ +#define ARP_HLEN 6 +/* + * The size of a MAC address in string form, each digit requires two chars + * and five separator characters to form '00:00:00:00:00:00'. + */ +#define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1) diff --git a/include/net/eth.h b/include/net/eth.h new file mode 100644 index 0000000000..17552bca81 --- /dev/null +++ b/include/net/eth.h @@ -0,0 +1,190 @@ +#include <net/arp.h> + +struct udevice; + +enum eth_state_t { + ETH_STATE_INIT, + ETH_STATE_PASSIVE, + ETH_STATE_ACTIVE +}; + +/** + * struct eth_pdata - Platform data for Ethernet MAC controllers + * + * @iobase: The base address of the hardware registers + * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env + * @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_... + * @max_speed: Maximum speed of Ethernet connection supported by MAC + * @priv_pdata: device specific plat + */ +struct eth_pdata { + phys_addr_t iobase; + unsigned char enetaddr[ARP_HLEN]; + int phy_interface; + int max_speed; + void *priv_pdata; +}; + +enum eth_recv_flags { + /* + * Check hardware device for new packets (otherwise only return those + * which are already in the memory buffer ready to process) + */ + ETH_RECV_CHECK_DEVICE = 1 << 0, +}; + +/** + * struct eth_ops - functions of Ethernet MAC controllers + * + * start: Prepare the hardware to send and receive packets + * send: Send the bytes passed in "packet" as a packet on the wire + * recv: Check if the hardware received a packet. If so, set the pointer to the + * packet buffer in the packetp parameter. If not, return an error or 0 to + * indicate that the hardware receive FIFO is empty. If 0 is returned, the + * network stack will not process the empty packet, but free_pkt() will be + * called if supplied + * free_pkt: Give the driver an opportunity to manage its packet buffer memory + * when the network stack is finished processing it. This will only be + * called when no error was returned from recv - optional + * stop: Stop the hardware from looking for packets - may be called even if + * state == PASSIVE + * mcast: Join or leave a multicast group (for TFTP) - optional + * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux + * on some platforms like ARM). This function expects the + * eth_pdata::enetaddr field to be populated. The method can + * return -ENOSYS to indicate that this is not implemented for + this hardware - optional. + * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a + * ROM on the board. This is how the driver should expose it + * to the network stack. This function should fill in the + * eth_pdata::enetaddr field - optional + * set_promisc: Enable or Disable promiscuous mode + * get_sset_count: Number of statistics counters + * get_string: Names of the statistic counters + * get_stats: The values of the statistic counters + */ +struct eth_ops { + int (*start)(struct udevice *dev); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev, int flags, uchar **packetp); + int (*free_pkt)(struct udevice *dev, uchar *packet, int length); + void (*stop)(struct udevice *dev); + int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); + int (*write_hwaddr)(struct udevice *dev); + int (*read_rom_hwaddr)(struct udevice *dev); + int (*set_promisc)(struct udevice *dev, bool enable); + int (*get_sset_count)(struct udevice *dev); + void (*get_strings)(struct udevice *dev, u8 *data); + void (*get_stats)(struct udevice *dev, u64 *data); +}; + +#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops) + +struct udevice *eth_get_dev(void); /* get the current device */ +/* + * The devname can be either an exact name given by the driver or device tree + * or it can be an alias of the form "eth%d" + */ +struct udevice *eth_get_dev_by_name(const char *devname); +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ + +/* Used only when NetConsole is enabled */ +int eth_is_active(struct udevice *dev); /* Test device for active state */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ + +int eth_initialize(void); /* Initialize network subsystem */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + +int eth_get_dev_index(void); /* get the device index */ + +/** + * eth_env_set_enetaddr_by_index() - set the MAC address environment variable + * + * This sets up an environment variable with the given MAC address (@enetaddr). + * The environment variable to be set is defined by <@base_name><@index>addr. + * If @index is 0 it is omitted. For common Ethernet this means ethaddr, + * eth1addr, etc. + * + * @base_name: Base name for variable, typically "eth" + * @index: Index of interface being updated (>=0) + * @enetaddr: Pointer to MAC address to put into the variable + * Return: 0 if OK, other value on error + */ +int eth_env_set_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr); + + +/* + * Initialize USB ethernet device with CONFIG_DM_ETH + * Returns: + * 0 is success, non-zero is error status. + */ +int usb_ether_init(void); + +/* + * Get the hardware address for an ethernet interface . + * Args: + * base_name - base name for device (normally "eth") + * index - device index number (0 for first) + * enetaddr - returns 6 byte hardware address + * Returns: + * Return true if the address is valid. + */ +int eth_env_get_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr); + +int eth_init(void); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */ + +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) +int eth_receive(void *packet, int length); /* Receive a packet*/ +extern void (*push_packet)(void *packet, int length); +#endif +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +const char *eth_get_name(void); /* get name of current device */ + +/* + * The number of receive packet buffers, and the required packet buffer + * alignment in memory. + * + */ +#define PKTBUFSRX CONFIG_SYS_RX_ETH_BUFFER +#define PKTALIGN ARCH_DMA_MINALIGN + +/* Number of packets processed together */ +#define ETH_PACKETS_BATCH_RECV 32 + +extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet address */ +extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet address */ +extern struct in_addr net_ip; /* Our IP addr (0 = unknown) */ +extern struct in_addr net_server_ip; /* Server IP addr (0 = unknown) */ +extern uchar *net_tx_packet; /* THE transmit packet */ +extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ +extern uchar *net_rx_packet; /* Current receive packet */ +extern int net_rx_packet_len; /* Current rx packet length */ +extern const u8 net_bcast_ethaddr[ARP_HLEN]; /* Ethernet broadcast address */ +extern const u8 net_null_ethaddr[ARP_HLEN]; + +/** + * string_to_enetaddr() - Parse a MAC address + * + * Convert a string MAC address + * + * Implemented in lib/net_utils.c (built unconditionally) + * + * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit + * hex value + * @enetaddr: Place to put MAC address (6 bytes) + */ +void string_to_enetaddr(const char *addr, uint8_t *enetaddr); + +typedef struct ulwip { + bool loop; + int err; + bool init_done; +} ulwip; + +struct ulwip *eth_lwip_priv(struct udevice *current);

On Tue, 26 Sept 2023 at 03:46, Maxim Uvarov maxim.uvarov@linaro.org wrote:
current net.h has ethernet and protocol definitions. Protocol definitions overlap with lwIP protocol definitions and net.h can not be included from lwIP code. Splitting on logical blocks makes that work.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
include/net.h | 189 +-------------------------------------------- include/net/arp.h | 7 ++ include/net/eth.h | 190 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 185 deletions(-) create mode 100644 include/net/arp.h create mode 100644 include/net/eth.h
Reviewed-by: Simon Glass sjg@chromium.org
Please void typedef
[..]
-/**
- struct eth_ops - functions of Ethernet MAC controllers
- start: Prepare the hardware to send and receive packets
- send: Send the bytes passed in "packet" as a packet on the wire
- recv: Check if the hardware received a packet. If so, set the pointer to the
packet buffer in the packetp parameter. If not, return an error or 0 to
indicate that the hardware receive FIFO is empty. If 0 is returned, the
network stack will not process the empty packet, but free_pkt() will be
called if supplied
- free_pkt: Give the driver an opportunity to manage its packet buffer memory
when the network stack is finished processing it. This will only be
called when no error was returned from recv - optional
- stop: Stop the hardware from looking for packets - may be called even if
state == PASSIVE
- mcast: Join or leave a multicast group (for TFTP) - optional
- write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux
on some platforms like ARM). This function expects the
eth_pdata::enetaddr field to be populated. The method can
return -ENOSYS to indicate that this is not implemented for
this hardware - optional.
- read_rom_hwaddr: Some devices have a backup of the MAC address stored in a
ROM on the board. This is how the driver should expose it
to the network stack. This function should fill in the
eth_pdata::enetaddr field - optional
- set_promisc: Enable or Disable promiscuous mode
- get_sset_count: Number of statistics counters
- get_string: Names of the statistic counters
- get_stats: The values of the statistic counters
- */
-struct eth_ops {
int (*start)(struct udevice *dev);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev, int flags, uchar **packetp);
int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
void (*stop)(struct udevice *dev);
int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
int (*write_hwaddr)(struct udevice *dev);
int (*read_rom_hwaddr)(struct udevice *dev);
int (*set_promisc)(struct udevice *dev, bool enable);
int (*get_sset_count)(struct udevice *dev);
void (*get_strings)(struct udevice *dev, u8 *data);
void (*get_stats)(struct udevice *dev, u64 *data);
-};
-#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
-struct udevice *eth_get_dev(void); /* get the current device */ -/*
- The devname can be either an exact name given by the driver or device tree
- or it can be an alias of the form "eth%d"
- */
-struct udevice *eth_get_dev_by_name(const char *devname); -unsigned char *eth_get_ethaddr(void); /* get the current device MAC */
-/* Used only when NetConsole is enabled */ -int eth_is_active(struct udevice *dev); /* Test device for active state */ -int eth_init_state_only(void); /* Set active state */ -void eth_halt_state_only(void); /* Set passive state */
-int eth_initialize(void); /* Initialize network subsystem */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */
-int eth_get_dev_index(void); /* get the device index */
-/**
- eth_env_set_enetaddr_by_index() - set the MAC address environment variable
- This sets up an environment variable with the given MAC address (@enetaddr).
- The environment variable to be set is defined by <@base_name><@index>addr.
- If @index is 0 it is omitted. For common Ethernet this means ethaddr,
- eth1addr, etc.
- @base_name: Base name for variable, typically "eth"
- @index: Index of interface being updated (>=0)
- @enetaddr: Pointer to MAC address to put into the variable
- Return: 0 if OK, other value on error
- */
-int eth_env_set_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr);
-/*
- Initialize USB ethernet device with CONFIG_DM_ETH
- Returns:
0 is success, non-zero is error status.
- */
-int usb_ether_init(void);
-/*
- Get the hardware address for an ethernet interface .
- Args:
base_name - base name for device (normally "eth")
index - device index number (0 for first)
enetaddr - returns 6 byte hardware address
- Returns:
Return true if the address is valid.
- */
-int eth_env_get_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr);
-int eth_init(void); /* Initialize the device */ -int eth_send(void *packet, int length); /* Send a packet */
-#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) -int eth_receive(void *packet, int length); /* Receive a packet*/ -extern void (*push_packet)(void *packet, int length); -#endif -int eth_rx(void); /* Check for received packets */ -void eth_halt(void); /* stop SCC */ -const char *eth_get_name(void); /* get name of current device */ -int eth_mcast_join(struct in_addr mcast_addr, int join); +#include <net/eth.h>
/**********************************************************************/ /* @@ -495,16 +334,6 @@ extern char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN]; /* Our root path */ /* Indicates whether the pxe path prefix / config file was specified in dhcp option */ extern char *pxelinux_configfile; /** END OF BOOTP EXTENTIONS **/ -extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet address */ -extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet address */ -extern struct in_addr net_ip; /* Our IP addr (0 = unknown) */ -extern struct in_addr net_server_ip; /* Server IP addr (0 = unknown) */ -extern uchar *net_tx_packet; /* THE transmit packet */ -extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ -extern uchar *net_rx_packet; /* Current receive packet */ -extern int net_rx_packet_len; /* Current rx packet length */ -extern const u8 net_bcast_ethaddr[ARP_HLEN]; /* Ethernet broadcast address */ -extern const u8 net_null_ethaddr[ARP_HLEN];
#define VLAN_NONE 4095 /* untagged */ #define VLAN_IDMASK 0x0fff /* mask of valid vlan id */ @@ -557,6 +386,8 @@ extern struct in_addr net_ntp_server; /* the ip address to NTP */ extern int net_ntp_time_offset; /* offset time from UTC */ #endif
+int eth_mcast_join(struct in_addr mcast_addr, int join);
/* Initialize the network adapter */ int net_init(void); int net_loop(enum proto_t); @@ -827,18 +658,6 @@ static inline void net_random_ethaddr(uchar *addr) addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ }
-/**
- string_to_enetaddr() - Parse a MAC address
- Convert a string MAC address
- Implemented in lib/net_utils.c (built unconditionally)
- @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit
hex value
- @enetaddr: Place to put MAC address (6 bytes)
- */
-void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
/* Convert an IP address to a string */ void ip_to_string(struct in_addr x, char *s); diff --git a/include/net/arp.h b/include/net/arp.h new file mode 100644 index 0000000000..f614f0ef78 --- /dev/null +++ b/include/net/arp.h @@ -0,0 +1,7 @@ +/* ARP hardware address length */ +#define ARP_HLEN 6 +/*
- The size of a MAC address in string form, each digit requires two chars
- and five separator characters to form '00:00:00:00:00:00'.
- */
+#define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1) diff --git a/include/net/eth.h b/include/net/eth.h new file mode 100644 index 0000000000..17552bca81 --- /dev/null +++ b/include/net/eth.h @@ -0,0 +1,190 @@ +#include <net/arp.h>
+struct udevice;
+enum eth_state_t {
ETH_STATE_INIT,
ETH_STATE_PASSIVE,
ETH_STATE_ACTIVE
+};
+/**
- struct eth_pdata - Platform data for Ethernet MAC controllers
- @iobase: The base address of the hardware registers
- @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env
- @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_...
- @max_speed: Maximum speed of Ethernet connection supported by MAC
- @priv_pdata: device specific plat
- */
+struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[ARP_HLEN];
int phy_interface;
int max_speed;
void *priv_pdata;
+};
+enum eth_recv_flags {
/*
* Check hardware device for new packets (otherwise only return those
* which are already in the memory buffer ready to process)
*/
ETH_RECV_CHECK_DEVICE = 1 << 0,
+};
+/**
- struct eth_ops - functions of Ethernet MAC controllers
- start: Prepare the hardware to send and receive packets
- send: Send the bytes passed in "packet" as a packet on the wire
- recv: Check if the hardware received a packet. If so, set the pointer to the
packet buffer in the packetp parameter. If not, return an error or 0 to
indicate that the hardware receive FIFO is empty. If 0 is returned, the
network stack will not process the empty packet, but free_pkt() will be
called if supplied
- free_pkt: Give the driver an opportunity to manage its packet buffer memory
when the network stack is finished processing it. This will only be
called when no error was returned from recv - optional
- stop: Stop the hardware from looking for packets - may be called even if
state == PASSIVE
- mcast: Join or leave a multicast group (for TFTP) - optional
- write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux
on some platforms like ARM). This function expects the
eth_pdata::enetaddr field to be populated. The method can
return -ENOSYS to indicate that this is not implemented for
this hardware - optional.
- read_rom_hwaddr: Some devices have a backup of the MAC address stored in a
ROM on the board. This is how the driver should expose it
to the network stack. This function should fill in the
eth_pdata::enetaddr field - optional
- set_promisc: Enable or Disable promiscuous mode
- get_sset_count: Number of statistics counters
- get_string: Names of the statistic counters
- get_stats: The values of the statistic counters
- */
+struct eth_ops {
int (*start)(struct udevice *dev);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev, int flags, uchar **packetp);
int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
void (*stop)(struct udevice *dev);
int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
int (*write_hwaddr)(struct udevice *dev);
int (*read_rom_hwaddr)(struct udevice *dev);
int (*set_promisc)(struct udevice *dev, bool enable);
int (*get_sset_count)(struct udevice *dev);
void (*get_strings)(struct udevice *dev, u8 *data);
void (*get_stats)(struct udevice *dev, u64 *data);
Please add full comments to each method
+};
+#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
+struct udevice *eth_get_dev(void); /* get the current device */ +/*
- The devname can be either an exact name given by the driver or device tree
- or it can be an alias of the form "eth%d"
- */
+struct udevice *eth_get_dev_by_name(const char *devname); +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */
+/* Used only when NetConsole is enabled */ +int eth_is_active(struct udevice *dev); /* Test device for active state */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */
+int eth_initialize(void); /* Initialize network subsystem */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */
+int eth_get_dev_index(void); /* get the device index */
need real comments on these functions
+/**
- eth_env_set_enetaddr_by_index() - set the MAC address environment variable
- This sets up an environment variable with the given MAC address (@enetaddr).
- The environment variable to be set is defined by <@base_name><@index>addr.
- If @index is 0 it is omitted. For common Ethernet this means ethaddr,
- eth1addr, etc.
- @base_name: Base name for variable, typically "eth"
- @index: Index of interface being updated (>=0)
- @enetaddr: Pointer to MAC address to put into the variable
- Return: 0 if OK, other value on error
- */
+int eth_env_set_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr);
+/*
- Initialize USB ethernet device with CONFIG_DM_ETH
- Returns:
0 is success, non-zero is error status.
- */
+int usb_ether_init(void);
+/*
- Get the hardware address for an ethernet interface .
- Args:
base_name - base name for device (normally "eth")
index - device index number (0 for first)
enetaddr - returns 6 byte hardware address
- Returns:
Return true if the address is valid.
- */
+int eth_env_get_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr);
+int eth_init(void); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) +int eth_receive(void *packet, int length); /* Receive a packet*/ +extern void (*push_packet)(void *packet, int length); +#endif +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +const char *eth_get_name(void); /* get name of current device */
+/*
The number of receive packet buffers, and the required packet buffer
alignment in memory.
- */
+#define PKTBUFSRX CONFIG_SYS_RX_ETH_BUFFER +#define PKTALIGN ARCH_DMA_MINALIGN
+/* Number of packets processed together */ +#define ETH_PACKETS_BATCH_RECV 32
+extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet address */ +extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet address */ +extern struct in_addr net_ip; /* Our IP addr (0 = unknown) */ +extern struct in_addr net_server_ip; /* Server IP addr (0 = unknown) */ +extern uchar *net_tx_packet; /* THE transmit packet */ +extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ +extern uchar *net_rx_packet; /* Current receive packet */ +extern int net_rx_packet_len; /* Current rx packet length */ +extern const u8 net_bcast_ethaddr[ARP_HLEN]; /* Ethernet broadcast address */ +extern const u8 net_null_ethaddr[ARP_HLEN];
+/**
- string_to_enetaddr() - Parse a MAC address
- Convert a string MAC address
- Implemented in lib/net_utils.c (built unconditionally)
- @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit
hex value
- @enetaddr: Place to put MAC address (6 bytes)
- */
+void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
+typedef struct ulwip {
bool loop;
int err;
bool init_done;
+} ulwip;
+struct ulwip *eth_lwip_priv(struct udevice *current);
2.30.2
Regards, Simon
participants (6)
-
Maxim Uvarov
-
Peter Robinson
-
Sean Edmond
-
Simon Glass
-
Simon Goldschmidt
-
Tom Rini