~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/fs/i386/pc/pxe.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* pxe.c - Driver to provide access to the pxe filesystem  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2008,2009  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <grub/dl.h>
 
21
#include <grub/fs.h>
 
22
#include <grub/mm.h>
 
23
#include <grub/disk.h>
 
24
#include <grub/file.h>
 
25
#include <grub/misc.h>
 
26
#include <grub/bufio.h>
 
27
#include <grub/env.h>
 
28
 
 
29
#include <grub/machine/pxe.h>
 
30
#include <grub/machine/int.h>
 
31
#include <grub/machine/memory.h>
 
32
 
 
33
#define SEGMENT(x)      ((x) >> 4)
 
34
#define OFFSET(x)       ((x) & 0xF)
 
35
#define SEGOFS(x)       ((SEGMENT(x) << 16) + OFFSET(x))
 
36
#define LINEAR(x)       (void *) (((x >> 16) <<4) + (x & 0xFFFF))
 
37
 
 
38
struct grub_pxe_disk_data
 
39
{
 
40
  grub_uint32_t server_ip;
 
41
  grub_uint32_t gateway_ip;
 
42
};
 
43
 
 
44
struct grub_pxe_bangpxe *grub_pxe_pxenv;
 
45
static grub_uint32_t grub_pxe_your_ip;
 
46
static grub_uint32_t grub_pxe_default_server_ip;
 
47
static grub_uint32_t grub_pxe_default_gateway_ip;
 
48
static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
 
49
 
 
50
static grub_file_t curr_file = 0;
 
51
 
 
52
struct grub_pxe_data
 
53
{
 
54
  grub_uint32_t packet_number;
 
55
  grub_uint32_t block_size;
 
56
  char filename[0];
 
57
};
 
58
 
 
59
static grub_uint32_t pxe_rm_entry = 0;
 
60
 
 
61
static struct grub_pxe_bangpxe *
 
62
grub_pxe_scan (void)
 
63
{
 
64
  struct grub_bios_int_registers regs;
 
65
  struct grub_pxenv *pxenv;
 
66
  struct grub_pxe_bangpxe *bangpxe;
 
67
 
 
68
  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
 
69
 
 
70
  regs.ebx = 0;
 
71
  regs.ecx = 0;
 
72
  regs.eax = 0x5650;
 
73
  regs.es = 0;
 
74
 
 
75
  grub_bios_interrupt (0x1a, &regs);
 
76
 
 
77
  if ((regs.eax & 0xffff) != 0x564e)
 
78
    return NULL;
 
79
 
 
80
  pxenv = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
 
81
  if (grub_memcmp (pxenv->signature, GRUB_PXE_SIGNATURE,
 
82
                   sizeof (pxenv->signature))
 
83
      != 0)
 
84
    return NULL;
 
85
 
 
86
  if (pxenv->version < 0x201)
 
87
    return NULL;
 
88
 
 
89
  bangpxe = (void *) ((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4)
 
90
                      + (pxenv->pxe_ptr & 0xffff));
 
91
 
 
92
  if (!bangpxe)
 
93
    return NULL;
 
94
 
 
95
  if (grub_memcmp (bangpxe->signature, GRUB_PXE_BANGPXE_SIGNATURE,
 
96
                   sizeof (bangpxe->signature)) != 0)
 
97
    return NULL;
 
98
 
 
99
  pxe_rm_entry = bangpxe->rm_entry;
 
100
 
 
101
  return bangpxe;
 
102
}
 
103
 
 
104
static int
 
105
grub_pxe_iterate (int (*hook) (const char *name))
 
106
{
 
107
  if (hook ("pxe"))
 
108
    return 1;
 
109
  return 0;
 
110
}
 
111
 
 
112
static grub_err_t
 
113
parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
 
