Imported Debian patch 3.6-2
[debian/elilo] / glue_netfs.c
1 /*
2  *  Copyright (C) 2001-2003 Hewlett-Packard Co.
3  *      Contributed by Stephane Eranian <eranian@hpl.hp.com>
4  *
5  * This file is part of the ELILO, the EFI Linux boot loader.
6  *
7  *  ELILO is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2, or (at your option)
10  *  any later version.
11  *
12  *  ELILO is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with ELILO; see the file COPYING.  If not, write to the Free
19  *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20  *  02111-1307, USA.
21  *
22  * Please check out the elilo.txt for complete documentation on how
23  * to use this program.
24  */
25 #include <efi.h>
26 #include <efilib.h>
27
28 #include "glue_netfs.h"
29 #include "fs/netfs.h"
30 #include "strops.h"
31
32 #include "elilo.h"
33 #include "vars.h"
34
35 /*
36  * disable this if you only want the default config file (elilo.conf)
37  * and not the ip-address based first file attempt
38  */
39
40 static INTN glue(fileops_t *this, VOID *intf);
41
42 /* object exported to fileops */
43 fileops_fs_t netfs_glue = { NETFS_PROTOCOL  , glue, netfs_install, netfs_uninstall};
44         
45
46 #define NETFS_DEFAULT_KERNEL            L"vmlinux"
47 #define NETFS_DEFAULT_CONFIG            L"elilo.conf"
48 #define NETFS_DEFAULT_SERVER_TYPE       EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_BOOT
49
50
51 static CHAR16 netfs_default_path[FILENAME_MAXLEN];
52
53
54 /*
55  * Pxe Discovery protocol layers
56  * Layer 0 is used to download the boot loader
57  */
58 #define NETFS_CONFIG_LAYER      1
59 #define NETFS_KERNEL_LAYER      2
60
61 static CHAR16 *hexa=L"0123456789ABCDEF";
62
63 static VOID
64 convert_ip2hex(UINT8 *ip, INTN l, CHAR16 *str)
65 {
66         UINTN i;
67
68         for(i=0; i < l; i++) {
69                 str[2*i]   = hexa[(ip[i] & 0xf0)>>4];
70                 str[2*i+1] = hexa[ip[i] & 0x0f];
71         }
72 }
73
74 static VOID
75 convert_ip2decstr(UINT8 *ip, INTN l, CHAR16 *str)
76 {
77         UINTN i, j;
78         UINTN v, val;
79
80         for(i=0, j=0; i < l; i++) {
81                 val = ip[i];
82                 v = val / 100;
83                 if (v) {
84                         str[j++] = L'0'+v;
85                 }
86                 val = val % 100;
87                 v = val / 10;
88                 if (v || ip[i] >= 100) {
89                         str[j++] = L'0'+v;
90                 }
91
92                 v = val % 10;
93                 str[j++] = L'0'+v;
94                 if (i < l-1) str[j++] = L'.';
95         }
96         str[j] = CHAR_NULL;
97 }
98
99 static int
100 netfs_set_default_path(netfs_interface_t *netfs, netfs_info_t *info)
101 {
102         INTN len;
103
104         StrnCpy(netfs_default_path, info->bootfile, FILENAME_MAXLEN);
105
106         len = StrLen(netfs_default_path) - 1;
107
108         while (len >= 0) {
109                 if (netfs_default_path[len] == CHAR_SLASH || netfs_default_path[len] == CHAR_BACKSLASH) break;
110                 len--;
111         }
112         netfs_default_path[len+1] = CHAR_NULL;
113  
114         DBG_PRT((L"netfs_default_path=%s\n", netfs_default_path));
115
116         return EFI_SUCCESS;
117 }
118
119 static EFI_STATUS
120 netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
121 {
122         netfs_interface_t *netfs = (netfs_interface_t *)intf;
123         netfs_info_t info;
124         EFI_STATUS status;
125         UINT8 *ipaddr;
126         UINTN m;
127         CHAR16 ip_var[64], str[64];
128         UINT8 *ip;
129
130         if (config == NULL || kname == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
131
132         netfs->netfs_getinfo(netfs, &info);
133
134         m      = info.using_ipv6 ? 16 : 4;
135         ipaddr = info.using_ipv6 ? info.cln_ipaddr.v6.Addr: info.cln_ipaddr.v4.Addr;
136
137         convert_ip2decstr(ipaddr, m, ip_var);
138         set_var(VAR_NETFS_IPADDR, ip_var);
139
140         ip = info.using_ipv6 ? info.netmask.v6.Addr: info.netmask.v4.Addr;
141         convert_ip2decstr(ip, m, str);
142         set_var(VAR_NETFS_NETMASK, str);
143
144         ip = info.using_ipv6 ? info.gw_ipaddr.v6.Addr: info.gw_ipaddr.v4.Addr;
145         convert_ip2decstr(ip, m, str);
146         set_var(VAR_NETFS_GATEWAY, str);
147
148         set_var(VAR_NETFS_HOSTNAME, info.hostname);
149         set_var(VAR_NETFS_DOMAINAME, info.domainame);
150
151         if (info.using_pxe) {
152                 status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config[0].fname);
153                 if (EFI_ERROR(status)) {
154                         StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1);
155                         config[0].fname[maxlen-1] = CHAR_NULL;
156                 }
157
158                 status = netfs->netfs_query_layer(netfs, 0, NETFS_KERNEL_LAYER, maxlen, kname);
159                 if (EFI_ERROR(status)) {
160                         StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1);
161                         kname[maxlen-1] = CHAR_NULL;
162                 }
163         } else {
164 #ifdef ENABLE_MACHINE_SPECIFIC_NETCONFIG
165
166 #  if defined(CONFIG_ia64)
167 #    define CONFIG_ARCH_EXTENSION L"-ia64.conf\0"
168 #  elif defined (CONFIG_ia32)
169 #    define CONFIG_ARCH_EXTENSION L"-ia64.conf\0"
170 #  else
171 #    error "You need to specfy your default arch config file"
172 #  endif            
173
174 #  define CONFIG_EXTENSION L".conf\0"
175                 /*
176                  * will try machine/subnet specific files first.
177                  * the filenames are constructed based on the IP(v4) address
178                  */
179                 convert_ip2hex(ipaddr, m, str);
180                 StrnCpy(config[0].fname, str, maxlen-1);
181                 StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6);
182
183                 StrnCpy(config[1].fname, str, maxlen-1);
184                 StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, 11);
185
186                 StrnCpy(config[2].fname, str, maxlen-1);
187                 StrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6);
188
189                 StrnCpy(config[3].fname, str, maxlen-1);
190                 StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, 11);
191
192                 StrnCpy(config[4].fname, str, maxlen-1);
193                 StrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6);
194                 
195                 StrnCpy(config[5].fname, str, maxlen-1);
196                 StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, 11);
197
198                 StrnCpy(config[6].fname, str, maxlen-1);
199                 StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6);
200 #else
201                 StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1);
202                 config[0].fname[maxlen-1] = CHAR_NULL;
203 #endif
204                 StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1);
205                 kname[maxlen-1] = CHAR_NULL;
206
207                 /*
208                  * extract bootloader path prefix to be used for 
209                  * the config file (and possibly the other files we 
210                  * need to download)
211                  */
212                 netfs_set_default_path(netfs, &info);
213         }
214         return EFI_SUCCESS;
215 }
216
217 static EFI_STATUS
218 netfs_getdefault_path(CHAR16 *path, UINTN maxlen)
219 {
220         if (maxlen <= StrLen(netfs_default_path)) return EFI_BUFFER_TOO_SMALL;
221
222         StrCpy(path, netfs_default_path);
223         return EFI_SUCCESS;
224 }
225
226
227 static EFI_STATUS 
228 glue_open(VOID *intf, CHAR16 *name, fops_fd_t *fd)
229 {
230         netfs_interface_t *netfs = (netfs_interface_t *)intf;
231         CHAR16 fullname[FILENAME_MAXLEN];
232
233         if (name[0] != CHAR_SLASH && name[0] != CHAR_BACKSLASH && netfs_default_path[0] != CHAR_NULL) {
234                 if (StrLen(netfs_default_path) + StrLen(name) + 1 >= FILENAME_MAXLEN)
235                         return EFI_INVALID_PARAMETER;
236
237                 StrCpy(fullname, netfs_default_path);
238                 StrCat(fullname, name);
239                 name = fullname;
240         }
241         return netfs->netfs_open(intf, name, fd);
242 }
243
244 static INTN
245 glue(fileops_t *fp, VOID *intf)
246 {
247         netfs_interface_t *netfs = (netfs_interface_t *)intf;
248
249         /* record underlying interface */
250         fp->intf        = intf;
251
252         fp->open            = glue_open;
253         fp->read            = (fops_read_t)netfs->netfs_read;
254         fp->close           = (fops_close_t)netfs->netfs_close;
255         fp->infosize        = (fops_infosize_t)netfs->netfs_infosize;
256         fp->seek            = (fops_seek_t)netfs->netfs_seek;
257         fp->setdefaults     = (fops_setdefaults_t)netfs_setdefaults;
258         fp->getdefault_path = (fops_getdefault_path_t)netfs_getdefault_path;
259         fp->intf            = intf;
260
261         /* fill out the name of the underlying file system */
262         netfs->netfs_name(netfs, fp->name, FILEOPS_NAME_MAXLEN);
263
264         return 0;
265 }