xref: /freebsd/stand/uboot/net.c (revision dcc20bced51583df83e49af269ff7be5fb48dbf8)
19dc70af8SWarner Losh /*-
29dc70af8SWarner Losh  * Copyright (c) 2000-2001 Benno Rice
39dc70af8SWarner Losh  * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
49dc70af8SWarner Losh  * All rights reserved.
59dc70af8SWarner Losh  *
69dc70af8SWarner Losh  * Redistribution and use in source and binary forms, with or without
79dc70af8SWarner Losh  * modification, are permitted provided that the following conditions
89dc70af8SWarner Losh  * are met:
99dc70af8SWarner Losh  * 1. Redistributions of source code must retain the above copyright
109dc70af8SWarner Losh  *    notice, this list of conditions and the following disclaimer.
119dc70af8SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
129dc70af8SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
139dc70af8SWarner Losh  *    documentation and/or other materials provided with the distribution.
149dc70af8SWarner Losh  *
159dc70af8SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
169dc70af8SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
179dc70af8SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
189dc70af8SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199dc70af8SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
209dc70af8SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
219dc70af8SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
229dc70af8SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
239dc70af8SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
249dc70af8SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
259dc70af8SWarner Losh  * SUCH DAMAGE.
269dc70af8SWarner Losh  */
279dc70af8SWarner Losh 
289dc70af8SWarner Losh #include <sys/param.h>
299dc70af8SWarner Losh #include <sys/types.h>
309dc70af8SWarner Losh #include <sys/socket.h>
319dc70af8SWarner Losh 
329dc70af8SWarner Losh #include <net/if.h>
339dc70af8SWarner Losh #include <netinet/in.h>
349dc70af8SWarner Losh #include <netinet/in_systm.h>
359dc70af8SWarner Losh #include <netinet/if_ether.h>
369dc70af8SWarner Losh #include <netinet/ip.h>
379dc70af8SWarner Losh 
389dc70af8SWarner Losh #include <stand.h>
399dc70af8SWarner Losh #include <net.h>
409dc70af8SWarner Losh #include <netif.h>
419dc70af8SWarner Losh 
429dc70af8SWarner Losh #include "api_public.h"
439dc70af8SWarner Losh #include "glue.h"
449dc70af8SWarner Losh #include "libuboot.h"
459dc70af8SWarner Losh #include "dev_net.h"
469dc70af8SWarner Losh 
479dc70af8SWarner Losh static int	net_probe(struct netif *, void *);
489dc70af8SWarner Losh static int	net_match(struct netif *, void *);
499dc70af8SWarner Losh static void	net_init(struct iodesc *, void *);
509dc70af8SWarner Losh static ssize_t	net_get(struct iodesc *, void **, time_t);
519dc70af8SWarner Losh static ssize_t	net_put(struct iodesc *, void *, size_t);
529dc70af8SWarner Losh static void	net_end(struct netif *);
539dc70af8SWarner Losh 
549dc70af8SWarner Losh extern struct netif_stats net_stats[];
559dc70af8SWarner Losh 
569dc70af8SWarner Losh struct netif_dif net_ifs[] = {
579dc70af8SWarner Losh 	/*	dif_unit	dif_nsel	dif_stats	dif_private */
589dc70af8SWarner Losh 	{	0,		1,		&net_stats[0],	0,	},
599dc70af8SWarner Losh };
609dc70af8SWarner Losh 
619dc70af8SWarner Losh struct netif_stats net_stats[nitems(net_ifs)];
629dc70af8SWarner Losh 
639dc70af8SWarner Losh struct netif_driver uboot_net = {
649dc70af8SWarner Losh 	"uboot_eth",		/* netif_bname */
659dc70af8SWarner Losh 	net_match,		/* netif_match */
669dc70af8SWarner Losh 	net_probe,		/* netif_probe */
679dc70af8SWarner Losh 	net_init,		/* netif_init */
689dc70af8SWarner Losh 	net_get,		/* netif_get */
699dc70af8SWarner Losh 	net_put,		/* netif_put */
709dc70af8SWarner Losh 	net_end,		/* netif_end */
719dc70af8SWarner Losh 	net_ifs,		/* netif_ifs */
729dc70af8SWarner Losh 	nitems(net_ifs)		/* netif_nifs */
739dc70af8SWarner Losh };
749dc70af8SWarner Losh 
759dc70af8SWarner Losh struct uboot_softc {
769dc70af8SWarner Losh 	uint32_t	sc_pad;
779dc70af8SWarner Losh 	uint8_t		sc_rxbuf[ETHER_MAX_LEN];
789dc70af8SWarner Losh 	uint8_t		sc_txbuf[ETHER_MAX_LEN + PKTALIGN];
799dc70af8SWarner Losh 	uint8_t		*sc_txbufp;
809dc70af8SWarner Losh 	int		sc_handle;	/* device handle for ub_dev_xxx */
819dc70af8SWarner Losh };
829dc70af8SWarner Losh 
839dc70af8SWarner Losh static struct uboot_softc uboot_softc;
849dc70af8SWarner Losh 
859dc70af8SWarner Losh /*
869dc70af8SWarner Losh  * get_env_net_params()
879dc70af8SWarner Losh  *
889dc70af8SWarner Losh  * Attempt to obtain all the parms we need for netbooting from the U-Boot
899dc70af8SWarner Losh  * environment.  If we fail to obtain the values it may still be possible to
909dc70af8SWarner Losh  * netboot; the net_dev code will attempt to get the values from bootp, rarp,
919dc70af8SWarner Losh  * and other such sources.
929dc70af8SWarner Losh  *
939dc70af8SWarner Losh  * If rootip.s_addr is non-zero net_dev assumes the required global variables
949dc70af8SWarner Losh  * are set and skips the bootp inquiry.  For that reason, we don't set rootip
959dc70af8SWarner Losh  * until we've verified that we have at least the minimum required info.
969dc70af8SWarner Losh  *
979dc70af8SWarner Losh  * This is called from netif_init() which can result in it getting called
989dc70af8SWarner Losh  * multiple times, by design.  The network code at higher layers zeroes out
999dc70af8SWarner Losh  * rootip when it closes a network interface, so if it gets opened again we have
1009dc70af8SWarner Losh  * to obtain all this info again.
1019dc70af8SWarner Losh  */
1029dc70af8SWarner Losh static void
get_env_net_params(void)103*dcc20bceSWarner Losh get_env_net_params(void)
1049dc70af8SWarner Losh {
1059dc70af8SWarner Losh 	char *envstr;
1069dc70af8SWarner Losh 	in_addr_t rootaddr, serveraddr;
1079dc70af8SWarner Losh 
1089dc70af8SWarner Losh 	/*
1099dc70af8SWarner Losh 	 * Silently get out right away if we don't have rootpath, because none
1109dc70af8SWarner Losh 	 * of the other info we obtain below is sufficient to boot without it.
1119dc70af8SWarner Losh 	 *
1129dc70af8SWarner Losh 	 * If we do have rootpath, copy it into the global var and also set
1139dc70af8SWarner Losh 	 * dhcp.root-path in the env.  If we don't get all the other info from
1149dc70af8SWarner Losh 	 * the u-boot env below, we will still try dhcp/bootp, but the server-
1159dc70af8SWarner Losh 	 * provided path will not replace the user-provided value we set here.
1169dc70af8SWarner Losh 	 */
1179dc70af8SWarner Losh 	if ((envstr = ub_env_get("rootpath")) == NULL)
1189dc70af8SWarner Losh 		return;
1199dc70af8SWarner Losh 	strlcpy(rootpath, envstr, sizeof(rootpath));
1209dc70af8SWarner Losh 	setenv("dhcp.root-path", rootpath, 0);
1219dc70af8SWarner Losh 
1229dc70af8SWarner Losh 	/*
1239dc70af8SWarner Losh 	 * Our own IP address must be valid.  Silently get out if it's not set,
1249dc70af8SWarner Losh 	 * but whine if it's there and we can't parse it.
1259dc70af8SWarner Losh 	 */
1269dc70af8SWarner Losh 	if ((envstr = ub_env_get("ipaddr")) == NULL)
1279dc70af8SWarner Losh 		return;
1289dc70af8SWarner Losh 	if ((myip.s_addr = inet_addr(envstr)) == INADDR_NONE) {
1299dc70af8SWarner Losh 		printf("Could not parse ipaddr '%s'\n", envstr);
1309dc70af8SWarner Losh 		return;
1319dc70af8SWarner Losh 	}
1329dc70af8SWarner Losh 
1339dc70af8SWarner Losh 	/*
1349dc70af8SWarner Losh 	 * Netmask is optional, default to the "natural" netmask for our IP, but
1359dc70af8SWarner Losh 	 * whine if it was provided and we couldn't parse it.
1369dc70af8SWarner Losh 	 */
1379dc70af8SWarner Losh 	if ((envstr = ub_env_get("netmask")) != NULL &&
1389dc70af8SWarner Losh 	    (netmask = inet_addr(envstr)) == INADDR_NONE) {
1399dc70af8SWarner Losh 		printf("Could not parse netmask '%s'\n", envstr);
1409dc70af8SWarner Losh 	}
1419dc70af8SWarner Losh 	if (netmask == INADDR_NONE) {
1429dc70af8SWarner Losh 		if (IN_CLASSA(myip.s_addr))
1439dc70af8SWarner Losh 			netmask = IN_CLASSA_NET;
1449dc70af8SWarner Losh 		else if (IN_CLASSB(myip.s_addr))
1459dc70af8SWarner Losh 			netmask = IN_CLASSB_NET;
1469dc70af8SWarner Losh 		else
1479dc70af8SWarner Losh 			netmask = IN_CLASSC_NET;
1489dc70af8SWarner Losh 	}
1499dc70af8SWarner Losh 
1509dc70af8SWarner Losh 	/*
1519dc70af8SWarner Losh 	 * Get optional serverip before rootpath; the latter can override it.
1529dc70af8SWarner Losh 	 * Whine only if it's present but can't be parsed.
1539dc70af8SWarner Losh 	 */
1549dc70af8SWarner Losh 	serveraddr = INADDR_NONE;
1559dc70af8SWarner Losh 	if ((envstr = ub_env_get("serverip")) != NULL) {
1569dc70af8SWarner Losh 		if ((serveraddr = inet_addr(envstr)) == INADDR_NONE)
1579dc70af8SWarner Losh 			printf("Could not parse serverip '%s'\n", envstr);
1589dc70af8SWarner Losh 	}
1599dc70af8SWarner Losh 
1609dc70af8SWarner Losh 	/*
1619dc70af8SWarner Losh 	 * There must be a rootpath.  It may be ip:/path or it may be just the
1629dc70af8SWarner Losh 	 * path in which case the ip needs to be in serverip.
1639dc70af8SWarner Losh 	 */
1649dc70af8SWarner Losh 	rootaddr = net_parse_rootpath();
1659dc70af8SWarner Losh 	if (rootaddr == INADDR_NONE)
1669dc70af8SWarner Losh 		rootaddr = serveraddr;
1679dc70af8SWarner Losh 	if (rootaddr == INADDR_NONE) {
1689dc70af8SWarner Losh 		printf("No server address for rootpath '%s'\n", envstr);
1699dc70af8SWarner Losh 		return;
1709dc70af8SWarner Losh 	}
1719dc70af8SWarner Losh 	rootip.s_addr = rootaddr;
1729dc70af8SWarner Losh 
1739dc70af8SWarner Losh 	/*
1749dc70af8SWarner Losh 	 * Gateway IP is optional unless rootip is on a different net in which
1759dc70af8SWarner Losh 	 * case whine if it's missing or we can't parse it, and set rootip addr
1769dc70af8SWarner Losh 	 * to zero, which signals to other network code that network params
1779dc70af8SWarner Losh 	 * aren't set (so it will try dhcp, bootp, etc).
1789dc70af8SWarner Losh 	 */
1799dc70af8SWarner Losh 	envstr = ub_env_get("gatewayip");
1809dc70af8SWarner Losh 	if (!SAMENET(myip, rootip, netmask)) {
1819dc70af8SWarner Losh 		if (envstr == NULL)  {
1829dc70af8SWarner Losh 			printf("Need gatewayip for a root server on a "
1839dc70af8SWarner Losh 			    "different network.\n");
1849dc70af8SWarner Losh 			rootip.s_addr = 0;
1859dc70af8SWarner Losh 			return;
1869dc70af8SWarner Losh 		}
1879dc70af8SWarner Losh 		if ((gateip.s_addr = inet_addr(envstr)) == INADDR_NONE) {
1889dc70af8SWarner Losh 			printf("Could not parse gatewayip '%s'\n", envstr);
1899dc70af8SWarner Losh 			rootip.s_addr = 0;
1909dc70af8SWarner Losh 			return;
1919dc70af8SWarner Losh 		}
1929dc70af8SWarner Losh 	}
1939dc70af8SWarner Losh }
1949dc70af8SWarner Losh 
1959dc70af8SWarner Losh static int
net_match(struct netif * nif,void * machdep_hint)1969dc70af8SWarner Losh net_match(struct netif *nif, void *machdep_hint)
1979dc70af8SWarner Losh {
1989dc70af8SWarner Losh 	char **a = (char **)machdep_hint;
1999dc70af8SWarner Losh 
2009dc70af8SWarner Losh 	if (memcmp("net", *a, 3) == 0)
2019dc70af8SWarner Losh 		return (1);
2029dc70af8SWarner Losh 
2039dc70af8SWarner Losh 	printf("net_match: could not match network device\n");
2049dc70af8SWarner Losh 	return (0);
2059dc70af8SWarner Losh }
2069dc70af8SWarner Losh 
2079dc70af8SWarner Losh static int
net_probe(struct netif * nif,void * machdep_hint)2089dc70af8SWarner Losh net_probe(struct netif *nif, void *machdep_hint)
2099dc70af8SWarner Losh {
2109dc70af8SWarner Losh 	struct device_info *di;
2119dc70af8SWarner Losh 	int i;
2129dc70af8SWarner Losh 
2139dc70af8SWarner Losh 	for (i = 0; i < devs_no; i++)
2149dc70af8SWarner Losh 		if ((di = ub_dev_get(i)) != NULL)
2159dc70af8SWarner Losh 			if (di->type == DEV_TYP_NET)
2169dc70af8SWarner Losh 				break;
2179dc70af8SWarner Losh 
2189dc70af8SWarner Losh 	if (i == devs_no) {
2199dc70af8SWarner Losh 		printf("net_probe: no network devices found, maybe not"
2209dc70af8SWarner Losh 		    " enumerated yet..?\n");
2219dc70af8SWarner Losh 		return (-1);
2229dc70af8SWarner Losh 	}
2239dc70af8SWarner Losh 
2249dc70af8SWarner Losh #if defined(NETIF_DEBUG)
2259dc70af8SWarner Losh 	printf("net_probe: network device found: %d\n", i);
2269dc70af8SWarner Losh #endif
2279dc70af8SWarner Losh 	uboot_softc.sc_handle = i;
2289dc70af8SWarner Losh 
2299dc70af8SWarner Losh 	return (0);
2309dc70af8SWarner Losh }
2319dc70af8SWarner Losh 
2329dc70af8SWarner Losh static ssize_t
net_put(struct iodesc * desc,void * pkt,size_t len)2339dc70af8SWarner Losh net_put(struct iodesc *desc, void *pkt, size_t len)
2349dc70af8SWarner Losh {
2359dc70af8SWarner Losh 	struct netif *nif = desc->io_netif;
2369dc70af8SWarner Losh 	struct uboot_softc *sc = nif->nif_devdata;
2379dc70af8SWarner Losh 	size_t sendlen;
2389dc70af8SWarner Losh 	ssize_t rv;
2399dc70af8SWarner Losh 
2409dc70af8SWarner Losh #if defined(NETIF_DEBUG)
2419dc70af8SWarner Losh 	struct ether_header *eh;
2429dc70af8SWarner Losh 
2439dc70af8SWarner Losh 	printf("net_put: desc %p, pkt %p, len %d\n", desc, pkt, len);
2449dc70af8SWarner Losh 	eh = pkt;
2459dc70af8SWarner Losh 	printf("dst: %s ", ether_sprintf(eh->ether_dhost));
2469dc70af8SWarner Losh 	printf("src: %s ", ether_sprintf(eh->ether_shost));
2479dc70af8SWarner Losh 	printf("type: 0x%x\n", eh->ether_type & 0xffff);
2489dc70af8SWarner Losh #endif
2499dc70af8SWarner Losh 
2509dc70af8SWarner Losh 	if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
2519dc70af8SWarner Losh 		sendlen = ETHER_MIN_LEN - ETHER_CRC_LEN;
2529dc70af8SWarner Losh 		bzero(sc->sc_txbufp, sendlen);
2539dc70af8SWarner Losh 	} else
2549dc70af8SWarner Losh 		sendlen = len;
2559dc70af8SWarner Losh 
2569dc70af8SWarner Losh 	memcpy(sc->sc_txbufp, pkt, len);
2579dc70af8SWarner Losh 
2589dc70af8SWarner Losh 	rv = ub_dev_send(sc->sc_handle, sc->sc_txbufp, sendlen);
2599dc70af8SWarner Losh 
2609dc70af8SWarner Losh #if defined(NETIF_DEBUG)
2619dc70af8SWarner Losh 	printf("net_put: ub_send returned %d\n", rv);
2629dc70af8SWarner Losh #endif
2639dc70af8SWarner Losh 	if (rv == 0)
2649dc70af8SWarner Losh 		rv = len;
2659dc70af8SWarner Losh 	else
2669dc70af8SWarner Losh 		rv = -1;
2679dc70af8SWarner Losh 
2689dc70af8SWarner Losh 	return (rv);
2699dc70af8SWarner Losh }
2709dc70af8SWarner Losh 
2719dc70af8SWarner Losh static ssize_t
net_get(struct iodesc * desc,void ** pkt,time_t timeout)2729dc70af8SWarner Losh net_get(struct iodesc *desc, void **pkt, time_t timeout)
2739dc70af8SWarner Losh {
2749dc70af8SWarner Losh 	struct netif *nif = desc->io_netif;
2759dc70af8SWarner Losh 	struct uboot_softc *sc = nif->nif_devdata;
2769dc70af8SWarner Losh 	time_t t;
2779dc70af8SWarner Losh 	int err, rlen;
2789dc70af8SWarner Losh 	size_t len;
2799dc70af8SWarner Losh 	char *buf;
2809dc70af8SWarner Losh 
2819dc70af8SWarner Losh #if defined(NETIF_DEBUG)
2829dc70af8SWarner Losh 	printf("net_get: pkt %p, timeout %d\n", pkt, timeout);
2839dc70af8SWarner Losh #endif
2849dc70af8SWarner Losh 	t = getsecs();
2859dc70af8SWarner Losh 	len = sizeof(sc->sc_rxbuf);
2869dc70af8SWarner Losh 	do {
2879dc70af8SWarner Losh 		err = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len, &rlen);
2889dc70af8SWarner Losh 
2899dc70af8SWarner Losh 		if (err != 0) {
2909dc70af8SWarner Losh 			printf("net_get: ub_dev_recv() failed, error=%d\n",
2919dc70af8SWarner Losh 			    err);
2929dc70af8SWarner Losh 			rlen = 0;
2939dc70af8SWarner Losh 			break;
2949dc70af8SWarner Losh 		}
2959dc70af8SWarner Losh 	} while ((rlen == -1 || rlen == 0) && (getsecs() - t < timeout));
2969dc70af8SWarner Losh 
2979dc70af8SWarner Losh #if defined(NETIF_DEBUG)
2989dc70af8SWarner Losh 	printf("net_get: received len %d (%x)\n", rlen, rlen);
2999dc70af8SWarner Losh #endif
3009dc70af8SWarner Losh 
3019dc70af8SWarner Losh 	if (rlen > 0) {
3029dc70af8SWarner Losh 		buf = malloc(rlen + ETHER_ALIGN);
3039dc70af8SWarner Losh 		if (buf == NULL)
3049dc70af8SWarner Losh 			return (-1);
3059dc70af8SWarner Losh 		memcpy(buf + ETHER_ALIGN, sc->sc_rxbuf, rlen);
3069dc70af8SWarner Losh 		*pkt = buf;
3079dc70af8SWarner Losh 		return ((ssize_t)rlen);
3089dc70af8SWarner Losh 	}
3099dc70af8SWarner Losh 
3109dc70af8SWarner Losh 	return (-1);
3119dc70af8SWarner Losh }
3129dc70af8SWarner Losh 
3139dc70af8SWarner Losh static void
net_init(struct iodesc * desc,void * machdep_hint)3149dc70af8SWarner Losh net_init(struct iodesc *desc, void *machdep_hint)
3159dc70af8SWarner Losh {
3169dc70af8SWarner Losh 	struct netif *nif = desc->io_netif;
3179dc70af8SWarner Losh 	struct uboot_softc *sc;
3189dc70af8SWarner Losh 	struct device_info *di;
3199dc70af8SWarner Losh 	int err;
3209dc70af8SWarner Losh 
3219dc70af8SWarner Losh 	sc = nif->nif_devdata = &uboot_softc;
3229dc70af8SWarner Losh 
3239dc70af8SWarner Losh 	if ((err = ub_dev_open(sc->sc_handle)) != 0)
3249dc70af8SWarner Losh 		panic("%s%d: initialisation failed with error %d",
3259dc70af8SWarner Losh 		    nif->nif_driver->netif_bname, nif->nif_unit, err);
3269dc70af8SWarner Losh 
3279dc70af8SWarner Losh 	/* Get MAC address */
3289dc70af8SWarner Losh 	di = ub_dev_get(sc->sc_handle);
3299dc70af8SWarner Losh 	memcpy(desc->myea, di->di_net.hwaddr, 6);
3309dc70af8SWarner Losh 	if (memcmp (desc->myea, "\0\0\0\0\0\0", 6) == 0) {
3319dc70af8SWarner Losh 		panic("%s%d: empty ethernet address!",
3329dc70af8SWarner Losh 		    nif->nif_driver->netif_bname, nif->nif_unit);
3339dc70af8SWarner Losh 	}
3349dc70af8SWarner Losh 
3359dc70af8SWarner Losh 	/* Attempt to get netboot params from the u-boot env. */
3369dc70af8SWarner Losh 	get_env_net_params();
3379dc70af8SWarner Losh 	if (myip.s_addr != 0)
3389dc70af8SWarner Losh 		desc->myip = myip;
3399dc70af8SWarner Losh 
3409dc70af8SWarner Losh #if defined(NETIF_DEBUG)
3419dc70af8SWarner Losh 	printf("network: %s%d attached to %s\n", nif->nif_driver->netif_bname,
3429dc70af8SWarner Losh 	    nif->nif_unit, ether_sprintf(desc->myea));
3439dc70af8SWarner Losh #endif
3449dc70af8SWarner Losh 
3459dc70af8SWarner Losh 	/* Set correct alignment for TX packets */
3469dc70af8SWarner Losh 	sc->sc_txbufp = sc->sc_txbuf;
3479dc70af8SWarner Losh 	if ((unsigned long)sc->sc_txbufp % PKTALIGN)
3489dc70af8SWarner Losh 		sc->sc_txbufp += PKTALIGN -
3499dc70af8SWarner Losh 		    (unsigned long)sc->sc_txbufp % PKTALIGN;
3509dc70af8SWarner Losh }
3519dc70af8SWarner Losh 
3529dc70af8SWarner Losh static void
net_end(struct netif * nif)3539dc70af8SWarner Losh net_end(struct netif *nif)
3549dc70af8SWarner Losh {
3559dc70af8SWarner Losh 	struct uboot_softc *sc = nif->nif_devdata;
3569dc70af8SWarner Losh 	int err;
3579dc70af8SWarner Losh 
3589dc70af8SWarner Losh 	if ((err = ub_dev_close(sc->sc_handle)) != 0)
3599dc70af8SWarner Losh 		panic("%s%d: net_end failed with error %d",
3609dc70af8SWarner Losh 		    nif->nif_driver->netif_bname, nif->nif_unit, err);
3619dc70af8SWarner Losh }
362