114
{
 
115
  grub_uint32_t newip = 0;
 
116
  unsigned long t;
 
117
  int i;
 
118
  const char *ptr = val;
 
119
 
 
120
  for (i = 0; i < 4; i++)
 
121
    {
 
122
      t = grub_strtoul (ptr, (char **) &ptr, 0);
 
123
      if (grub_errno)
 
124
        return grub_errno;
 
125
      if (t & ~0xff)
 
126
        return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
 
127
      newip >>= 8;
 
128
      newip |= (t << 24);
 
129
      if (i != 3 && *ptr != '.')
 
130
        return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
 
131
      ptr++;
 
132
    }
 
133
  *ip = newip;
 
134
  if (rest)
 
135
    *rest = ptr - 1;
 
136
  return 0;
 
137
}
 
138
 
 
139
static grub_err_t
 
140
grub_pxe_open (const char *name, grub_disk_t disk)
 
141
{
 
142
  struct grub_pxe_disk_data *data;
 
143
 
 
144
  if (grub_strcmp (name, "pxe") != 0
 
145
      && grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) != 0)
 
146
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk");
 
147
 
 
148
  data = grub_malloc (sizeof (*data));
 
149
  if (!data)
 
150
    return grub_errno;
 
151
 
 
152
  if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
 
153
    {
 
154
      const char *ptr;
 
155
      grub_err_t err;
 
156
 
 
157
      ptr = name + sizeof ("pxe:") - 1;
 
158
      err = parse_ip (ptr, &(data->server_ip), &ptr);
 
159
      if (err)
 
160
        return err;
 
161
      if (*ptr == ':')
 
162
        {
 
163
          err = parse_ip (ptr + 1, &(data->gateway_ip), 0);
 
164
          if (err)
 
165
            return err;
 
166
        }
 
167
      else
 
168
        data->gateway_ip = grub_pxe_default_gateway_ip;
 
169
    }
 
170
  else
 
171
    {
 
172
      data->server_ip = grub_pxe_default_server_ip;
 
173
      data->gateway_ip = grub_pxe_default_gateway_ip;
 
174
    }
 
175
 
 
176
  disk->total_sectors = 0;
 
177
  disk->id = (unsigned long) data;
 
178
 
 
179
  disk->data = data;
 
180
 
 
181
  return GRUB_ERR_NONE;
 
182
}
 
183
 
 
184
static void
 
185
grub_pxe_close (grub_disk_t disk)
 
186
{
 
187
  grub_free (disk->data);
 
188
}
 
189
 
 
190
static grub_err_t
 
191
grub_pxe_read (grub_disk_t disk __attribute((unused)),
 
192
               grub_disk_addr_t sector __attribute((unused)),
 
193
               grub_size_t size __attribute((unused)),
 
194
               char *buf __attribute((unused)))
 
195
{
 
196
  return GRUB_ERR_OUT_OF_RANGE;
 
197
}
 
198
 
 
199
static grub_err_t
 
200
grub_pxe_write (grub_disk_t disk __attribute((unused)),
 
201
                grub_disk_addr_t sector __attribute((unused)),
 
202
                grub_size_t size __attribute((unused)),
 
203
                const char *buf __attribute((unused)))
 
204
{
 
205
  return GRUB_ERR_OUT_OF_RANGE;
 
206
}
 
207
 
 
208
static struct grub_disk_dev grub_pxe_dev =
 
209
  {
 
210
    .name = "pxe",
 
211
    .id = GRUB_DISK_DEVICE_PXE_ID,
 
212
    .iterate = grub_pxe_iterate,
 
213
    .open = grub_pxe_open,
 
214
    .close = grub_pxe_close,
 
215
    .read = grub_pxe_read,
 
216
    .write = grub_pxe_write,
 
217
    .next = 0
 
218
  };
 
219
 
 
220
static grub_err_t
 
221
grub_pxefs_dir (grub_device_t device,
 
222
                const char *path  __attribute__ ((unused)),
 
223
                int (*hook) (const char *filename,
 
224
                             const struct grub_dirhook_info *info)
 
225
                __attribute__ ((unused)))
 
