~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, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

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
}