1201901Smarius/*	$NetBSD: dev_net.c,v 1.23 2008/04/28 20:24:06 martin Exp $	*/
238465Smsmith
338465Smsmith/*-
438465Smsmith * Copyright (c) 1997 The NetBSD Foundation, Inc.
538465Smsmith * All rights reserved.
638465Smsmith *
738465Smsmith * This code is derived from software contributed to The NetBSD Foundation
838465Smsmith * by Gordon W. Ross.
938465Smsmith *
1038465Smsmith * Redistribution and use in source and binary forms, with or without
1138465Smsmith * modification, are permitted provided that the following conditions
1238465Smsmith * are met:
1338465Smsmith * 1. Redistributions of source code must retain the above copyright
1438465Smsmith *    notice, this list of conditions and the following disclaimer.
1538465Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1638465Smsmith *    notice, this list of conditions and the following disclaimer in the
1738465Smsmith *    documentation and/or other materials provided with the distribution.
1838465Smsmith *
1938465Smsmith * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2038465Smsmith * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2138465Smsmith * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2238465Smsmith * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2338465Smsmith * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2438465Smsmith * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2538465Smsmith * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2638465Smsmith * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2738465Smsmith * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2838465Smsmith * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2938465Smsmith * POSSIBILITY OF SUCH DAMAGE.
3038465Smsmith */
3138465Smsmith
32119483Sobrien#include <sys/cdefs.h>
33119483Sobrien__FBSDID("$FreeBSD$");
34119483Sobrien
35119483Sobrien/*-
3638465Smsmith * This module implements a "raw device" interface suitable for
3738465Smsmith * use by the stand-alone I/O library NFS code.  This interface
3838465Smsmith * does not support any "block" access, and exists only for the
3938465Smsmith * purpose of initializing the network interface, getting boot
4038465Smsmith * parameters, and performing the NFS mount.
4138465Smsmith *
4238465Smsmith * At open time, this does:
4338465Smsmith *
4438465Smsmith * find interface      - netif_open()
4538465Smsmith * RARP for IP address - rarp_getipaddress()
4638465Smsmith * RPC/bootparams      - callrpc(d, RPC_BOOTPARAMS, ...)
4738465Smsmith * RPC/mountd          - nfs_mount(sock, ip, path)
4838465Smsmith *
4938465Smsmith * the root file handle from mountd is saved in a global
5038465Smsmith * for use by the NFS open code (NFS/lookup).
5138465Smsmith */
5238465Smsmith
5338465Smsmith#include <machine/stdarg.h>
5438465Smsmith#include <sys/param.h>
5538465Smsmith#include <sys/socket.h>
5638465Smsmith#include <net/if.h>
5738465Smsmith#include <netinet/in.h>
5838465Smsmith#include <netinet/in_systm.h>
5938465Smsmith
6038465Smsmith#include <stand.h>
6146356Sdfr#include <string.h>
6238465Smsmith#include <net.h>
6338465Smsmith#include <netif.h>
6464527Sps#include <bootp.h>
6538465Smsmith#include <bootparam.h>
6638465Smsmith
6738465Smsmith#include "dev_net.h"
6838465Smsmith#include "bootstrap.h"
6938465Smsmith
70200945Smarius#ifdef	NETIF_DEBUG
7138465Smsmithint debug = 0;
72200945Smarius#endif
7338465Smsmith
74201932Smariusstatic char *netdev_name;
7538465Smsmithstatic int netdev_sock = -1;
7638465Smsmithstatic int netdev_opens;
7738465Smsmith
7838465Smsmithstatic int	net_init(void);
7950737Sdfrstatic int	net_open(struct open_file *, ...);
8038465Smsmithstatic int	net_close(struct open_file *);
81201932Smariusstatic void	net_cleanup(void);
8238465Smsmithstatic int	net_strategy();
8368547Sbennostatic void	net_print(int);
8438465Smsmith
8538465Smsmithstatic int net_getparams(int sock);
8638465Smsmith
8738465Smsmithstruct devsw netdev = {
88182731Sraj	"net",
89182731Sraj	DEVT_NET,
90182731Sraj	net_init,
91182731Sraj	net_strategy,
92182731Sraj	net_open,
93182731Sraj	net_close,
94182731Sraj	noioctl,
95201932Smarius	net_print,
96201932Smarius	net_cleanup
9738465Smsmith};
9838465Smsmith
99200945Smariusstatic int
10038465Smsmithnet_init(void)
10138465Smsmith{
102182731Sraj
103182731Sraj	return (0);
10438465Smsmith}
10538465Smsmith
10638465Smsmith/*
10738465Smsmith * Called by devopen after it sets f->f_dev to our devsw entry.
10838465Smsmith * This opens the low-level device and sets f->f_devdata.
10938465Smsmith * This is declared with variable arguments...
11038465Smsmith */
111200945Smariusstatic int
11250737Sdfrnet_open(struct open_file *f, ...)
11338465Smsmith{
114182731Sraj	va_list args;
115182731Sraj	char *devname;		/* Device part of file name (or NULL). */
116182731Sraj	int error = 0;
11738465Smsmith
118182731Sraj	va_start(args, f);
119182731Sraj	devname = va_arg(args, char*);
120182731Sraj	va_end(args);
12138465Smsmith
122201932Smarius#ifdef	NETIF_OPEN_CLOSE_ONCE
123201932Smarius	/* Before opening another interface, close the previous one first. */
124201932Smarius	if (netdev_sock >= 0 && strcmp(devname, netdev_name) != 0)
125201932Smarius		net_cleanup();
126201932Smarius#endif
127201932Smarius
128182731Sraj	/* On first open, do netif open, mount, etc. */
129182731Sraj	if (netdev_opens == 0) {
130182731Sraj		/* Find network interface. */
131182731Sraj		if (netdev_sock < 0) {
132182731Sraj			netdev_sock = netif_open(devname);
133182731Sraj			if (netdev_sock < 0) {
134182731Sraj				printf("net_open: netif_open() failed\n");
135182731Sraj				return (ENXIO);
136182731Sraj			}
137201932Smarius			netdev_name = strdup(devname);
138200945Smarius#ifdef	NETIF_DEBUG
139182731Sraj			if (debug)
140200945Smarius				printf("net_open: netif_open() succeeded\n");
141200945Smarius#endif
142182731Sraj		}
143182731Sraj		if (rootip.s_addr == 0) {
144182731Sraj			/* Get root IP address, and path, etc. */
145182731Sraj			error = net_getparams(netdev_sock);
146182731Sraj			if (error) {
14738465Smsmith				/* getparams makes its own noise */
148201932Smarius				free(netdev_name);
149182731Sraj				netif_close(netdev_sock);
150182731Sraj				netdev_sock = -1;
151182731Sraj				return (error);
152182731Sraj			}
153182731Sraj		}
15438465Smsmith	}
155182731Sraj	netdev_opens++;
156182731Sraj	f->f_devdata = &netdev_sock;
157182731Sraj	return (error);
15838465Smsmith}
15938465Smsmith
160200945Smariusstatic int
161182731Srajnet_close(struct open_file *f)
16238465Smsmith{
163201932Smarius
16438465Smsmith#ifdef	NETIF_DEBUG
165182731Sraj	if (debug)
166182731Sraj		printf("net_close: opens=%d\n", netdev_opens);
16738465Smsmith#endif
16838465Smsmith
169182731Sraj	f->f_devdata = NULL;
170201932Smarius
171201932Smarius#ifndef	NETIF_OPEN_CLOSE_ONCE
172182731Sraj	/* Extra close call? */
173182731Sraj	if (netdev_opens <= 0)
174182731Sraj		return (0);
175182731Sraj	netdev_opens--;
176182731Sraj	/* Not last close? */
177182731Sraj	if (netdev_opens > 0)
178201932Smarius		return (0);
179201932Smarius	/* On last close, do netif close, etc. */
180201932Smarius#ifdef	NETIF_DEBUG
181201932Smarius	if (debug)
182201932Smarius		printf("net_close: calling net_cleanup()\n");
183201932Smarius#endif
184201932Smarius	net_cleanup();
185201932Smarius#endif
186201932Smarius	return (0);
187201932Smarius}
188201932Smarius
189201932Smariusstatic void
190201932Smariusnet_cleanup(void)
191201932Smarius{
192201932Smarius
193182731Sraj	if (netdev_sock >= 0) {
194200945Smarius#ifdef	NETIF_DEBUG
195182731Sraj		if (debug)
196201932Smarius			printf("net_cleanup: calling netif_close()\n");
197200945Smarius#endif
198201932Smarius		rootip.s_addr = 0;
199201932Smarius		free(netdev_name);
200182731Sraj		netif_close(netdev_sock);
201182731Sraj		netdev_sock = -1;
202182731Sraj	}
20338465Smsmith}
20438465Smsmith
205200945Smariusstatic int
20638465Smsmithnet_strategy()
20738465Smsmith{
208182731Sraj
209182731Sraj	return (EIO);
21038465Smsmith}
21138465Smsmith
21238465Smsmith#define SUPPORT_BOOTP
21338465Smsmith
21438465Smsmith/*
21538465Smsmith * Get info for NFS boot: our IP address, our hostname,
21638465Smsmith * server IP address, and our root path on the server.
21738465Smsmith * There are two ways to do this:  The old, Sun way,
21838465Smsmith * and the more modern, BOOTP way. (RFC951, RFC1048)
21938465Smsmith *
22038465Smsmith * The default is to use the Sun bootparams RPC
22138465Smsmith * (because that is what the kernel will do).
22238465Smsmith * MD code can make try_bootp initialied data,
22338465Smsmith * which will override this common definition.
22438465Smsmith */
22538465Smsmith#ifdef	SUPPORT_BOOTP
22638465Smsmithint try_bootp = 1;
22738465Smsmith#endif
22838465Smsmith
22950737Sdfrextern n_long ip_convertaddr(char *p);
23050737Sdfr
23138465Smsmithstatic int
232182731Srajnet_getparams(int sock)
23338465Smsmith{
234182731Sraj	char buf[MAXHOSTNAMELEN];
235182731Sraj	char temp[FNAME_SIZE];
236182731Sraj	struct iodesc *d;
237182731Sraj	int i;
238182731Sraj	n_long smask;
23938465Smsmith
24038465Smsmith#ifdef	SUPPORT_BOOTP
241182731Sraj	/*
242182731Sraj	 * Try to get boot info using BOOTP.  If we succeed, then
243182731Sraj	 * the server IP address, gateway, and root path will all
244182731Sraj	 * be initialized.  If any remain uninitialized, we will
245182731Sraj	 * use RARP and RPC/bootparam (the Sun way) to get them.
246182731Sraj	 */
247182731Sraj	if (try_bootp)
248182731Sraj		bootp(sock, BOOTP_NONE);
249182731Sraj	if (myip.s_addr != 0)
250182731Sraj		goto exit;
251200945Smarius#ifdef	NETIF_DEBUG
252182731Sraj	if (debug)
253182731Sraj		printf("net_open: BOOTP failed, trying RARP/RPC...\n");
25438465Smsmith#endif
255200945Smarius#endif
25638465Smsmith
257182731Sraj	/*
258182731Sraj	 * Use RARP to get our IP address.  This also sets our
259182731Sraj	 * netmask to the "natural" default for our address.
260182731Sraj	 */
261182731Sraj	if (rarp_getipaddress(sock)) {
262182731Sraj		printf("net_open: RARP failed\n");
263182731Sraj		return (EIO);
264182731Sraj	}
265182731Sraj	printf("net_open: client addr: %s\n", inet_ntoa(myip));
26638465Smsmith
267182731Sraj	/* Get our hostname, server IP address, gateway. */
268182731Sraj	if (bp_whoami(sock)) {
269182731Sraj		printf("net_open: bootparam/whoami RPC failed\n");
270182731Sraj		return (EIO);
271182731Sraj	}
272200945Smarius#ifdef	NETIF_DEBUG
273182731Sraj	if (debug)
274182731Sraj		printf("net_open: client name: %s\n", hostname);
275200945Smarius#endif
27638465Smsmith
277182731Sraj	/*
278182731Sraj	 * Ignore the gateway from whoami (unreliable).
279182731Sraj	 * Use the "gateway" parameter instead.
280182731Sraj	 */
281182731Sraj	smask = 0;
282182731Sraj	gateip.s_addr = 0;
283182731Sraj	if (bp_getfile(sock, "gateway", &gateip, buf) == 0) {
284182731Sraj		/* Got it!  Parse the netmask. */
285182731Sraj		smask = ip_convertaddr(buf);
286182731Sraj	}
287182731Sraj	if (smask) {
288182731Sraj		netmask = smask;
289200945Smarius#ifdef	NETIF_DEBUG
290182731Sraj		if (debug)
291200945Smarius			printf("net_open: subnet mask: %s\n", intoa(netmask));
292200945Smarius#endif
293182731Sraj	}
294200945Smarius#ifdef	NETIF_DEBUG
295182731Sraj	if (gateip.s_addr && debug)
296182731Sraj		printf("net_open: net gateway: %s\n", inet_ntoa(gateip));
297200945Smarius#endif
29838465Smsmith
299182731Sraj	/* Get the root server and pathname. */
300182731Sraj	if (bp_getfile(sock, "root", &rootip, rootpath)) {
301182731Sraj		printf("net_open: bootparam/getfile RPC failed\n");
302182731Sraj		return (EIO);
303182731Sraj	}
304182731Srajexit:
305182731Sraj	/*
306182731Sraj	 * If present, strip the server's address off of the rootpath
307182731Sraj	 * before passing it along.  This allows us to be compatible with
308182731Sraj	 * the kernel's diskless (BOOTP_NFSROOT) booting conventions
309182731Sraj	 */
310182731Sraj	for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
311182731Sraj		if (rootpath[i] == ':')
312182731Sraj			break;
313182731Sraj	if (i && i != FNAME_SIZE && rootpath[i] == ':') {
314182731Sraj		rootpath[i++] = '\0';
315182731Sraj		if (inet_addr(&rootpath[0]) != INADDR_NONE)
316182731Sraj			rootip.s_addr = inet_addr(&rootpath[0]);
317182731Sraj		bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1);
318182731Sraj		bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1);
319182731Sraj	}
320200945Smarius#ifdef	NETIF_DEBUG
321182731Sraj	if (debug) {
322182731Sraj		printf("net_open: server addr: %s\n", inet_ntoa(rootip));
323182731Sraj		printf("net_open: server path: %s\n", rootpath);
324182731Sraj	}
325200945Smarius#endif
326101112Sjake
327182731Sraj	d = socktodesc(sock);
328182731Sraj	sprintf(temp, "%6D", d->myea, ":");
329182731Sraj	setenv("boot.netif.ip", inet_ntoa(myip), 1);
330182731Sraj	setenv("boot.netif.netmask", intoa(netmask), 1);
331182731Sraj	setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
332182731Sraj	setenv("boot.netif.hwaddr", temp, 1);
333182731Sraj	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
334182731Sraj	setenv("boot.nfsroot.path", rootpath, 1);
335101112Sjake
336182731Sraj	return (0);
33738465Smsmith}
33868547Sbenno
33968547Sbennostatic void
34068547Sbennonet_print(int verbose)
34168547Sbenno{
342182731Sraj	struct netif_driver *drv;
343182731Sraj	int i, d, cnt;
344182731Sraj
345182731Sraj	cnt = 0;
346182731Sraj	for (d = 0; netif_drivers[d]; d++) {
347182731Sraj		drv = netif_drivers[d];
348182731Sraj		for (i = 0; i < drv->netif_nifs; i++) {
349182731Sraj			printf("\t%s%d:", "net", cnt++);
350182731Sraj			if (verbose)
351182731Sraj				printf(" (%s%d)", drv->netif_bname,
352182731Sraj				    drv->netif_ifs[i].dif_unit);
353182731Sraj		}
354182731Sraj	}
355182731Sraj	printf("\n");
35668547Sbenno}
357