Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/uboot/net.c
34677 views
1
/*-
2
* Copyright (c) 2000-2001 Benno Rice
3
* Copyright (c) 2007 Semihalf, Rafal Jaworowski <[email protected]>
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
32
#include <net/if.h>
33
#include <netinet/in.h>
34
#include <netinet/in_systm.h>
35
#include <netinet/if_ether.h>
36
#include <netinet/ip.h>
37
38
#include <stand.h>
39
#include <net.h>
40
#include <netif.h>
41
42
#include "api_public.h"
43
#include "glue.h"
44
#include "libuboot.h"
45
#include "dev_net.h"
46
47
static int net_probe(struct netif *, void *);
48
static int net_match(struct netif *, void *);
49
static void net_init(struct iodesc *, void *);
50
static ssize_t net_get(struct iodesc *, void **, time_t);
51
static ssize_t net_put(struct iodesc *, void *, size_t);
52
static void net_end(struct netif *);
53
54
extern struct netif_stats net_stats[];
55
56
struct netif_dif net_ifs[] = {
57
/* dif_unit dif_nsel dif_stats dif_private */
58
{ 0, 1, &net_stats[0], 0, },
59
};
60
61
struct netif_stats net_stats[nitems(net_ifs)];
62
63
struct netif_driver uboot_net = {
64
"uboot_eth", /* netif_bname */
65
net_match, /* netif_match */
66
net_probe, /* netif_probe */
67
net_init, /* netif_init */
68
net_get, /* netif_get */
69
net_put, /* netif_put */
70
net_end, /* netif_end */
71
net_ifs, /* netif_ifs */
72
nitems(net_ifs) /* netif_nifs */
73
};
74
75
struct uboot_softc {
76
uint32_t sc_pad;
77
uint8_t sc_rxbuf[ETHER_MAX_LEN];
78
uint8_t sc_txbuf[ETHER_MAX_LEN + PKTALIGN];
79
uint8_t *sc_txbufp;
80
int sc_handle; /* device handle for ub_dev_xxx */
81
};
82
83
static struct uboot_softc uboot_softc;
84
85
/*
86
* get_env_net_params()
87
*
88
* Attempt to obtain all the parms we need for netbooting from the U-Boot
89
* environment. If we fail to obtain the values it may still be possible to
90
* netboot; the net_dev code will attempt to get the values from bootp, rarp,
91
* and other such sources.
92
*
93
* If rootip.s_addr is non-zero net_dev assumes the required global variables
94
* are set and skips the bootp inquiry. For that reason, we don't set rootip
95
* until we've verified that we have at least the minimum required info.
96
*
97
* This is called from netif_init() which can result in it getting called
98
* multiple times, by design. The network code at higher layers zeroes out
99
* rootip when it closes a network interface, so if it gets opened again we have
100
* to obtain all this info again.
101
*/
102
static void
103
get_env_net_params(void)
104
{
105
char *envstr;
106
in_addr_t rootaddr, serveraddr;
107
108
/*
109
* Silently get out right away if we don't have rootpath, because none
110
* of the other info we obtain below is sufficient to boot without it.
111
*
112
* If we do have rootpath, copy it into the global var and also set
113
* dhcp.root-path in the env. If we don't get all the other info from
114
* the u-boot env below, we will still try dhcp/bootp, but the server-
115
* provided path will not replace the user-provided value we set here.
116
*/
117
if ((envstr = ub_env_get("rootpath")) == NULL)
118
return;
119
strlcpy(rootpath, envstr, sizeof(rootpath));
120
setenv("dhcp.root-path", rootpath, 0);
121
122
/*
123
* Our own IP address must be valid. Silently get out if it's not set,
124
* but whine if it's there and we can't parse it.
125
*/
126
if ((envstr = ub_env_get("ipaddr")) == NULL)
127
return;
128
if ((myip.s_addr = inet_addr(envstr)) == INADDR_NONE) {
129
printf("Could not parse ipaddr '%s'\n", envstr);
130
return;
131
}
132
133
/*
134
* Netmask is optional, default to the "natural" netmask for our IP, but
135
* whine if it was provided and we couldn't parse it.
136
*/
137
if ((envstr = ub_env_get("netmask")) != NULL &&
138
(netmask = inet_addr(envstr)) == INADDR_NONE) {
139
printf("Could not parse netmask '%s'\n", envstr);
140
}
141
if (netmask == INADDR_NONE) {
142
if (IN_CLASSA(myip.s_addr))
143
netmask = IN_CLASSA_NET;
144
else if (IN_CLASSB(myip.s_addr))
145
netmask = IN_CLASSB_NET;
146
else
147
netmask = IN_CLASSC_NET;
148
}
149
150
/*
151
* Get optional serverip before rootpath; the latter can override it.
152
* Whine only if it's present but can't be parsed.
153
*/
154
serveraddr = INADDR_NONE;
155
if ((envstr = ub_env_get("serverip")) != NULL) {
156
if ((serveraddr = inet_addr(envstr)) == INADDR_NONE)
157
printf("Could not parse serverip '%s'\n", envstr);
158
}
159
160
/*
161
* There must be a rootpath. It may be ip:/path or it may be just the
162
* path in which case the ip needs to be in serverip.
163
*/
164
rootaddr = net_parse_rootpath();
165
if (rootaddr == INADDR_NONE)
166
rootaddr = serveraddr;
167
if (rootaddr == INADDR_NONE) {
168
printf("No server address for rootpath '%s'\n", envstr);
169
return;
170
}
171
rootip.s_addr = rootaddr;
172
173
/*
174
* Gateway IP is optional unless rootip is on a different net in which
175
* case whine if it's missing or we can't parse it, and set rootip addr
176
* to zero, which signals to other network code that network params
177
* aren't set (so it will try dhcp, bootp, etc).
178
*/
179
envstr = ub_env_get("gatewayip");
180
if (!SAMENET(myip, rootip, netmask)) {
181
if (envstr == NULL) {
182
printf("Need gatewayip for a root server on a "
183
"different network.\n");
184
rootip.s_addr = 0;
185
return;
186
}
187
if ((gateip.s_addr = inet_addr(envstr)) == INADDR_NONE) {
188
printf("Could not parse gatewayip '%s'\n", envstr);
189
rootip.s_addr = 0;
190
return;
191
}
192
}
193
}
194
195
static int
196
net_match(struct netif *nif, void *machdep_hint)
197
{
198
char **a = (char **)machdep_hint;
199
200
if (memcmp("net", *a, 3) == 0)
201
return (1);
202
203
printf("net_match: could not match network device\n");
204
return (0);
205
}
206
207
static int
208
net_probe(struct netif *nif, void *machdep_hint)
209
{
210
struct device_info *di;
211
int i;
212
213
for (i = 0; i < devs_no; i++)
214
if ((di = ub_dev_get(i)) != NULL)
215
if (di->type == DEV_TYP_NET)
216
break;
217
218
if (i == devs_no) {
219
printf("net_probe: no network devices found, maybe not"
220
" enumerated yet..?\n");
221
return (-1);
222
}
223
224
#if defined(NETIF_DEBUG)
225
printf("net_probe: network device found: %d\n", i);
226
#endif
227
uboot_softc.sc_handle = i;
228
229
return (0);
230
}
231
232
static ssize_t
233
net_put(struct iodesc *desc, void *pkt, size_t len)
234
{
235
struct netif *nif = desc->io_netif;
236
struct uboot_softc *sc = nif->nif_devdata;
237
size_t sendlen;
238
ssize_t rv;
239
240
#if defined(NETIF_DEBUG)
241
struct ether_header *eh;
242
243
printf("net_put: desc %p, pkt %p, len %d\n", desc, pkt, len);
244
eh = pkt;
245
printf("dst: %s ", ether_sprintf(eh->ether_dhost));
246
printf("src: %s ", ether_sprintf(eh->ether_shost));
247
printf("type: 0x%x\n", eh->ether_type & 0xffff);
248
#endif
249
250
if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
251
sendlen = ETHER_MIN_LEN - ETHER_CRC_LEN;
252
bzero(sc->sc_txbufp, sendlen);
253
} else
254
sendlen = len;
255
256
memcpy(sc->sc_txbufp, pkt, len);
257
258
rv = ub_dev_send(sc->sc_handle, sc->sc_txbufp, sendlen);
259
260
#if defined(NETIF_DEBUG)
261
printf("net_put: ub_send returned %d\n", rv);
262
#endif
263
if (rv == 0)
264
rv = len;
265
else
266
rv = -1;
267
268
return (rv);
269
}
270
271
static ssize_t
272
net_get(struct iodesc *desc, void **pkt, time_t timeout)
273
{
274
struct netif *nif = desc->io_netif;
275
struct uboot_softc *sc = nif->nif_devdata;
276
time_t t;
277
int err, rlen;
278
size_t len;
279
char *buf;
280
281
#if defined(NETIF_DEBUG)
282
printf("net_get: pkt %p, timeout %d\n", pkt, timeout);
283
#endif
284
t = getsecs();
285
len = sizeof(sc->sc_rxbuf);
286
do {
287
err = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len, &rlen);
288
289
if (err != 0) {
290
printf("net_get: ub_dev_recv() failed, error=%d\n",
291
err);
292
rlen = 0;
293
break;
294
}
295
} while ((rlen == -1 || rlen == 0) && (getsecs() - t < timeout));
296
297
#if defined(NETIF_DEBUG)
298
printf("net_get: received len %d (%x)\n", rlen, rlen);
299
#endif
300
301
if (rlen > 0) {
302
buf = malloc(rlen + ETHER_ALIGN);
303
if (buf == NULL)
304
return (-1);
305
memcpy(buf + ETHER_ALIGN, sc->sc_rxbuf, rlen);
306
*pkt = buf;
307
return ((ssize_t)rlen);
308
}
309
310
return (-1);
311
}
312
313
static void
314
net_init(struct iodesc *desc, void *machdep_hint)
315
{
316
struct netif *nif = desc->io_netif;
317
struct uboot_softc *sc;
318
struct device_info *di;
319
int err;
320
321
sc = nif->nif_devdata = &uboot_softc;
322
323
if ((err = ub_dev_open(sc->sc_handle)) != 0)
324
panic("%s%d: initialisation failed with error %d",
325
nif->nif_driver->netif_bname, nif->nif_unit, err);
326
327
/* Get MAC address */
328
di = ub_dev_get(sc->sc_handle);
329
memcpy(desc->myea, di->di_net.hwaddr, 6);
330
if (memcmp (desc->myea, "\0\0\0\0\0\0", 6) == 0) {
331
panic("%s%d: empty ethernet address!",
332
nif->nif_driver->netif_bname, nif->nif_unit);
333
}
334
335
/* Attempt to get netboot params from the u-boot env. */
336
get_env_net_params();
337
if (myip.s_addr != 0)
338
desc->myip = myip;
339
340
#if defined(NETIF_DEBUG)
341
printf("network: %s%d attached to %s\n", nif->nif_driver->netif_bname,
342
nif->nif_unit, ether_sprintf(desc->myea));
343
#endif
344
345
/* Set correct alignment for TX packets */
346
sc->sc_txbufp = sc->sc_txbuf;
347
if ((unsigned long)sc->sc_txbufp % PKTALIGN)
348
sc->sc_txbufp += PKTALIGN -
349
(unsigned long)sc->sc_txbufp % PKTALIGN;
350
}
351
352
static void
353
net_end(struct netif *nif)
354
{
355
struct uboot_softc *sc = nif->nif_devdata;
356
int err;
357
358
if ((err = ub_dev_close(sc->sc_handle)) != 0)
359
panic("%s%d: net_end failed with error %d",
360
nif->nif_driver->netif_bname, nif->nif_unit, err);
361
}
362
363