- Add support for attaching alternative DLTs to an interface.
[dragonfly.git] / sys / boot / common / dev_net.c
1 /*      
2  * $NetBSD: dev_net.c,v 1.12 1997/12/10 20:38:37 gwr 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  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *        This product includes software developed by the NetBSD
23  *        Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * $FreeBSD: src/sys/boot/common/dev_net.c,v 1.13 2003/11/03 19:45:05 iedowse Exp $
41  * $DragonFly: src/sys/boot/common/dev_net.c,v 1.4 2003/11/10 06:08:31 dillon Exp $
42  */
43
44 /*-
45  * This module implements a "raw device" interface suitable for
46  * use by the stand-alone I/O library NFS code.  This interface
47  * does not support any "block" access, and exists only for the
48  * purpose of initializing the network interface, getting boot
49  * parameters, and performing the NFS mount.
50  *
51  * At open time, this does:
52  *
53  * find interface      - netif_open()
54  * RARP for IP address - rarp_getipaddress()
55  * RPC/bootparams      - callrpc(d, RPC_BOOTPARAMS, ...)
56  * RPC/mountd          - nfs_mount(sock, ip, path)
57  *
58  * the root file handle from mountd is saved in a global
59  * for use by the NFS open code (NFS/lookup).
60  */
61
62 #include <machine/stdarg.h>
63 #include <sys/param.h>
64 #include <sys/socket.h>
65 #include <net/if.h>
66 #include <netinet/in.h>
67 #include <netinet/in_systm.h>
68
69 #include <stand.h>
70 #include <string.h>
71 #include <net.h>
72 #include <netif.h>
73 #include <bootp.h>
74 #include <bootparam.h>
75
76 #include "dev_net.h"
77 #include "bootstrap.h"
78
79 int debug = 0;
80
81 static int netdev_sock = -1;
82 static int netdev_opens;
83
84 static int      net_init(void);
85 static int      net_open(struct open_file *, ...);
86 static int      net_close(struct open_file *);
87 static int      net_strategy();
88 static void     net_print(int);
89
90 static int net_getparams(int sock);
91
92 struct devsw netdev = {
93     "net", 
94     DEVT_NET, 
95     net_init,
96     net_strategy, 
97     net_open, 
98     net_close, 
99     noioctl,
100     net_print
101 };
102
103 int
104 net_init(void)
105 {
106     return 0;
107 }
108
109 /*
110  * Called by devopen after it sets f->f_dev to our devsw entry.
111  * This opens the low-level device and sets f->f_devdata.
112  * This is declared with variable arguments...
113  */
114 int
115 net_open(struct open_file *f, ...)
116 {
117     va_list args;
118     char *devname;              /* Device part of file name (or NULL). */
119     int error = 0;
120
121     va_start(args, f);
122     devname = va_arg(args, char*);
123     va_end(args);
124
125     /* On first open, do netif open, mount, etc. */
126     if (netdev_opens == 0) {
127         /* Find network interface. */
128         if (netdev_sock < 0) {
129             netdev_sock = netif_open(devname);
130             if (netdev_sock < 0) {
131                 printf("net_open: netif_open() failed\n");
132                 return (ENXIO);
133             }
134             if (debug)
135                 printf("net_open: netif_open() succeeded\n");
136         }
137         if (rootip.s_addr == 0) {
138             /* Get root IP address, and path, etc. */
139             error = net_getparams(netdev_sock);
140             if (error) {
141                                 /* getparams makes its own noise */
142                 netif_close(netdev_sock);
143                 netdev_sock = -1;
144                 return (error);
145             }
146         }
147         netdev_opens++;
148     }
149     netdev_opens++;
150     f->f_devdata = &netdev_sock;
151     return (error);
152 }
153
154 int
155 net_close(f)
156     struct open_file *f;
157 {
158
159 #ifdef  NETIF_DEBUG
160     if (debug)
161         printf("net_close: opens=%d\n", netdev_opens);
162 #endif
163
164     /* On last close, do netif close, etc. */
165     f->f_devdata = NULL;
166     /* Extra close call? */
167     if (netdev_opens <= 0)
168         return (0);
169     netdev_opens--;
170     /* Not last close? */
171     if (netdev_opens > 0)
172         return(0);
173     rootip.s_addr = 0;
174     if (netdev_sock >= 0) {
175         if (debug)
176             printf("net_close: calling netif_close()\n");
177         netif_close(netdev_sock);
178         netdev_sock = -1;
179     }
180     return (0);
181 }
182
183 int
184 net_strategy()
185 {
186     return EIO;
187 }
188
189 #define SUPPORT_BOOTP
190
191 /*
192  * Get info for NFS boot: our IP address, our hostname,
193  * server IP address, and our root path on the server.
194  * There are two ways to do this:  The old, Sun way,
195  * and the more modern, BOOTP way. (RFC951, RFC1048)
196  *
197  * The default is to use the Sun bootparams RPC
198  * (because that is what the kernel will do).
199  * MD code can make try_bootp initialied data,
200  * which will override this common definition.
201  */
202 #ifdef  SUPPORT_BOOTP
203 int try_bootp = 1;
204 #endif
205
206 extern n_long ip_convertaddr(char *p);
207
208 static int
209 net_getparams(sock)
210     int sock;
211 {
212     char buf[MAXHOSTNAMELEN];
213     char temp[FNAME_SIZE];
214     struct iodesc *d;
215     int i;
216     n_long smask;
217
218 #ifdef  SUPPORT_BOOTP
219     /*
220      * Try to get boot info using BOOTP.  If we succeed, then
221      * the server IP address, gateway, and root path will all
222      * be initialized.  If any remain uninitialized, we will
223      * use RARP and RPC/bootparam (the Sun way) to get them.
224      */
225     if (try_bootp)
226         bootp(sock, BOOTP_NONE);
227     if (myip.s_addr != 0)
228         goto exit;
229     if (debug)
230         printf("net_open: BOOTP failed, trying RARP/RPC...\n");
231 #endif
232
233     /*
234      * Use RARP to get our IP address.  This also sets our
235      * netmask to the "natural" default for our address.
236      */
237     if (rarp_getipaddress(sock)) {
238         printf("net_open: RARP failed\n");
239         return (EIO);
240     }
241     printf("net_open: client addr: %s\n", inet_ntoa(myip));
242
243     /* Get our hostname, server IP address, gateway. */
244     if (bp_whoami(sock)) {
245         printf("net_open: bootparam/whoami RPC failed\n");
246         return (EIO);
247     }
248     printf("net_open: client name: %s\n", hostname);
249
250     /*
251      * Ignore the gateway from whoami (unreliable).
252      * Use the "gateway" parameter instead.
253      */
254     smask = 0;
255     gateip.s_addr = 0;
256     if (bp_getfile(sock, "gateway", &gateip, buf) == 0) {
257         /* Got it!  Parse the netmask. */
258         smask = ip_convertaddr(buf);
259     }
260     if (smask) {
261         netmask = smask;
262         printf("net_open: subnet mask: %s\n", intoa(netmask));
263     }
264     if (gateip.s_addr)
265         printf("net_open: net gateway: %s\n", inet_ntoa(gateip));
266
267     /* Get the root server and pathname. */
268     if (bp_getfile(sock, "root", &rootip, rootpath)) {
269         printf("net_open: bootparam/getfile RPC failed\n");
270         return (EIO);
271     }
272  exit:
273     /*  
274      * If present, strip the server's address off of the rootpath
275      * before passing it along.  This allows us to be compatible with
276      * the kernel's diskless (BOOTP_NFSROOT) booting conventions
277      */
278     for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
279             if (rootpath[i] == ':')
280                     break;
281     if (i && i != FNAME_SIZE && rootpath[i] == ':') {
282             rootpath[i++] = '\0';
283             if (inet_addr(&rootpath[0]) != INADDR_NONE)
284                     rootip.s_addr = inet_addr(&rootpath[0]);
285             bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1);
286             bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1);          
287     }
288     printf("net_open: server addr: %s\n", inet_ntoa(rootip));
289     printf("net_open: server path: %s\n", rootpath);        
290
291     d = socktodesc(sock);
292     sprintf(temp, "%6D", d->myea, ":");
293     setenv("boot.netif.ip", inet_ntoa(myip), 1);
294     setenv("boot.netif.netmask", intoa(netmask), 1);
295     setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
296     setenv("boot.netif.hwaddr", temp, 1);
297     setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
298     setenv("boot.nfsroot.path", rootpath, 1);
299
300     return (0);
301 }
302
303 static void
304 net_print(int verbose)
305 {
306     return;
307 }