226
{
 
227
  if (device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID)
 
228
    return grub_error (GRUB_ERR_IO, "not a pxe disk");
 
229
 
 
230
  return GRUB_ERR_NONE;
 
231
}
 
232
 
 
233
static grub_err_t
 
234
grub_pxefs_open (struct grub_file *file, const char *name)
 
235
{
 
236
  union
 
237
    {
 
238
      struct grub_pxenv_tftp_get_fsize c1;
 
239
      struct grub_pxenv_tftp_open c2;
 
240
    } c;
 
241
  struct grub_pxe_data *data;
 
242
  struct grub_pxe_disk_data *disk_data = file->device->disk->data;
 
243
  grub_file_t file_int, bufio;
 
244
 
 
245
  if (file->device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID)
 
246
    return grub_error (GRUB_ERR_IO, "not a pxe disk");
 
247
 
 
248
  if (curr_file != 0)
 
249
    {
 
250
      grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c.c2, pxe_rm_entry);
 
251
      curr_file = 0;
 
252
    }
 
253
 
 
254
  c.c1.server_ip = disk_data->server_ip;
 
255
  c.c1.gateway_ip = disk_data->gateway_ip;
 
256
  grub_strcpy ((char *)&c.c1.filename[0], name);
 
257
  grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1, pxe_rm_entry);
 
258
  if (c.c1.status)
 
259
    return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
 
260
 
 
261
  file->size = c.c1.file_size;
 
262
 
 
263
  c.c2.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
 
264
  c.c2.packet_size = grub_pxe_blksize;
 
265
  grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2, pxe_rm_entry);
 
266
  if (c.c2.status)
 
267
    return grub_error (GRUB_ERR_BAD_FS, "open fails");
 
268
 
 
269
  data = grub_zalloc (sizeof (struct grub_pxe_data) + grub_strlen (name) + 1);
 
270
  if (! data)
 
271
    return grub_errno;
 
272
 
 
273
  data->block_size = c.c2.packet_size;
 
274
  grub_strcpy (data->filename, name);
 
275
 
 
276
  file_int = grub_malloc (sizeof (*file_int));
 
277
  if (! file_int)
 
278
    {
 
279
      grub_free (data);
 
280
      return grub_errno;
 
281
    }
 
282
 
 
283
  file->data = data;
 
284
  file->not_easly_seekable = 1;
 
285
  grub_memcpy (file_int, file, sizeof (struct grub_file));
 
286
  curr_file = file_int;
 
287
 
 
288
  bufio = grub_bufio_open (file_int, data->block_size);
 
289
  if (! bufio)
 
290
    {
 
291
      grub_free (file_int);
 
292
      grub_free (data);
 
293
      return grub_errno;
 
294
    }
 
295
 
 
296
  grub_memcpy (file, bufio, sizeof (struct grub_file));
 
297
 
 
298
  return GRUB_ERR_NONE;
 
299
}
 
300
 
 
301
static grub_ssize_t
 
302
grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
 
303
{
 
304
  struct grub_pxenv_tftp_read c;
 
305
  struct grub_pxe_data *data;
 
306
  struct grub_pxe_disk_data *disk_data = file->device->disk->data;
 
307
  grub_uint32_t pn, r;
 
308
 
 
309
  data = file->data;
 
310
 
 
311
  pn = grub_divmod64 (file->offset, data->block_size, &r);
 
312
  if (r)
 
313
    {
 
314
      grub_error (GRUB_ERR_BAD_FS,
 
315
                  "read access must be aligned to packet size");
 
316
      return -1;
 
317
    }
 
318
 
 
319
  if ((curr_file != file) || (data->packet_number > pn))
 
320
    {
 
321
      struct grub_pxenv_tftp_open o;
 
322
 
 
323
      if (curr_file != 0)
 
324
        grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o, pxe_rm_entry);
 
325
 
 
326
      o.server_ip = disk_data->server_ip;
 
327
      o.gateway_ip = disk_data->gateway_ip;
 
328
      grub_strcpy ((char *)&o.filename[0], data->filename);
 
329
      o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
 
330
      o.packet_size = data->block_size;
 
331
      grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o, pxe_rm_entry);
 
