~jonathank89/burg/burg-percise

« back to all changes in this revision

Viewing changes to fs/i386/pc/pxe.c

2009-12-25  Vladimir Serbinenko  <phcoder@gmail.com>

        Support for (pxe[:server[:gateway]]) syntax and
        use environment variable for PXE.

        * commands/i386/pc/pxecmd.c (options): Removed.
        (print_ip): Removed.
        (grub_cmd_pxe): Removed
        (grub_cmd_pxe_unload): New function.
        * fs/i386/pc/pxe.c (grub_pxe_disk_data): New structure.
        (grub_pxe_your_ip): Made static.
        (grub_pxe_default_server_ip): Likewise.
        (grub_pxe_default_gateway_ip): Likewise.
        (grub_pxe_blksize): Likewise.
        (parse_ip): New function.
        (grub_pxe_open): Support server and gateway specification.
        (grub_pxe_close): Free disk->data.
        (grub_pxefs_open): Use disk->data.
        (grub_pxefs_read): Likewise.
        (grub_env_write_readonly): New function.
        (set_mac_env): Likewise.
        (set_env_limn_ro): Likewise.
        (parse_dhcp_vendor): Likewise.
        (grub_pxe_detect): Set the environment variables.
        (set_ip_env): New function.
        (write_ip_env): Likewise.
        (grub_env_write_pxe_default_server): Likewise.
        (grub_env_write_pxe_default_gateway): Likewise.
        (grub_env_write_pxe_blocksize): Likewise.
        (GRUB_MOD_INIT(pxe)): Set environment variables.
        * include/grub/i386/pc/pxe.h (grub_pxe_mac_addr): Rename to ...
        (grub_pxe_mac_addr_t): ... this. All users updated.
        (grub_pxe_your_ip): Removed.
        (grub_pxe_server_ip): Likewise.
        (grub_pxe_gateway_ip): Likewise.
        (grub_pxe_blksize): Likewise.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* pxe.c - Driver to provide access to the pxe filesystem  */
