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