332
      if (o.status)
 
333
        {
 
334
          grub_error (GRUB_ERR_BAD_FS, "open fails");
 
335
          return -1;
 
336
        }
 
337
      data->block_size = o.packet_size;
 
338
      data->packet_number = 0;
 
339
      curr_file = file;
 
340
    }
 
341
 
 
342
  c.buffer = SEGOFS (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
 
343
  while (pn >= data->packet_number)
 
344
    {
 
345
      c.buffer_size = data->block_size;
 
346
      grub_pxe_call (GRUB_PXENV_TFTP_READ, &c, pxe_rm_entry);
 
347
      if (c.status)
 
348
        {
 
349
          grub_error (GRUB_ERR_BAD_FS, "read fails");
 
350
          return -1;
 
351
        }
 
352
      data->packet_number++;
 
353
    }
 
354
 
 
355
  grub_memcpy (buf, (char *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, len);
 
356
 
 
357
  return len;
 
358
}
 
359
 
 
360
static grub_err_t
 
361
grub_pxefs_close (grub_file_t file)
 
362
{
 
363
  struct grub_pxenv_tftp_close c;
 
364
 
 
365
  if (curr_file == file)
 
366
    {
 
367
      grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c, pxe_rm_entry);
 
368
      curr_file = 0;
 
369
    }
 
370
 
 
371
  grub_free (file->data);
 
372
 
 
373
  return GRUB_ERR_NONE;
 
374
}
 
375
 
 
376
static grub_err_t
 
377
grub_pxefs_label (grub_device_t device __attribute ((unused)),
 
378
                   char **label __attribute ((unused)))
 
379
{
 
380
  *label = 0;
 
381
  return GRUB_ERR_NONE;
 
382
}
 
383
 
 
384
static struct grub_fs grub_pxefs_fs =
 
385
  {
 
386
    .name = "pxefs",
 
387
    .dir = grub_pxefs_dir,
 
388
    .open = grub_pxefs_open,
 
389
    .read = grub_pxefs_read,
 
390
    .close = grub_pxefs_close,
 
391
    .label = grub_pxefs_label,
 
392
    .next = 0
 
393
  };
 
394
 
 
395
static char *
 
396
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
 
397
                         const char *val __attribute__ ((unused)))
 
398
{
 
399
  return NULL;
 
400
}
 
401
 
 
402
static void
 
403
set_mac_env (grub_uint8_t *mac_addr, grub_size_t mac_len)
 
404
{
 
405
  char buf[(sizeof ("XX:") - 1) * mac_len + 1];
 
406
  char *ptr = buf;
 
407
  unsigned i;
 
408
 
 
409
  for (i = 0; i < mac_len; i++)
 
410
    {
 
411
      grub_snprintf (ptr, sizeof (buf) - (ptr - buf),
 
412
                     "%02x:", mac_addr[i] & 0xff);
 
413
      ptr += (sizeof ("XX:") - 1);
 
414
    }
 
415
  if (mac_len)
 
416
    *(ptr - 1) = 0;
 
417
  else
 
418
    buf[0] = 0;
 
419
 
 
420
  grub_env_set ("net_pxe_mac", buf);
 
421
  /* XXX: Is it possible to change MAC in PXE?  */
 
422
  grub_register_variable_hook ("net_pxe_mac", 0, grub_env_write_readonly);
 
423
}
 
424
 
 
425
static void
 
426
set_env_limn_ro (const char *varname, char *value, grub_size_t len)
 
427
{
 
428
  char c;
 
429
  c = value[len];
 
430
  value[len] = 0;
 
431
  grub_env_set (varname, value);
 
432
  value[len] = c;
 
433
  grub_register_variable_hook (varname, 0, grub_env_write_readonly);
 
434
}
 
435
 
 
436
static void
 
437
parse_dhcp_vendor (void *vend, int limit)
 