2
2
/*
3
3
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2008  Free Software Foundation, Inc.
 
4
 *  Copyright (C) 2008,2009  Free Software Foundation, Inc.
5
5
 *
6
6
 *  GRUB is free software: you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
24
24
#include <grub/file.h>
25
25
#include <grub/misc.h>
26
26
#include <grub/bufio.h>
 
27
#include <grub/env.h>
27
28
 
28
29
#include <grub/machine/pxe.h>
29
30
#include <grub/machine/memory.h>
33
34
#define SEGOFS(x)       ((SEGMENT(x) << 16) + OFFSET(x))
34
35
#define LINEAR(x)       (void *) (((x >> 16) <<4) + (x & 0xFFFF))
35
36
 
 
37
struct grub_pxe_disk_data
 
38
{
 
39
  grub_uint32_t server_ip;
 
40
  grub_uint32_t gateway_ip;
 
41
};
 
42
 
36
43
struct grub_pxenv *grub_pxe_pxenv;
37
 
grub_uint32_t grub_pxe_your_ip;
38
 
grub_uint32_t grub_pxe_server_ip;
39
 
grub_uint32_t grub_pxe_gateway_ip;
40
 
int grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
 
44
static grub_uint32_t grub_pxe_your_ip;
 
45
static grub_uint32_t grub_pxe_default_server_ip;
 
46
static grub_uint32_t grub_pxe_default_gateway_ip;
 
47
static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
41
48
 
42
49
static grub_file_t curr_file = 0;
43
50
 
57
64
}
58
65
 
59
66
static grub_err_t
 
67
parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
 
68
{
 
69
  grub_uint32_t newip = 0;
 
70
  unsigned long t;
 
71
  int i;
 
72
  const char *ptr = val;
 
73
 
 
74
  for (i = 0; i < 4; i++)
 
75
    {
 
76
      t = grub_strtoul (ptr, (char **) &ptr, 0);
 
77
      if (grub_errno)
 
78
        return grub_errno;
 
79
      if (t & ~0xff)
 
80
        return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
 
81
      newip >>= 8;
 
82
      newip |= (t << 24);
 
83
      if (i != 3 && *ptr != '.')
 
84
        return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
 
85
      ptr++;
 
86
    }
 
87
  *ip = newip;
 
88
  if (rest)
 
89
    *rest = ptr - 1;
 
90
  return 0;
 
91
}
 
92
 
 
93
static grub_err_t
60
94
grub_pxe_open (const char *name, grub_disk_t disk)
61
95
{
62
 
  if (grub_strcmp (name, "pxe"))
63
 
      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk");
 
96
  struct grub_pxe_disk_data *data;
 
97
 
 
98
  if (grub_strcmp (name, "pxe") != 0
 
99
      && grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) != 0)
 
100
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk");
 
101
 
 
102
  data = grub_malloc (sizeof (*data));
 
103
  if (!data)
 
104
    return grub_errno;
 
105
 
 
106
  if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
 
107
    {
 
108
      const char *ptr;
 
109
      grub_err_t err;
 
110
 
 
111
      ptr = name + sizeof ("pxe:") - 1;
 
112
      err = parse_ip (ptr, &(data->server_ip), &ptr);
 
113
      if (err)
 
114
        return err;
 
115
      if (*ptr == ':')
 
116
        {
 
117
          err = parse_ip (ptr + 1, &(data->server_ip), 0);
 
118
          if (err)
 
119
            return err;
 
120
        }
 
121
      else
 
122
        data->gateway_ip = grub_pxe_default_gateway_ip;
 
123
    }
 
124
  else
 
125
    {
 
126
      data->server_ip = grub_pxe_default_server_ip;
 
127
      data->gateway_ip = grub_pxe_default_gateway_ip;
 
128
    }
64
129
 
65
130
  disk->total_sectors = 0;
66
 
  disk->id = (unsigned long) "pxe";
 
131
  disk->id = (unsigned long) data;
67
132
 
68
133
  disk->has_partitions = 0;
69
 
  disk->data = 0;
 
134
  disk->data = data;
70
135
 
71
136
  return GRUB_ERR_NONE;
72
137
}
73
138
 
74
139
static void
75
 
grub_pxe_close (grub_disk_t disk __attribute((unused)))
 
140
grub_pxe_close (grub_disk_t disk)
76
141
{
 
142
  grub_free (disk->data);
77
143
}
78
144
 
79
145
static grub_err_t
125
191
      struct grub_pxenv_tftp_open c2;
126
192
    } c;
127
193
  struct grub_pxe_data *data;
 
194
  struct grub_pxe_disk_data *disk_data = file->device->disk->data;
128
195
  grub_file_t file_int, bufio;
129
196
 
130
197
  if (curr_file != 0)
133
200
      curr_file = 0;
134
201
    }
135
202
 
136
 
  c.c1.server_ip = grub_pxe_server_ip;
137
 
  c.c1.gateway_ip = grub_pxe_gateway_ip;
 
203
  c.c1.server_ip = disk_data->server_ip;
 
204
  c.c1.gateway_ip = disk_data->gateway_ip;
138
205
  grub_strcpy ((char *)&c.c1.filename[0], name);
139
206
  grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1);
140
207
  if (c.c1.status)
184
251
{
185
252
  struct grub_pxenv_tftp_read c;
186
253
  struct grub_pxe_data *data;
 
254
  struct grub_pxe_disk_data *disk_data = file->device->disk->data;
187
255
  grub_uint32_t pn, r;
188
256
 
189
257
  data = file->data;
203
271
      if (curr_file != 0)
204
272
        grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o);
205
273
 
206
 
      o.server_ip = grub_pxe_server_ip;
207
 
      o.gateway_ip = grub_pxe_gateway_ip;
 
274
      o.server_ip = disk_data->server_ip;
 
275
      o.gateway_ip = disk_data->gateway_ip;
208
276
      grub_strcpy ((char *)&o.filename[0], data->filename);
209
277
      o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
210
278
      o.packet_size = grub_pxe_blksize;
272
340
    .next = 0
273
341
  };
274
342
 
 
343
static char *
 
344
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
 
345
                         const char *val __attribute__ ((unused)))
 
346
{
 
347
  return NULL;
 
348
}
 
349
 
 
350
static void
 
351
set_mac_env (grub_uint8_t *mac_addr, grub_size_t mac_len)
 
352
{
 
353
  char buf[(sizeof ("XX:") - 1) * mac_len + 1];
 
354
  char *ptr = buf;
 
355
  unsigned i;
 
356
 
 
357
  for (i = 0; i < mac_len; i++)
 
358
    {
 
359
      grub_sprintf (ptr, "%02x:", mac_addr[i] & 0xff);
 
360
      ptr += (sizeof ("XX:") - 1);
 
361
    }
 
362
  if (mac_len)
 
363
    *(ptr - 1) = 0;
 
364
  else
 
365
    buf[0] = 0;
 
366
 
 
367
  grub_env_set ("net_pxe_mac", buf);
 
368
  /* XXX: Is it possible to change MAC in PXE?  */
 
