net.c revision 185099
1166065Spjd/*-
2166065Spjd * Copyright (c) 2000-2001 Benno Rice
3166065Spjd * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
4166065Spjd * All rights reserved.
5166065Spjd *
6166065Spjd * Redistribution and use in source and binary forms, with or without
7166065Spjd * modification, are permitted provided that the following conditions
8166065Spjd * are met:
9166065Spjd * 1. Redistributions of source code must retain the above copyright
10166065Spjd *    notice, this list of conditions and the following disclaimer.
11210984Spjd * 2. Redistributions in binary form must reproduce the above copyright
12210984Spjd *    notice, this list of conditions and the following disclaimer in the
13210984Spjd *    documentation and/or other materials provided with the distribution.
14210984Spjd *
15210984Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16210984Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17210984Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18210984Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19210984Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20210984Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21166065Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22166065Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23166065Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24166065Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25166065Spjd * SUCH DAMAGE.
26166065Spjd */
27166065Spjd
28166065Spjd#include <sys/cdefs.h>
29166065Spjd__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/net.c 185099 2008-11-19 17:34:28Z raj $");
30210984Spjd
31166065Spjd#include <sys/param.h>
32210984Spjd#include <sys/types.h>
33166065Spjd#include <sys/socket.h>
34210984Spjd
35166065Spjd#include <net/if.h>
36210984Spjd#include <netinet/in.h>
37166065Spjd#include <netinet/in_systm.h>
38166065Spjd#include <netinet/if_ether.h>
39166065Spjd#include <netinet/ip.h>
40166065Spjd
41210984Spjd#include <stand.h>
42210984Spjd#include <net.h>
43210984Spjd#include <netif.h>
44210984Spjd
45210984Spjd#include "api_public.h"
46210984Spjd#include "glue.h"
47210984Spjd#include "libuboot.h"
48210984Spjd
49210984Spjd#define NETIF_DEBUG
50210984Spjd#define NETIF_VERBOSE_DEBUG
51210984Spjd#undef NETIF_DEBUG
52210984Spjd#undef NETIF_VERBOSE_DEBUG
53210984Spjd
54210984Spjd
55210984Spjdstatic int	net_probe(struct netif *, void *);
56210984Spjdstatic int	net_match(struct netif *, void *);
57static void	net_init(struct iodesc *, void *);
58static int	net_get(struct iodesc *, void *, size_t, time_t);
59static int	net_put(struct iodesc *, void *, size_t);
60static void	net_end(struct netif *);
61
62extern struct netif_stats net_stats[];
63
64struct netif_dif net_ifs[] = {
65	/*	dif_unit	dif_nsel	dif_stats	dif_private */
66	{	0,		1,		&net_stats[0],	0,	},
67};
68
69struct netif_stats net_stats[NENTS(net_ifs)];
70
71struct netif_driver uboot_net = {
72	"uboot_eth",		/* netif_bname */
73	net_match,		/* netif_match */
74	net_probe,		/* netif_probe */
75	net_init,		/* netif_init */
76	net_get,		/* netif_get */
77	net_put,		/* netif_put */
78	net_end,		/* netif_end */
79	net_ifs,		/* netif_ifs */
80	NENTS(net_ifs)		/* netif_nifs */
81};
82
83struct uboot_softc {
84	uint32_t	sc_pad;
85	uint8_t		sc_rxbuf[ETHER_MAX_LEN];
86	uint8_t		sc_txbuf[ETHER_MAX_LEN + PKTALIGN];
87	uint8_t		*sc_txbufp;
88	int		sc_handle;	/* device handle for ub_dev_xxx */
89};
90
91static struct uboot_softc uboot_softc;
92
93static int
94net_match(struct netif *nif, void *machdep_hint)
95{
96	char **a = (char **)machdep_hint;
97
98	if (memcmp("net", *a, 3) == 0)
99		return (1);
100
101	printf("net_match: could not match network device\n");
102	return (0);
103}
104
105static int
106net_probe(struct netif *nif, void *machdep_hint)
107{
108	struct device_info *di;
109	int i;
110
111	for (i = 0; i < devs_no; i++)
112		if ((di = ub_dev_get(i)) != NULL)
113			if (di->type == DEV_TYP_NET)
114				break;
115
116	if (i == devs_no) {
117		printf("net_probe: no network devices found, maybe not"
118		    " enumerated yet..?\n");
119		return (-1);
120	}
121
122#if defined(NETIF_DEBUG)
123	printf("net_probe: network device found: %d\n", i);
124#endif
125	uboot_softc.sc_handle = i;
126
127	return (0);
128}
129
130static int
131net_put(struct iodesc *desc, void *pkt, size_t len)
132{
133	struct netif *nif = desc->io_netif;
134	struct uboot_softc *sc = nif->nif_devdata;
135	size_t sendlen;
136	ssize_t rv;
137
138#if defined(NETIF_DEBUG)
139	struct ether_header *eh;
140
141	printf("net_put: desc 0x%x, pkt 0x%x, len %d\n", desc, pkt, len);
142	eh = pkt;
143	printf("dst: %s ", ether_sprintf(eh->ether_dhost));
144	printf("src: %s ", ether_sprintf(eh->ether_shost));
145	printf("type: 0x%x\n", eh->ether_type & 0xffff);
146#endif
147
148	if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
149		sendlen = ETHER_MIN_LEN - ETHER_CRC_LEN;
150		bzero(sc->sc_txbufp, sendlen);
151	} else
152		sendlen = len;
153
154	memcpy(sc->sc_txbufp, pkt, len);
155
156	rv = ub_dev_send(sc->sc_handle, sc->sc_txbufp, sendlen);
157
158#if defined(NETIF_DEBUG)
159	printf("net_put: ub_send returned %d\n", rv);
160#endif
161	if (rv == 0)
162		rv = len;
163	else
164		rv = -1;
165
166	return (rv);
167}
168
169static int
170net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
171{
172	struct netif *nif = desc->io_netif;
173	struct uboot_softc *sc = nif->nif_devdata;
174	time_t t;
175	int err, rlen;
176
177#if defined(NETIF_DEBUG)
178	printf("net_get: pkt %x, len %d, timeout %d\n", pkt, len, timeout);
179#endif
180	t = getsecs();
181	do {
182		err = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len, &rlen);
183
184		if (err != 0) {
185			printf("net_get: ub_dev_recv() failed, error=%d\n",
186			    err);
187			rlen = 0;
188			break;
189		}
190	} while ((rlen == -1 || rlen == 0) && (getsecs() - t < timeout));
191
192#if defined(NETIF_DEBUG)
193	printf("net_get: received len %d (%x)\n", rlen, rlen);
194#endif
195
196	if (rlen > 0) {
197		memcpy(pkt, sc->sc_rxbuf, MIN(len, rlen));
198		if (rlen != len) {
199#if defined(NETIF_DEBUG)
200			printf("net_get: len %x, rlen %x\n", len, rlen);
201#endif
202		}
203		return (rlen);
204	}
205
206	return (-1);
207}
208
209static void
210net_init(struct iodesc *desc, void *machdep_hint)
211{
212	struct netif *nif = desc->io_netif;
213	struct uboot_softc *sc;
214	struct device_info *di;
215	int err;
216
217	sc = nif->nif_devdata = &uboot_softc;
218
219	if ((err = ub_dev_open(sc->sc_handle)) != 0)
220		panic("%s%d: initialisation failed with error %d\n",
221		    nif->nif_driver->netif_bname, nif->nif_unit, err);
222
223	/* Get MAC address */
224	di = ub_dev_get(sc->sc_handle);
225	memcpy(desc->myea, di->di_net.hwaddr, 6);
226	if (memcmp (desc->myea, "\0\0\0\0\0\0", 6) == 0) {
227		panic("%s%d: empty ethernet address!",
228		    nif->nif_driver->netif_bname, nif->nif_unit);
229	}
230
231#if defined(NETIF_DEBUG)
232	printf("network: %s%d attached to %s\n", nif->nif_driver->netif_bname,
233	    nif->nif_unit, ether_sprintf(desc->myea));
234#endif
235
236	/* Set correct alignment for TX packets */
237	sc->sc_txbufp = sc->sc_txbuf;
238	if ((unsigned long)sc->sc_txbufp % PKTALIGN)
239		sc->sc_txbufp += PKTALIGN -
240		    (unsigned long)sc->sc_txbufp % PKTALIGN;
241}
242
243static void
244net_end(struct netif *nif)
245{
246	struct uboot_softc *sc = nif->nif_devdata;
247	int err;
248
249	if ((err = ub_dev_close(sc->sc_handle)) != 0)
250		panic("%s%d: net_end failed with error %d\n",
251		    nif->nif_driver->netif_bname, nif->nif_unit, err);
252}
253