438
{
 
439
  grub_uint8_t *ptr, *ptr0;
 
440
 
 
441
  ptr = ptr0 = vend;
 
442
 
 
443
  if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != 0x63825363)
 
444
    return;
 
445
  ptr = ptr + sizeof (grub_uint32_t);
 
446
  while (ptr - ptr0 < limit)
 
447
    {
 
448
      grub_uint8_t tagtype;
 
449
      grub_uint8_t taglength;
 
450
 
 
451
      tagtype = *ptr++;
 
452
 
 
453
      /* Pad tag.  */
 
454
      if (tagtype == 0)
 
455
        continue;
 
456
 
 
457
      /* End tag.  */
 
458
      if (tagtype == 0xff)
 
459
        return;
 
460
 
 
461
      taglength = *ptr++;
 
462
 
 
463
      switch (tagtype)
 
464
        {
 
465
        case 12:
 
466
          set_env_limn_ro ("net_pxe_hostname", (char *) ptr, taglength);
 
467
          break;
 
468
 
 
469
        case 15:
 
470
          set_env_limn_ro ("net_pxe_domain", (char *) ptr, taglength);
 
471
          break;
 
472
 
 
473
        case 17:
 
474
          set_env_limn_ro ("net_pxe_rootpath", (char *) ptr, taglength);
 
475
          break;
 
476
 
 
477
        case 18:
 
478
          set_env_limn_ro ("net_pxe_extensionspath", (char *) ptr, taglength);
 
479
          break;
 
480
 
 
481
          /* If you need any other options please contact GRUB
 
482
             developpement team.  */
 
483
        }
 
484
 
 
485
      ptr += taglength;
 
486
    }
 
487
}
 
488
 
 
489
static void
 
490
grub_pxe_detect (void)
 
491
{
 
492
  struct grub_pxe_bangpxe *pxenv;
 
493
  struct grub_pxenv_get_cached_info ci;
 
494
  struct grub_pxenv_boot_player *bp;
 
495
 
 
496
  pxenv = grub_pxe_scan ();
 
497
  if (! pxenv)
 
498
    return;
 
499
 
 
500
  ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
 
501
  ci.buffer = 0;
 
502
  ci.buffer_size = 0;
 
503
  grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci, pxe_rm_entry);
 
504
  if (ci.status)
 
505
    return;
 
506
 
 
507
  bp = LINEAR (ci.buffer);
 
508
 
 
509
  grub_pxe_your_ip = bp->your_ip;
 
510
  grub_pxe_default_server_ip = bp->server_ip;
 
511
  grub_pxe_default_gateway_ip = bp->gateway_ip;
 
512
  set_mac_env (bp->mac_addr, bp->hw_len < sizeof (bp->mac_addr) ? bp->hw_len
 
513
               : sizeof (bp->mac_addr));
 
514
  set_env_limn_ro ("net_pxe_boot_file", (char *) bp->boot_file,
 
515
                   sizeof (bp->boot_file));
 
516
  set_env_limn_ro ("net_pxe_dhcp_server_name", (char *) bp->server_name,
 
517
                   sizeof (bp->server_name));
 
518
  parse_dhcp_vendor (&bp->vendor, sizeof (bp->vendor));
 
519
  grub_pxe_pxenv = pxenv;
 
520
}
 
521
 
 
522
void
 
523
grub_pxe_unload (void)
 
524
{
 
525
  if (grub_pxe_pxenv)
 
526
    {
 
527
      grub_fs_unregister (&grub_pxefs_fs);
 
528
      grub_disk_dev_unregister (&grub_pxe_dev);
 
529
 
 
530
      grub_pxe_pxenv = 0;
 
531
    }
 
532
}
 
533
 
 
534
static void
 
535
set_ip_env (char *varname, grub_uint32_t ip)
 