369
  grub_register_variable_hook ("net_pxe_mac", 0, grub_env_write_readonly);
 
370
}
 
371
 
 
372
static void
 
373
set_env_limn_ro (const char *varname, char *value, grub_size_t len)
 
374
{
 
375
  char c;
 
376
  c = value[len];
 
377
  value[len] = 0;
 
378
  grub_env_set (varname, value);
 
379
  value[len] = c;
 
380
  grub_register_variable_hook (varname, 0, grub_env_write_readonly);
 
381
}
 
382
 
 
383
static void
 
384
parse_dhcp_vendor (void *vend, int limit)
 
385
{
 
386
  grub_uint8_t *ptr, *ptr0;
 
387
 
 
388
  ptr = ptr0 = vend;
 
389
 
 
390
  if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != 0x63825363)
 
391
    return;
 
392
  ptr = ptr + sizeof (grub_uint32_t);
 
393
  while (ptr - ptr0 < limit)
 
394
    {
 
395
      grub_uint8_t tagtype;
 
396
      grub_uint8_t taglength;
 
397
 
 
398
      tagtype = *ptr++;
 
399
 
 
400
      /* Pad tag.  */
 
401
      if (tagtype == 0)
 
402
        continue;
 
403
 
 
404
      /* End tag.  */
 
405
      if (tagtype == 0xff)
 
406
        return;
 
407
 
 
408
      taglength = *ptr++;
 
409
 
 
410
      switch (tagtype)
 
411
        {
 
412
        case 12:
 
413
          set_env_limn_ro ("net_pxe_hostname", (char *) ptr, taglength);
 
414
          break;
 
415
 
 
416
        case 15:
 
417
          set_env_limn_ro ("net_pxe_domain", (char *) ptr, taglength);
 
418
          break;
 
419
 
 
420
        case 17:
 
421
          set_env_limn_ro ("net_pxe_rootpath", (char *) ptr, taglength);
 
422
          break;
 
423
 
 
424
        case 18:
 
425
          set_env_limn_ro ("net_pxe_extensionspath", (char *) ptr, taglength);
 
426
          break;
 
427
 
 
428
          /* If you need any other options please contact GRUB
 
429
             developpement team.  */
 
430
        }
 
431
 
 
432
      ptr += taglength;
 
433
    }
 
434
}
 
435
 
275
436
static void
276
437
grub_pxe_detect (void)
277
438
{
293
454
  bp = LINEAR (ci.buffer);
294
455
 
295
456
  grub_pxe_your_ip = bp->your_ip;
296
 
  grub_pxe_server_ip = bp->server_ip;
297
 
  grub_pxe_gateway_ip = bp->gateway_ip;
298
 
 
 
457
  grub_pxe_default_server_ip = bp->server_ip;
 
458
  grub_pxe_default_gateway_ip = bp->gateway_ip;
 
459
  set_mac_env (bp->mac_addr, bp->hw_len < sizeof (bp->mac_addr) ? bp->hw_len
 
460
               : sizeof (bp->mac_addr));
 
461
  set_env_limn_ro ("net_pxe_boot_file", (char *) bp->boot_file,
 
462
                   sizeof (bp->boot_file));
 
463
  set_env_limn_ro ("net_pxe_dhcp_server_name", (char *) bp->server_name,
 
464
                   sizeof (bp->server_name));
 
465
  parse_dhcp_vendor (&bp->vendor, sizeof (bp->vendor));
299
466
  grub_pxe_pxenv = pxenv;
300
467
}
301
468
 
311
478
    }
312
479
}
313
480
 
 
481
static void
 
482
set_ip_env (char *varname, grub_uint32_t ip)
 
