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