dev_net.c revision 301056
1/* $NetBSD: dev_net.c,v 1.23 2008/04/28 20:24:06 martin 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#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: stable/10/sys/boot/common/dev_net.c 301056 2016-05-31 17:01:54Z ian $"); 34 35/*- 36 * This module implements a "raw device" interface suitable for 37 * use by the stand-alone I/O library NFS code. This interface 38 * does not support any "block" access, and exists only for the 39 * purpose of initializing the network interface, getting boot 40 * parameters, and performing the NFS mount. 41 * 42 * At open time, this does: 43 * 44 * find interface - netif_open() 45 * RARP for IP address - rarp_getipaddress() 46 * RPC/bootparams - callrpc(d, RPC_BOOTPARAMS, ...) 47 * RPC/mountd - nfs_mount(sock, ip, path) 48 * 49 * the root file handle from mountd is saved in a global 50 * for use by the NFS open code (NFS/lookup). 51 */ 52 53#include <machine/stdarg.h> 54#include <sys/param.h> 55#include <sys/socket.h> 56#include <net/if.h> 57#include <netinet/in.h> 58#include <netinet/in_systm.h> 59 60#include <stand.h> 61#include <string.h> 62#include <net.h> 63#include <netif.h> 64#include <bootp.h> 65#include <bootparam.h> 66 67#include "dev_net.h" 68#include "bootstrap.h" 69 70#ifdef NETIF_DEBUG 71int debug = 0; 72#endif 73 74static char *netdev_name; 75static int netdev_sock = -1; 76static int netdev_opens; 77 78static int net_init(void); 79static int net_open(struct open_file *, ...); 80static int net_close(struct open_file *); 81static void net_cleanup(void); 82static int net_strategy(); 83static void net_print(int); 84 85static int net_getparams(int sock); 86 87struct devsw netdev = { 88 "net", 89 DEVT_NET, 90 net_init, 91 net_strategy, 92 net_open, 93 net_close, 94 noioctl, 95 net_print, 96 net_cleanup 97}; 98 99static int 100net_init(void) 101{ 102 103 return (0); 104} 105 106/* 107 * Called by devopen after it sets f->f_dev to our devsw entry. 108 * This opens the low-level device and sets f->f_devdata. 109 * This is declared with variable arguments... 110 */ 111static int 112net_open(struct open_file *f, ...) 113{ 114 char temp[FNAME_SIZE]; 115 struct iodesc *d; 116 va_list args; 117 char *devname; /* Device part of file name (or NULL). */ 118 int error = 0; 119 120 va_start(args, f); 121 devname = va_arg(args, char*); 122 va_end(args); 123 124#ifdef NETIF_OPEN_CLOSE_ONCE 125 /* Before opening another interface, close the previous one first. */ 126 if (netdev_sock >= 0 && strcmp(devname, netdev_name) != 0) 127 net_cleanup(); 128#endif 129 130 /* On first open, do netif open, mount, etc. */ 131 if (netdev_opens == 0) { 132 /* Find network interface. */ 133 if (netdev_sock < 0) { 134 netdev_sock = netif_open(devname); 135 if (netdev_sock < 0) { 136 printf("net_open: netif_open() failed\n"); 137 return (ENXIO); 138 } 139 netdev_name = strdup(devname); 140#ifdef NETIF_DEBUG 141 if (debug) 142 printf("net_open: netif_open() succeeded\n"); 143#endif 144 } 145 /* 146 * If network params were not set by netif_open(), try to get 147 * them via bootp, rarp, etc. 148 */ 149 if (rootip.s_addr == 0) { 150 /* Get root IP address, and path, etc. */ 151 error = net_getparams(netdev_sock); 152 if (error) { 153 /* getparams makes its own noise */ 154 free(netdev_name); 155 netif_close(netdev_sock); 156 netdev_sock = -1; 157 return (error); 158 } 159 } 160 /* 161 * Set the variables required by the kernel's nfs_diskless 162 * mechanism. This is the minimum set of variables required to 163 * mount a root filesystem without needing to obtain additional 164 * info from bootp or other sources. 165 */ 166 d = socktodesc(netdev_sock); 167 sprintf(temp, "%6D", d->myea, ":"); 168 setenv("boot.netif.hwaddr", temp, 1); 169 setenv("boot.netif.ip", inet_ntoa(myip), 1); 170 setenv("boot.netif.netmask", intoa(netmask), 1); 171 setenv("boot.netif.gateway", inet_ntoa(gateip), 1); 172 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 173 setenv("boot.nfsroot.path", rootpath, 1); 174 if (intf_mtu != 0) { 175 char mtu[16]; 176 sprintf(mtu, "%u", intf_mtu); 177 setenv("boot.netif.mtu", mtu, 1); 178 } 179 180 } 181 netdev_opens++; 182 f->f_devdata = &netdev_sock; 183 return (error); 184} 185 186static int 187net_close(struct open_file *f) 188{ 189 190#ifdef NETIF_DEBUG 191 if (debug) 192 printf("net_close: opens=%d\n", netdev_opens); 193#endif 194 195 f->f_devdata = NULL; 196 197#ifndef NETIF_OPEN_CLOSE_ONCE 198 /* Extra close call? */ 199 if (netdev_opens <= 0) 200 return (0); 201 netdev_opens--; 202 /* Not last close? */ 203 if (netdev_opens > 0) 204 return (0); 205 /* On last close, do netif close, etc. */ 206#ifdef NETIF_DEBUG 207 if (debug) 208 printf("net_close: calling net_cleanup()\n"); 209#endif 210 net_cleanup(); 211#endif 212 return (0); 213} 214 215static void 216net_cleanup(void) 217{ 218 219 if (netdev_sock >= 0) { 220#ifdef NETIF_DEBUG 221 if (debug) 222 printf("net_cleanup: calling netif_close()\n"); 223#endif 224 rootip.s_addr = 0; 225 free(netdev_name); 226 netif_close(netdev_sock); 227 netdev_sock = -1; 228 } 229} 230 231static int 232net_strategy() 233{ 234 235 return (EIO); 236} 237 238#define SUPPORT_BOOTP 239 240/* 241 * Get info for NFS boot: our IP address, our hostname, 242 * server IP address, and our root path on the server. 243 * There are two ways to do this: The old, Sun way, 244 * and the more modern, BOOTP way. (RFC951, RFC1048) 245 * 246 * The default is to use the Sun bootparams RPC 247 * (because that is what the kernel will do). 248 * MD code can make try_bootp initialied data, 249 * which will override this common definition. 250 */ 251#ifdef SUPPORT_BOOTP 252int try_bootp = 1; 253#endif 254 255extern n_long ip_convertaddr(char *p); 256 257static int 258net_getparams(int sock) 259{ 260 char buf[MAXHOSTNAMELEN]; 261 n_long rootaddr, smask; 262 263#ifdef SUPPORT_BOOTP 264 /* 265 * Try to get boot info using BOOTP. If we succeed, then 266 * the server IP address, gateway, and root path will all 267 * be initialized. If any remain uninitialized, we will 268 * use RARP and RPC/bootparam (the Sun way) to get them. 269 */ 270 if (try_bootp) 271 bootp(sock, BOOTP_NONE); 272 if (myip.s_addr != 0) 273 goto exit; 274#ifdef NETIF_DEBUG 275 if (debug) 276 printf("net_open: BOOTP failed, trying RARP/RPC...\n"); 277#endif 278#endif 279 280 /* 281 * Use RARP to get our IP address. This also sets our 282 * netmask to the "natural" default for our address. 283 */ 284 if (rarp_getipaddress(sock)) { 285 printf("net_open: RARP failed\n"); 286 return (EIO); 287 } 288 printf("net_open: client addr: %s\n", inet_ntoa(myip)); 289 290 /* Get our hostname, server IP address, gateway. */ 291 if (bp_whoami(sock)) { 292 printf("net_open: bootparam/whoami RPC failed\n"); 293 return (EIO); 294 } 295#ifdef NETIF_DEBUG 296 if (debug) 297 printf("net_open: client name: %s\n", hostname); 298#endif 299 300 /* 301 * Ignore the gateway from whoami (unreliable). 302 * Use the "gateway" parameter instead. 303 */ 304 smask = 0; 305 gateip.s_addr = 0; 306 if (bp_getfile(sock, "gateway", &gateip, buf) == 0) { 307 /* Got it! Parse the netmask. */ 308 smask = ip_convertaddr(buf); 309 } 310 if (smask) { 311 netmask = smask; 312#ifdef NETIF_DEBUG 313 if (debug) 314 printf("net_open: subnet mask: %s\n", intoa(netmask)); 315#endif 316 } 317#ifdef NETIF_DEBUG 318 if (gateip.s_addr && debug) 319 printf("net_open: net gateway: %s\n", inet_ntoa(gateip)); 320#endif 321 322 /* Get the root server and pathname. */ 323 if (bp_getfile(sock, "root", &rootip, rootpath)) { 324 printf("net_open: bootparam/getfile RPC failed\n"); 325 return (EIO); 326 } 327exit: 328 if ((rootaddr = net_parse_rootpath()) != INADDR_NONE) 329 rootip.s_addr = rootaddr; 330 331#ifdef NETIF_DEBUG 332 if (debug) { 333 printf("net_open: server addr: %s\n", inet_ntoa(rootip)); 334 printf("net_open: server path: %s\n", rootpath); 335 } 336#endif 337 338 return (0); 339} 340 341static void 342net_print(int verbose) 343{ 344 struct netif_driver *drv; 345 int i, d, cnt; 346 347 cnt = 0; 348 for (d = 0; netif_drivers[d]; d++) { 349 drv = netif_drivers[d]; 350 for (i = 0; i < drv->netif_nifs; i++) { 351 printf("\t%s%d:", "net", cnt++); 352 if (verbose) 353 printf(" (%s%d)", drv->netif_bname, 354 drv->netif_ifs[i].dif_unit); 355 } 356 } 357 printf("\n"); 358} 359 360/* 361 * Strip the server's address off of the rootpath if present and return it in 362 * network byte order, leaving just the pathname part in the global rootpath. 363 */ 364uint32_t 365net_parse_rootpath() 366{ 367 int i; 368 n_long addr = INADDR_NONE; 369 370 for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) 371 if (rootpath[i] == ':') 372 break; 373 if (i && i != FNAME_SIZE && rootpath[i] == ':') { 374 rootpath[i++] = '\0'; 375 addr = inet_addr(&rootpath[0]); 376 bcopy(&rootpath[i], rootpath, strlen(&rootpath[i])+1); 377 } 378 return (addr); 379} 380