483
{
 
484
  char buf[sizeof ("XXX.XXX.XXX.XXX")];
 
485
 
 
486
  grub_sprintf (buf, "%d.%d.%d.%d", (ip & 0xff),
 
487
                (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
 
488
  grub_env_set (varname, buf);
 
489
}
 
490
 
 
491
static char *
 
492
write_ip_env (grub_uint32_t *ip, const char *val)
 
493
{
 
494
  char *buf;
 
495
  grub_err_t err;
 
496
  grub_uint32_t newip;
 
497
  
 
498
  err = parse_ip (val, &newip, 0);
 
499
  if (err)
 
500
    return 0;
 
501
 
 
502
  /* Normalize the IP.  */
 
503
  buf = grub_malloc (sizeof ("XXX.XXX.XXX.XXX"));
 
504
  if (!buf)
 
505
    return 0;
 
506
 
 
507
  *ip = newip;
 
508
 
 
509
  grub_sprintf (buf, "%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff,
 
510
                (newip >> 16) & 0xff, (newip >> 24) & 0xff);
 
511
 
 
512
  return buf; 
 
513
}
 
514
 
 
515
static char *
 
516
grub_env_write_pxe_default_server (struct grub_env_var *var 
 
517
                                   __attribute__ ((unused)),
 
518
                                   const char *val)
 
519
{
 
520
  return write_ip_env (&grub_pxe_default_server_ip, val);
 
521
}
 
522
 
 
523
static char *
 
524
grub_env_write_pxe_default_gateway (struct grub_env_var *var
 
525
                                    __attribute__ ((unused)),
 
526
                                    const char *val)
 
527
{
 
528
  return write_ip_env (&grub_pxe_default_gateway_ip, val);
 
529
}
 
530
 
 
531
static char *
 
532
grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)),
 
533
                              const char *val)
 
534
{
 
535
  unsigned size;
 
536
  char *buf;
 
537
 
 
538
  size = grub_strtoul (val, 0, 0);
 
539
  if (grub_errno)
 
540
    return 0;
 
541
 
 
542
  if (size < GRUB_PXE_MIN_BLKSIZE)
 
543
    size = GRUB_PXE_MIN_BLKSIZE;
 
544
  else if (size > GRUB_PXE_MAX_BLKSIZE)
 
545
    size = GRUB_PXE_MAX_BLKSIZE;
 
546
  
 
547
  buf = grub_malloc (sizeof ("XXXXXX XXXXXX"));
 
548
  if (!buf)
 
549
    return 0;
 
550
 
 
551
  grub_sprintf (buf, "%d", size);
 
552
  grub_pxe_blksize = size;
 
553
  
 
554
  return buf;
 
555
}
 
556
 
 
557
 
314
558
GRUB_MOD_INIT(pxe)
315
559
{
316
560
  grub_pxe_detect ();
317
561
  if (grub_pxe_pxenv)
318
562
    {
 
563
      char *buf;
 
564
 
 
565
      buf = grub_malloc (sizeof ("XXXXXX XXXXXX"));
 
566
      if (buf)
 
567
        {
 
568
          grub_sprintf (buf, "%d", grub_pxe_blksize);
 
569
          grub_env_set ("net_pxe_blksize", buf);
 
570
        }
 
571
 
 
572
      set_ip_env ("pxe_default_server", grub_pxe_default_server_ip);
 
573
      set_ip_env ("pxe_default_gateway", grub_pxe_default_gateway_ip);
 
574
      set_ip_env ("net_pxe_ip", grub_pxe_your_ip);
 
575
      grub_register_variable_hook ("net_pxe_default_server", 0,
 
576
                                   grub_env_write_pxe_default_server);
 
577
      grub_register_variable_hook ("net_pxe_default_gateway", 0,
 
578
                                   grub_env_write_pxe_default_gateway);
 
579
 
 
580
      /* XXX: Is it possible to change IP in PXE?  */
 
581
      grub_register_variable_hook ("net_pxe_ip", 0,
 
582
                                   grub_env_write_readonly);
 
583
      grub_register_variable_hook ("net_pxe_blksize", 0,
 
584
                                   grub_env_write_pxe_blocksize);
319
585
      grub_disk_dev_register (&grub_pxe_dev);
320
586
      grub_fs_register (&grub_pxefs_fs);
321
587
    }