1 /* $NetBSD: dev_net.c,v 1.27 2019/03/31 20:08:45 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Gordon W. Ross. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This module implements a "raw device" interface suitable for 34 * use by the stand-alone I/O library NFS code. This interface 35 * does not support any "block" access, and exists only for the 36 * purpose of initializing the network interface, getting boot 37 * parameters, and performing the NFS mount. 38 * 39 * At open time, this does: 40 * 41 * find interface - netif_open() 42 * RARP for IP address - rarp_getipaddress() 43 * RPC/bootparams - callrpc(d, RPC_BOOTPARAMS, ...) 44 * RPC/mountd - nfs_mount(sock, ip, path) 45 * 46 * the root file handle from mountd is saved in a global 47 * for use by the NFS open code (NFS/lookup). 48 */ 49 50 #include <sys/param.h> 51 #include <sys/socket.h> 52 #include <net/if.h> 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 56 #include <lib/libkern/libkern.h> 57 58 #include "stand.h" 59 #include "net.h" 60 #include "netif.h" 61 #include "nfs.h" 62 #include "bootparam.h" 63 #include "dev_net.h" 64 #ifdef SUPPORT_BOOTP 65 #include "bootp.h" 66 #endif 67 68 extern int nfs_root_node[]; /* XXX - get from nfs_mount() */ 69 70 static int netdev_sock = -1; 71 static int netdev_opens; 72 73 static int net_getparams(int); 74 75 /* 76 * Called by devopen after it sets f->f_dev to our devsw entry. 77 * This opens the low-level device and sets f->f_devdata. 78 * This is declared with variable arguments... 79 */ 80 int 81 net_open(struct open_file *f, ...) 82 { 83 va_list ap; 84 char *devname; /* Device part of file name (or NULL). */ 85 int error = 0; 86 87 va_start(ap, f); 88 devname = va_arg(ap, char *); 89 va_end(ap); 90 91 #ifdef NETIF_DEBUG 92 if (debug) 93 printf("%s\n", devname); 94 #endif 95 96 /* On first open, do netif open, mount, etc. */ 97 if (netdev_opens == 0) { 98 /* Find network interface. */ 99 if (netdev_sock < 0) { 100 netdev_sock = netif_open(devname); 101 if (netdev_sock < 0) { 102 printf("netif_open() failed\n"); 103 return ENXIO; 104 } 105 #ifdef NETIF_DEBUG 106 if (debug) 107 printf("netif_open() succeeded\n"); 108 #endif 109 } 110 if (rootip.s_addr == 0) { 111 /* Get root IP address, and path, etc. */ 112 error = net_getparams(netdev_sock); 113 if (error) { 114 /* getparams makes its own noise */ 115 goto fail; 116 } 117 /* Get the NFS file handle (mountd). */ 118 error = nfs_mount(netdev_sock, rootip, rootpath); 119 if (error) { 120 printf("NFS mount error=%d\n", errno); 121 rootip.s_addr = 0; 122 fail: 123 netif_close(netdev_sock); 124 netdev_sock = -1; 125 return error; 126 } 127 #ifdef NETIF_DEBUG 128 if (debug) 129 printf("NFS mount succeeded\n"); 130 #endif 131 } 132 } 133 netdev_opens++; 134 f->f_devdata = nfs_root_node; 135 return error; 136 } 137 138 int 139 net_close(struct open_file *f) 140 { 141 142 #ifdef NETIF_DEBUG 143 if (debug) 144 printf("net_close: opens=%d\n", netdev_opens); 145 #endif 146 147 /* On last close, do netif close, etc. */ 148 f->f_devdata = NULL; 149 /* Extra close call? */ 150 if (netdev_opens <= 0) 151 return 0; 152 netdev_opens--; 153 /* Not last close? */ 154 if (netdev_opens > 0) 155 return 0; 156 rootip.s_addr = 0; 157 if (netdev_sock >= 0) { 158 #ifdef NETIF_DEBUG 159 if (debug) 160 printf("%s: calling netif_close()\n", __func__); 161 #endif 162 netif_close(netdev_sock); 163 netdev_sock = -1; 164 } 165 return 0; 166 } 167 168 int 169 net_ioctl(struct open_file *f, u_long cmd, void *data) 170 { 171 172 return EIO; 173 } 174 175 int 176 net_strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 177 size_t *rsize) 178 { 179 180 return EIO; 181 } 182 183 184 /* 185 * Get info for NFS boot: our IP address, our hostname, 186 * server IP address, and our root path on the server. 187 * There are two ways to do this: The old, Sun way, 188 * and the more modern, BOOTP way. (RFC951, RFC1048) 189 * 190 * The default is to use the Sun bootparams RPC 191 * (because that is what the kernel will do). 192 * MD code can make try_bootp initialied data, 193 * which will override this common definition. 194 */ 195 #ifdef SUPPORT_BOOTP 196 int try_bootp; 197 #endif 198 199 static int 200 net_getparams(int sock) 201 { 202 char buf[MAXHOSTNAMELEN]; 203 n_long smask; 204 205 #ifdef SUPPORT_BOOTP 206 /* 207 * Try to get boot info using BOOTP. If we succeed, then 208 * the server IP address, gateway, and root path will all 209 * be initialized. If any remain uninitialized, we will 210 * use RARP and RPC/bootparam (the Sun way) to get them. 211 */ 212 if (try_bootp) 213 bootp(sock); 214 if (myip.s_addr != 0) 215 return 0; 216 #ifdef NETIF_DEBUG 217 if (debug) 218 printf("BOOTP failed, trying RARP/RPC...\n"); 219 #endif 220 #endif 221 222 /* 223 * Use RARP to get our IP address. This also sets our 224 * netmask to the "natural" default for our address. 225 */ 226 if (rarp_getipaddress(sock)) { 227 printf("RARP failed\n"); 228 return EIO; 229 } 230 #ifdef NETIF_DEBUG 231 if (debug) 232 printf("client addr: %s\n", inet_ntoa(myip)); 233 #endif 234 235 /* Get our hostname, server IP address, gateway. */ 236 if (bp_whoami(sock)) { 237 printf("bootparam/whoami RPC failed\n"); 238 return EIO; 239 } 240 #ifdef NETIF_DEBUG 241 if (debug) 242 printf("client name: %s\n", hostname); 243 #endif 244 245 /* 246 * Ignore the gateway from whoami (unreliable). 247 * Use the "gateway" parameter instead. 248 */ 249 smask = 0; 250 gateip.s_addr = 0; 251 if (bp_getfile(sock, "gateway", &gateip, buf)) { 252 printf("%s: gateway bootparam missing\n", __func__); 253 } else { 254 /* Got it! Parse the netmask. */ 255 smask = inet_addr(buf); 256 } 257 if (smask) { 258 netmask = smask; 259 #ifdef NETIF_DEBUG 260 if (debug) 261 printf("subnet mask: %s\n", intoa(netmask)); 262 #endif 263 } 264 #ifdef NETIF_DEBUG 265 if (debug) 266 if (gateip.s_addr) 267 printf("net gateway: %s\n", inet_ntoa(gateip)); 268 #endif 269 270 /* Get the root server and pathname. */ 271 if (bp_getfile(sock, "root", &rootip, rootpath)) { 272 printf("bootparam/getfile RPC failed\n"); 273 return EIO; 274 } 275 276 #ifdef NETIF_DEBUG 277 if (debug) { 278 printf("server addr: %s\n", inet_ntoa(rootip)); 279 printf("server path: %s\n", rootpath); 280 } 281 #endif 282 283 return 0; 284 } 285