536
{
 
537
  char buf[sizeof ("XXX.XXX.XXX.XXX")];
 
538
 
 
539
  grub_snprintf (buf, sizeof (buf), "%d.%d.%d.%d", (ip & 0xff),
 
540
                 (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
 
541
  grub_env_set (varname, buf);
 
542
}
 
543
 
 
544
static char *
 
545
write_ip_env (grub_uint32_t *ip, const char *val)
 
546
{
 
547
  char *buf;
 
548
  grub_err_t err;
 
549
  grub_uint32_t newip;
 
550
  
 
551
  err = parse_ip (val, &newip, 0);
 
552
  if (err)
 
553
    return 0;
 
554
 
 
555
  /* Normalize the IP.  */
 
556
  buf = grub_xasprintf ("%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff,
 
557
                       (newip >> 16) & 0xff, (newip >> 24) & 0xff);
 
558
  if (!buf)
 
559
    return 0;
 
560
 
 
561
  *ip = newip;
 
562
 
 
563
  return buf; 
 
564
}
 
565
 
 
566
static char *
 
567
grub_env_write_pxe_default_server (struct grub_env_var *var 
 
568
                                   __attribute__ ((unused)),
 
569
                                   const char *val)
 
570
{
 
571
  return write_ip_env (&grub_pxe_default_server_ip, val);
 
572
}
 
573
 
 
574
static char *
 
575
grub_env_write_pxe_default_gateway (struct grub_env_var *var
 
576
                                    __attribute__ ((unused)),
 
577
                                    const char *val)
 
578
{
 
579
  return write_ip_env (&grub_pxe_default_gateway_ip, val);
 
580
}
 
581
 
 
582
static char *
 
583
grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)),
 
584
                              const char *val)
 
585
{
 
586
  unsigned size;
 
587
  char *buf;
 
588
 
 
589
  size = grub_strtoul (val, 0, 0);
 
590
  if (grub_errno)
 
591
    return 0;
 
592
 
 
593
  if (size < GRUB_PXE_MIN_BLKSIZE)
 
594
    size = GRUB_PXE_MIN_BLKSIZE;
 
595
  else if (size > GRUB_PXE_MAX_BLKSIZE)
 
596
    size = GRUB_PXE_MAX_BLKSIZE;
 
597
  
 
598
  buf = grub_xasprintf ("%d", size);
 
599
  if (!buf)
 
600
    return 0;
 
601
 
 
602
  grub_pxe_blksize = size;
 
603
  
 
604
  return buf;
 
605
}
 
606
 
 
607
 
 
608
GRUB_MOD_INIT(pxe)
 
609
{
 
610
  grub_pxe_detect ();
 
611
  if (grub_pxe_pxenv)
 
612
    {
 
613
      char *buf;
 
614
 
 
615
      buf = grub_xasprintf ("%d", grub_pxe_blksize);
 
616
      if (buf)
 
617
        grub_env_set ("pxe_blksize", buf);
 
618
      grub_free (buf);
 
619
 
 
620
      set_ip_env ("pxe_default_server", grub_pxe_default_server_ip);
 
621
      set_ip_env ("pxe_default_gateway", grub_pxe_default_gateway_ip);
 
622
      set_ip_env ("net_pxe_ip", grub_pxe_your_ip);
 
623
      grub_register_variable_hook ("pxe_default_server", 0,
 
624
                                   grub_env_write_pxe_default_server);
 
625
      grub_register_variable_hook ("pxe_default_gateway", 0,
 
626
                                   grub_env_write_pxe_default_gateway);
 
627
 
 
628
      /* XXX: Is it possible to change IP in PXE?  */
 
629
      grub_register_variable_hook ("net_pxe_ip", 0,
 
630
                                   grub_env_write_readonly);
 
631
      grub_register_variable_hook ("pxe_blksize", 0,
 
632
                                   grub_env_write_pxe_blocksize);
 
633
      grub_disk_dev_register (&grub_pxe_dev);
 
634
      grub_fs_register (&grub_pxefs_fs);
 
635
    }
 
636
}
 
637
 
 
638
GRUB_MOD_FINI(pxe)
 
639
{
 
640
  grub_pxe_unload ();
 
641
}