1# SPDX-License-Identifier: GPL-2.0
2# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3
4# Test various network-related functionality, such as the dhcp, ping, and
5# tftpboot commands.
6
7import pytest
8import u_boot_utils
9
10"""
11Note: This test relies on boardenv_* containing configuration values to define
12which network environment is available for testing. Without this, this test
13will be automatically skipped.
14
15For example:
16
17# Boolean indicating whether the Ethernet device is attached to USB, and hence
18# USB enumeration needs to be performed prior to network tests.
19# This variable may be omitted if its value is False.
20env__net_uses_usb = False
21
22# Boolean indicating whether the Ethernet device is attached to PCI, and hence
23# PCI enumeration needs to be performed prior to network tests.
24# This variable may be omitted if its value is False.
25env__net_uses_pci = True
26
27# True if a DHCP server is attached to the network, and should be tested.
28# If DHCP testing is not possible or desired, this variable may be omitted or
29# set to False.
30env__net_dhcp_server = True
31
32# True if a DHCPv6 server is attached to the network, and should be tested.
33# If DHCPv6 testing is not possible or desired, this variable may be omitted or
34# set to False.
35env__net_dhcp6_server = True
36
37# A list of environment variables that should be set in order to configure a
38# static IP. If solely relying on DHCP, this variable may be omitted or set to
39# an empty list.
40env__net_static_env_vars = [
41    ('ipaddr', '10.0.0.100'),
42    ('netmask', '255.255.255.0'),
43    ('serverip', '10.0.0.1'),
44]
45
46# Details regarding a file that may be read from a TFTP server. This variable
47# may be omitted or set to None if TFTP testing is not possible or desired.
48env__net_tftp_readable_file = {
49    'fn': 'ubtest-readable.bin',
50    'addr': 0x10000000,
51    'size': 5058624,
52    'crc32': 'c2244b26',
53}
54
55# Details regarding a file that may be read from a NFS server. This variable
56# may be omitted or set to None if NFS testing is not possible or desired.
57env__net_nfs_readable_file = {
58    'fn': 'ubtest-readable.bin',
59    'addr': 0x10000000,
60    'size': 5058624,
61    'crc32': 'c2244b26',
62}
63
64# True if a router advertisement service is connected to the network, and should
65# be tested. If router advertisement testing is not possible or desired, this
66variable may be omitted or set to False.
67env__router_on_net = True
68"""
69
70net_set_up = False
71net6_set_up = False
72
73def test_net_pre_commands(u_boot_console):
74    """Execute any commands required to enable network hardware.
75
76    These commands are provided by the boardenv_* file; see the comment at the
77    beginning of this file.
78    """
79
80    init_usb = u_boot_console.config.env.get('env__net_uses_usb', False)
81    if init_usb:
82        u_boot_console.run_command('usb start')
83
84    init_pci = u_boot_console.config.env.get('env__net_uses_pci', False)
85    if init_pci:
86        u_boot_console.run_command('pci enum')
87
88@pytest.mark.buildconfigspec('cmd_dhcp')
89def test_net_dhcp(u_boot_console):
90    """Test the dhcp command.
91
92    The boardenv_* file may be used to enable/disable this test; see the
93    comment at the beginning of this file.
94    """
95
96    test_dhcp = u_boot_console.config.env.get('env__net_dhcp_server', False)
97    if not test_dhcp:
98        pytest.skip('No DHCP server available')
99
100    u_boot_console.run_command('setenv autoload no')
101    output = u_boot_console.run_command('dhcp')
102    assert 'DHCP client bound to address ' in output
103
104    global net_set_up
105    net_set_up = True
106
107@pytest.mark.buildconfigspec('cmd_dhcp6')
108def test_net_dhcp6(u_boot_console):
109    """Test the dhcp6 command.
110
111    The boardenv_* file may be used to enable/disable this test; see the
112    comment at the beginning of this file.
113    """
114
115    test_dhcp6 = u_boot_console.config.env.get('env__net_dhcp6_server', False)
116    if not test_dhcp6:
117        pytest.skip('No DHCP6 server available')
118
119    u_boot_console.run_command('setenv autoload no')
120    output = u_boot_console.run_command('dhcp6')
121    assert 'DHCP6 client bound to ' in output
122
123    global net6_set_up
124    net6_set_up = True
125
126@pytest.mark.buildconfigspec('net')
127def test_net_setup_static(u_boot_console):
128    """Set up a static IP configuration.
129
130    The configuration is provided by the boardenv_* file; see the comment at
131    the beginning of this file.
132    """
133
134    env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None)
135    if not env_vars:
136        pytest.skip('No static network configuration is defined')
137
138    for (var, val) in env_vars:
139        u_boot_console.run_command('setenv %s %s' % (var, val))
140
141    global net_set_up
142    net_set_up = True
143
144@pytest.mark.buildconfigspec('cmd_ping')
145def test_net_ping(u_boot_console):
146    """Test the ping command.
147
148    The $serverip (as set up by either test_net_dhcp or test_net_setup_static)
149    is pinged. The test validates that the host is alive, as reported by the
150    ping command's output.
151    """
152
153    if not net_set_up:
154        pytest.skip('Network not initialized')
155
156    output = u_boot_console.run_command('ping $serverip')
157    assert 'is alive' in output
158
159@pytest.mark.buildconfigspec('IPV6_ROUTER_DISCOVERY')
160def test_net_network_discovery(u_boot_console):
161    """Test the network discovery feature of IPv6.
162
163    An IPv6 network command (ping6 in this case) is run to make U-Boot send a
164    router solicitation packet, receive a router advertisement message, and
165    parse it.
166    A router advertisement service needs to be running for this test to succeed.
167    U-Boot receives the RA, processes it, and if successful, assigns the gateway
168    IP and prefix length.
169    The configuration is provided by the boardenv_* file; see the comment at
170    the beginning of this file.
171    """
172
173    router_on_net = u_boot_console.config.env.get('env__router_on_net', False)
174    if not router_on_net:
175        pytest.skip('No router on network')
176
177    fake_host_ip = 'fe80::215:5dff:fef6:2ec6'
178    output = u_boot_console.run_command('ping6 ' + fake_host_ip)
179    assert 'ROUTER SOLICITATION 1' in output
180    assert 'Set gatewayip6:' in output
181    assert '0000:0000:0000:0000:0000:0000:0000:0000' not in output
182
183@pytest.mark.buildconfigspec('cmd_net')
184def test_net_tftpboot(u_boot_console):
185    """Test the tftpboot command.
186
187    A file is downloaded from the TFTP server, its size and optionally its
188    CRC32 are validated.
189
190    The details of the file to download are provided by the boardenv_* file;
191    see the comment at the beginning of this file.
192    """
193
194    if not net_set_up:
195        pytest.skip('Network not initialized')
196
197    f = u_boot_console.config.env.get('env__net_tftp_readable_file', None)
198    if not f:
199        pytest.skip('No TFTP readable file to read')
200
201    addr = f.get('addr', None)
202
203    fn = f['fn']
204    if not addr:
205        output = u_boot_console.run_command('tftpboot %s' % (fn))
206    else:
207        output = u_boot_console.run_command('tftpboot %x %s' % (addr, fn))
208    expected_text = 'Bytes transferred = '
209    sz = f.get('size', None)
210    if sz:
211        expected_text += '%d' % sz
212    assert expected_text in output
213
214    expected_crc = f.get('crc32', None)
215    if not expected_crc:
216        return
217
218    if u_boot_console.config.buildconfig.get('config_cmd_crc32', 'n') != 'y':
219        return
220
221    output = u_boot_console.run_command('crc32 $fileaddr $filesize')
222    assert expected_crc in output
223
224@pytest.mark.buildconfigspec('cmd_nfs')
225def test_net_nfs(u_boot_console):
226    """Test the nfs command.
227
228    A file is downloaded from the NFS server, its size and optionally its
229    CRC32 are validated.
230
231    The details of the file to download are provided by the boardenv_* file;
232    see the comment at the beginning of this file.
233    """
234
235    if not net_set_up:
236        pytest.skip('Network not initialized')
237
238    f = u_boot_console.config.env.get('env__net_nfs_readable_file', None)
239    if not f:
240        pytest.skip('No NFS readable file to read')
241
242    addr = f.get('addr', None)
243    if not addr:
244        addr = u_boot_utils.find_ram_base(u_boot_console)
245
246    fn = f['fn']
247    output = u_boot_console.run_command('nfs %x %s' % (addr, fn))
248    expected_text = 'Bytes transferred = '
249    sz = f.get('size', None)
250    if sz:
251        expected_text += '%d' % sz
252    assert expected_text in output
253
254    expected_crc = f.get('crc32', None)
255    if not expected_crc:
256        return
257
258    if u_boot_console.config.buildconfig.get('config_cmd_crc32', 'n') != 'y':
259        return
260
261    output = u_boot_console.run_command('crc32 %x $filesize' % addr)
262    assert expected_crc in output
263