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