summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/cmdline.inc4
-rw-r--r--core/comboot.inc4
-rw-r--r--core/fs/btrfs/btrfs.c68
-rw-r--r--core/fs/chdir.c59
-rw-r--r--core/fs/diskio.c156
-rw-r--r--core/fs/fat/fat.c81
-rw-r--r--core/fs/fs.c68
-rw-r--r--core/fs/getcwd.c13
-rw-r--r--core/fs/getfssec.c4
-rw-r--r--core/fs/iso9660/iso9660.c29
-rw-r--r--core/fs/lib/loadconfig.c30
-rw-r--r--core/fs/lib/searchconfig.c40
-rw-r--r--core/fs/pxe/dhcp_option.c193
-rw-r--r--core/fs/pxe/dnsresolv.c95
-rw-r--r--core/fs/pxe/idle.c2
-rw-r--r--core/fs/pxe/pxe.c241
-rw-r--r--core/fs/pxe/pxe.h34
-rw-r--r--core/fs/readdir.c11
-rw-r--r--core/include/fs.h12
-rw-r--r--core/pxelinux.asm16
20 files changed, 675 insertions, 485 deletions
diff --git a/core/cmdline.inc b/core/cmdline.inc
index 7fa53816..3e63f9ab 100644
--- a/core/cmdline.inc
+++ b/core/cmdline.inc
@@ -48,12 +48,14 @@ make_plain_cmdline:
; Actual IPAppend strings...
;
%if IS_PXELINUX
- extern IPOption, BOOTIFStr
+ extern IPOption, BOOTIFStr, SYSUUIDStr
+ global IPAppends, numIPAppends
section .data16
alignz 2
IPAppends dw IPOption
dw BOOTIFStr
+ dw SYSUUIDStr
numIPAppends equ ($-IPAppends)/2
%else
IPAppends equ 0
diff --git a/core/comboot.inc b/core/comboot.inc
index 45b770f3..0c9956a0 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -580,8 +580,10 @@ comapi_derinfo:
mov P_SI,ax
mov ax,[InitStack+2]
mov P_FS,ax
- mov eax,[MyIP]
+ mov eax,[IPInfo.MyIP]
mov P_ECX,eax
+ mov P_GS,0
+ mov P_DI,IPInfo
%else
; Physical medium...
diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c
index 72dcbe92..b6a14e3b 100644
--- a/core/fs/btrfs/btrfs.c
+++ b/core/fs/btrfs/btrfs.c
@@ -11,6 +11,7 @@
*
*/
+#include <dprintf.h>
#include <stdio.h>
#include <string.h>
#include <cache.h>
@@ -54,12 +55,9 @@ static int bin_search(void *ptr, int item_size, void *cmp_item, cmp_func func,
return 1;
}
-static int cache_ready;
+/* XXX: these should go into the filesystem instance structure */
static struct btrfs_chunk_map chunk_map;
static struct btrfs_super_block sb;
-/* used for small chunk read for btrfs_read */
-#define RAW_BUF_SIZE 4096
-static u8 raw_buf[RAW_BUF_SIZE];
static u64 fs_tree;
static int btrfs_comp_chunk_map(struct btrfs_chunk_map_item *m1,
@@ -127,36 +125,8 @@ static u64 logical_physical(u64 logical)
chunk_map.map[slot-1].logical;
}
-/* raw read from disk, offset and count are bytes */
-static int raw_read(struct fs_info *fs, char *buf, u64 offset, u64 count)
-{
- struct disk *disk = fs->fs_dev->disk;
- size_t max = RAW_BUF_SIZE >> disk->sector_shift;
- size_t off, cnt, done, total;
- sector_t sec;
-
- total = count;
- while (count > 0) {
- sec = offset >> disk->sector_shift;
- off = offset - (sec << disk->sector_shift);
- done = disk->rdwr_sectors(disk, raw_buf, sec, max, 0);
- if (done == 0)/* no data */
- break;
- cnt = (done << disk->sector_shift) - off;
- if (cnt > count)
- cnt = count;
- memcpy(buf, raw_buf + off, cnt);
- count -= cnt;
- buf += cnt;
- offset += cnt;
- if (done != max)/* no enough sectors */
- break;
- }
- return total - count;
-}
-
/* cache read from disk, offset and count are bytes */
-static int cache_read(struct fs_info *fs, char *buf, u64 offset, u64 count)
+static int btrfs_read(struct fs_info *fs, char *buf, u64 offset, u64 count)
{
const char *cd;
size_t block_size = fs->fs_dev->cache_block_size;
@@ -181,13 +151,6 @@ static int cache_read(struct fs_info *fs, char *buf, u64 offset, u64 count)
return total - count;
}
-static int btrfs_read(struct fs_info *fs, char *buf, u64 offset, u64 count)
-{
- if (cache_ready)
- return cache_read(fs, buf, offset, count);
- return raw_read(fs, buf, offset, count);
-}
-
/* btrfs has several super block mirrors, need to calculate their location */
static inline u64 btrfs_sb_offset(int mirror)
{
@@ -207,9 +170,16 @@ static void btrfs_read_super_block(struct fs_info *fs)
u64 transid = 0;
struct btrfs_super_block buf;
+ sb.total_bytes = ~0; /* Unknown as of yet */
+
/* find most recent super block */
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
offset = btrfs_sb_offset(i);
+ dprintf("btrfs super: %llu max %llu\n",
+ offset, sb.total_bytes);
+ if (offset >= sb.total_bytes)
+ break;
+
ret = btrfs_read(fs, (char *)&buf, offset, sizeof(buf));
if (ret < sizeof(buf))
break;
@@ -560,10 +530,19 @@ static int btrfs_next_extent(struct inode *inode, uint32_t lstart)
ret = search_tree(fs, fs_tree, &search_key, &path);
if (ret) { /* impossible */
printf("btrfs: search extent data error!\n");
- return 0;
+ return -1;
}
extent_item = *(struct btrfs_file_extent_item *)path.data;
+ if (extent_item.encryption) {
+ printf("btrfs: found encrypted data, cannot continue!\n");
+ return -1;
+ }
+ if (extent_item.compression) {
+ printf("btrfs: found compressed data, cannot continue!\n");
+ return -1;
+ }
+
if (extent_item.type == BTRFS_FILE_EXTENT_INLINE) {/* inline file */
/* we fake a extent here, and PVT of inode will tell us */
offset = path.offsets[0] + sizeof(struct btrfs_header)
@@ -666,16 +645,15 @@ static int btrfs_fs_init(struct fs_info *fs)
fs->block_shift = BTRFS_BLOCK_SHIFT;
fs->block_size = 1 << fs->block_shift;
+ /* Initialize the block cache */
+ cache_init(fs->fs_dev, fs->block_shift);
+
btrfs_read_super_block(fs);
if (strncmp((char *)(&sb.magic), BTRFS_MAGIC, sizeof(sb.magic)))
return -1;
btrfs_read_sys_chunk_array();
btrfs_read_chunk_tree(fs);
btrfs_get_fs_tree(fs);
- cache_ready = 1;
-
- /* Initialize the block cache */
- cache_init(fs->fs_dev, fs->block_shift);
return fs->block_shift;
}
diff --git a/core/fs/chdir.c b/core/fs/chdir.c
index bfce9bce..9e8dfd2e 100644
--- a/core/fs/chdir.c
+++ b/core/fs/chdir.c
@@ -16,15 +16,56 @@ void pm_realpath(com32sys_t *regs)
realpath(dst, src, FILENAME_MAX);
}
+#define EMIT(x) \
+do { \
+ if (++n < bufsize) \
+ *q++ = (x); \
+} while (0)
+
+static size_t join_paths(char *dst, size_t bufsize,
+ const char *s1, const char *s2)
+{
+ const char *list[2];
+ int i;
+ char c;
+ const char *p;
+ char *q = dst;
+ size_t n = 0;
+ bool slash = false;
+
+ list[0] = s1;
+ list[1] = s2;
+
+ for (i = 0; i < 2; i++) {
+ p = list[i];
+
+ while ((c = *p++)) {
+ if (c == '/') {
+ if (!slash)
+ EMIT(c);
+ slash = true;
+ } else {
+ EMIT(c);
+ slash = false;
+ }
+ }
+ }
+
+ if (bufsize)
+ *q = '\0';
+
+ return n;
+}
+
size_t realpath(char *dst, const char *src, size_t bufsize)
{
if (this_fs->fs_ops->realpath) {
return this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
} else {
/* Filesystems with "common" pathname resolution */
- return snprintf(dst, bufsize, "%s%s",
- src[0] == '/' ? "" : this_fs->cwd_name,
- src);
+ return join_paths(dst, bufsize,
+ src[0] == '/' ? "" : this_fs->cwd_name,
+ src);
}
}
@@ -32,7 +73,7 @@ int chdir(const char *src)
{
int rv;
struct file *file;
- char *p;
+ char cwd_buf[CURRENTDIR_MAX];
if (this_fs->fs_ops->chdir)
return this_fs->fs_ops->chdir(this_fs, src);
@@ -53,14 +94,10 @@ int chdir(const char *src)
_close_file(file);
/* Save the current working directory */
- realpath(this_fs->cwd_name, src, CURRENTDIR_MAX);
- p = strchr(this_fs->cwd_name, '\0');
+ realpath(cwd_buf, src, CURRENTDIR_MAX);
/* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */
- if (p < this_fs->cwd_name + CURRENTDIR_MAX - 1 &&
- (p == this_fs->cwd_name || p[1] != '/')) {
- p[0] = '/';
- p[1] = '\0';
- }
+ join_paths(this_fs->cwd_name, CURRENTDIR_MAX, cwd_buf, "/");
+
return 0;
}
diff --git a/core/fs/diskio.c b/core/fs/diskio.c
index 464cca6d..d4901c3d 100644
--- a/core/fs/diskio.c
+++ b/core/fs/diskio.c
@@ -56,7 +56,7 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf,
t = xlba / disk->s;
h = t % disk->h;
c = t / disk->h;
-
+
ireg.eax.b[0] = chunk;
ireg.ecx.b[1] = c;
ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
@@ -65,11 +65,20 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf,
ireg.es = SEG(tptr);
retry = RETRY_COUNT;
-
+
for (;;) {
+ dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n",
+ ireg.edx.b[0], chunk, xlba, c, h, s+1,
+ ireg.es, ireg.ebx.w[0],
+ (ireg.eax.b[1] & 1) ? "<-" : "->",
+ ptr);
+
__intcall(0x13, &ireg, &oreg);
if (!(oreg.eflags.l & EFLAGS_CF))
break;
+
+ dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]);
+
if (retry--)
continue;
@@ -80,6 +89,11 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf,
retry = RETRY_COUNT;
ireg.eax.b[0] = chunk;
continue;
+ } else {
+ printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n",
+ oreg.eax.w[0],
+ is_write ? "writing" : "reading",
+ lba, c, h, s+1);
}
return done; /* Failure */
}
@@ -113,18 +127,22 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf,
char *tptr;
size_t chunk, freeseg;
int sector_shift = disk->sector_shift;
- com32sys_t ireg, oreg;
+ com32sys_t ireg, oreg, reset;
size_t done = 0;
size_t bytes;
int retry;
memset(&ireg, 0, sizeof ireg);
-
+
ireg.eax.b[1] = 0x42 + is_write;
ireg.edx.b[0] = disk->disk_number;
ireg.ds = SEG(&pkt);
ireg.esi.w[0] = OFFS(&pkt);
+ memset(&reset, 0, sizeof reset);
+
+ ireg.edx.b[0] = disk->disk_number;
+
lba += disk->part_start;
while (count) {
chunk = count;
@@ -157,12 +175,29 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf,
pkt.buf = FAR_PTR(tptr);
pkt.lba = lba;
+ dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n",
+ ireg.edx.b[0], pkt.blocks, pkt.lba,
+ pkt.buf.seg, pkt.buf.offs,
+ (ireg.eax.b[1] & 1) ? "<-" : "->",
+ ptr);
+
__intcall(0x13, &ireg, &oreg);
if (!(oreg.eflags.l & EFLAGS_CF))
break;
+
+ dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]);
+
if (retry--)
continue;
+ /*
+ * Some systems seem to get "stuck" in an error state when
+ * using EBIOS. Doesn't happen when using CBIOS, which is
+ * good, since some other systems get timeout failures
+ * waiting for the floppy disk to spin up.
+ */
+ __intcall(0x13, &reset, NULL);
+
/* For any starting value, this will always end with ..., 1, 0 */
chunk >>= 1;
if (chunk) {
@@ -172,7 +207,10 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf,
}
/*** XXX: Consider falling back to CHS here?! ***/
- printf("reading sectors error(EDD)\n");
+ printf("EDD: Error %04x %s sector %llu\n",
+ oreg.eax.w[0],
+ is_write ? "writing" : "reading",
+ lba);
return done; /* Failure */
}
@@ -216,7 +254,7 @@ static inline bool is_power_of_2(uint32_t x)
static int ilog2(uint32_t num)
{
int i = 0;
-
+
if (!is_power_of_2(num)) {
printf("ERROR: the num must be power of 2 when conveting to log2\n");
return 0;
@@ -241,57 +279,73 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
static struct disk disk;
static __lowmem struct edd_disk_params edd_params;
com32sys_t ireg, oreg;
- bool ebios = cdrom;
- int sector_size = cdrom ? 2048 : 512;
- unsigned int hard_max_transfer = ebios ? 127 : 63;
+ bool ebios;
+ int sector_size;
+ unsigned int hard_max_transfer;
memset(&ireg, 0, sizeof ireg);
-
- /* Get EBIOS support */
- ireg.eax.b[1] = 0x41;
- ireg.ebx.w[0] = 0x55aa;
ireg.edx.b[0] = devno;
- ireg.eflags.b[0] = 0x3; /* CF set */
- __intcall(0x13, &ireg, &oreg);
-
- if (cdrom || (!(oreg.eflags.l & EFLAGS_CF) &&
- oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1))) {
+ if (cdrom) {
+ /*
+ * The query functions don't work right on some CD-ROM stacks.
+ * Known affected systems: ThinkPad T22, T23.
+ */
+ sector_size = 2048;
ebios = true;
- hard_max_transfer = 127;
-
- /* Query EBIOS parameters */
- edd_params.len = sizeof edd_params;
-
- ireg.eax.b[1] = 0x48;
- ireg.ds = SEG(&edd_params);
- ireg.esi.w[0] = OFFS(&edd_params);
- __intcall(0x13, &ireg, &oreg);
-
- if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
- if (edd_params.len < sizeof edd_params)
- memset((char *)&edd_params + edd_params.len, 0,
- sizeof edd_params - edd_params.len);
- if (edd_params.sector_size >= 512 &&
- is_power_of_2(edd_params.sector_size))
- sector_size = edd_params.sector_size;
+ hard_max_transfer = 32;
+ } else {
+ sector_size = 512;
+ ebios = false;
+ hard_max_transfer = 63;
+
+ /* CBIOS parameters */
+ disk.h = bsHeads;
+ disk.s = bsSecPerTrack;
+
+ if ((int8_t)devno < 0) {
+ /* Get hard disk geometry from BIOS */
+
+ ireg.eax.b[1] = 0x08;
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF)) {
+ disk.h = oreg.edx.b[1] + 1;
+ disk.s = oreg.ecx.b[0] & 63;
+ }
}
- }
- /* CBIOS parameters */
- disk.h = bsHeads;
- disk.s = bsSecPerTrack;
+ /* Get EBIOS support */
+ ireg.eax.b[1] = 0x41;
+ ireg.ebx.w[0] = 0x55aa;
+ ireg.eflags.b[0] = 0x3; /* CF set */
- if ((int8_t)devno < 0) {
- /* Get hard disk geometry from BIOS */
-
- ireg.eax.b[1] = 0x08;
__intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF) &&
+ oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) {
+ ebios = true;
+ hard_max_transfer = 127;
+
+ /* Query EBIOS parameters */
+ edd_params.len = sizeof edd_params;
+
+ ireg.eax.b[1] = 0x48;
+ ireg.ds = SEG(&edd_params);
+ ireg.esi.w[0] = OFFS(&edd_params);
+ __intcall(0x13, &ireg, &oreg);
- if (!(oreg.eflags.l & EFLAGS_CF)) {
- disk.h = oreg.edx.b[1] + 1;
- disk.s = oreg.ecx.b[0] & 63;
+ if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
+ if (edd_params.len < sizeof edd_params)
+ memset((char *)&edd_params + edd_params.len, 0,
+ sizeof edd_params - edd_params.len);
+
+ if (edd_params.sector_size >= 512 &&
+ is_power_of_2(edd_params.sector_size))
+ sector_size = edd_params.sector_size;
+ }
}
+
}
disk.disk_number = devno;
@@ -306,11 +360,15 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
disk.maxtransfer = MaxTransfer;
+ dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
+ devno, cdrom, ebios, sector_size, disk.sector_shift,
+ part_start, disk.maxtransfer);
+
return &disk;
}
-/*
+/*
* Initialize the device structure.
*
* NOTE: the disk cache needs to be revamped to support multiple devices...
@@ -324,9 +382,9 @@ struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start,
dev.disk = disk_init(devno, cdrom, part_start,
bsHeads, bsSecPerTrack, MaxTransfer);
-
+
dev.cache_data = diskcache;
dev.cache_size = sizeof diskcache;
-
+
return &dev;
}
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index a21f4312..5902f481 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -6,6 +6,7 @@
#include <core.h>
#include <disk.h>
#include <fs.h>
+#include <ilog2.h>
#include <klibc/compiler.h>
#include "codepage.h"
#include "fat_fs.h"
@@ -19,7 +20,6 @@ static struct inode * new_fat_inode(struct fs_info *fs)
return inode;
}
-
/*
* Check for a particular sector in the FAT cache
*/
@@ -276,26 +276,32 @@ static void mangle_dos_name(char *mangle_buf, const char *src)
int i;
unsigned char c;
- i = 0;
- while (i < 11) {
- c = *src++;
-
+ if (src[0] == '.' && (!src[1] || (src[1] == '.' && !src[2]))) {
+ /* . and .. mangle to their respective zero-padded version */
+ i = stpcpy(mangle_buf, src) - mangle_buf;
+ } else {
+ i = 0;
+ while (i < 11) {
+ c = *src++;
+
if ((c <= ' ') || (c == '/'))
break;
-
+
if (c == '.') {
while (i < 8)
mangle_buf[i++] = ' ';
i = 8;
continue;
}
-
+
c = codepage.upper[c];
if (i == 0 && c == 0xe5)
c = 0x05; /* Special hack for the first byte only! */
-
+
mangle_buf[i++] = c;
+ }
}
+
while (i < 11)
mangle_buf[i++] = ' ';
@@ -408,7 +414,10 @@ static inline sector_t first_sector(struct fs_info *fs,
sector_t sector;
first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low;
- sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data;
+ if (first_clust == 0)
+ sector = sbi->root; /* first_clust == 0 means root directory */
+ else
+ sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data;
return sector;
}
@@ -533,7 +542,16 @@ found:
inode->size = de->file_size;
PVT(inode)->start_cluster =
(de->first_cluster_high << 16) + de->first_cluster_low;
- PVT(inode)->start = PVT(inode)->here = first_sector(fs, de);
+ if (PVT(inode)->start_cluster == 0) {
+ /* Root directory */
+ int root_size = FAT_SB(fs)->root_size;
+
+ PVT(inode)->start_cluster = FAT_SB(fs)->root_cluster;
+ inode->size = root_size ? root_size << fs->sector_shift : ~0;
+ PVT(inode)->start = PVT(inode)->here = FAT_SB(fs)->root;
+ } else {
+ PVT(inode)->start = PVT(inode)->here = first_sector(fs, de);
+ }
inode->mode = get_inode_mode(de->attr);
return inode;
@@ -696,45 +714,6 @@ got:
return 0;
}
-/* Load the config file, return 1 if failed, or 0 */
-static int vfat_load_config(void)
-{
- const char *search_directories[] = {
- "/boot/syslinux",
- "/syslinux",
- "/",
- NULL
- };
- com32sys_t regs;
- int i;
-
- /* If installed by extlinux, try the extlinux filename */
- if (*CurrentDirName && !generic_load_config())
- return 0;
-
- for (i = 0; search_directories[i]; i++) {
- memset(&regs, 0, sizeof regs);
- snprintf(ConfigName, FILENAME_MAX, "%s/syslinux.cfg",
- search_directories[i]);
- regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
- call16(core_open, &regs, &regs);
- if (!(regs.eflags.l & EFLAGS_ZF))
- break;
- }
- if (!search_directories[i])
- return -1;
-
- /* Set the current working directory */
- chdir(search_directories[i]);
- return 0;
-}
-
-static inline __constfunc uint32_t bsr(uint32_t num)
-{
- asm("bsrl %1,%0" : "=r" (num) : "rm" (num));
- return num;
-}
-
/* init. the fs meta data, return the block size in bits */
static int vfat_fs_init(struct fs_info *fs)
{
@@ -767,7 +746,7 @@ static int vfat_fs_init(struct fs_info *fs)
sbi->root_size = root_dir_size(fs, &fat);
sbi->data = sbi->root + sbi->root_size;
- sbi->clust_shift = bsr(fat.bxSecPerClust);
+ sbi->clust_shift = ilog2(fat.bxSecPerClust);
sbi->clust_byte_shift = sbi->clust_shift + fs->sector_shift;
sbi->clust_mask = fat.bxSecPerClust - 1;
sbi->clust_size = fat.bxSecPerClust << fs->sector_shift;
@@ -808,7 +787,7 @@ const struct fs_ops vfat_fs_ops = {
.getfssec = generic_getfssec,
.close_file = generic_close_file,
.mangle_name = vfat_mangle_name,
- .load_config = vfat_load_config,
+ .load_config = generic_load_config,
.readdir = vfat_readdir,
.iget_root = vfat_iget_root,
.iget = vfat_iget,
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 9b8e30f0..48856c9e 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -30,6 +30,18 @@ struct inode *alloc_inode(struct fs_info *fs, uint32_t ino, size_t data)
}
/*
+ * Free a refcounted inode
+ */
+void put_inode(struct inode *inode)
+{
+ while (inode && --inode->refcnt == 0) {
+ struct inode *dead = inode;
+ inode = inode->parent;
+ free(dead);
+ }
+}
+
+/*
* Get an empty file structure
*/
static struct file *alloc_file(void)
@@ -193,19 +205,14 @@ int searchdir(const char *name)
char *part, *p, echar;
int symlink_count = MAX_SYMLINK_CNT;
-// mp("enter: name = %s", name);
-
if (!(file = alloc_file()))
goto err_no_close;
-// mp("111");
file->fs = this_fs;
/* if we have ->searchdir method, call it */
if (file->fs->fs_ops->searchdir) {
file->fs->fs_ops->searchdir(name, file);
-// mp("this fs has searchdir(), inode = %d",file->inode);
-
if (file->inode)
return file_to_handle(file);
else
@@ -215,13 +222,10 @@ int searchdir(const char *name)
/* else, try the generic-path-lookup method */
parent = get_inode(this_fs->cwd);
-// mp("222");
p = pathbuf = strdup(name);
if (!pathbuf)
goto err;
- //mp("parent->ino = %d", parent->ino);
-
do {
got_link:
if (*p == '/') {
@@ -243,7 +247,20 @@ int searchdir(const char *name)
p++;
*p++ = '\0';
- if (part[0] != '.' || part[1] != '\0') {
+ if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
+ if (inode->parent) {
+ put_inode(parent);
+ parent = get_inode(inode->parent);
+ put_inode(inode);
+ inode = NULL;
+ if (!echar) {
+ /* Terminal double dots */
+ inode = parent;
+ parent = inode->parent ?
+ get_inode(inode->parent) : NULL;
+ }
+ }
+ } else if (part[0] != '.' || part[1] != '\0') {
inode = this_fs->fs_ops->iget(part, parent);
if (!inode)
goto err;
@@ -286,7 +303,7 @@ int searchdir(const char *name)
goto got_link;
}
- put_inode(parent);
+ inode->parent = parent;
parent = NULL;
if (!echar)
@@ -312,16 +329,11 @@ int searchdir(const char *name)
file->inode = inode;
file->offset = 0;
- dprintf("File %s -> %p (inode %p) len %u\n", name, file,
- inode, inode->size);
-
return file_to_handle(file);
err:
- if (inode)
- put_inode(inode);
- if (parent)
- put_inode(parent);
+ put_inode(inode);
+ put_inode(parent);
if (pathbuf)
free(pathbuf);
_close_file(file);
@@ -338,14 +350,20 @@ int open_file(const char *name, struct com32_filedata *filedata)
mangle_name(mangled_name, name);
rv = searchdir(mangled_name);
- //mp("name = %s, rv = %d", name, rv);
+ if (rv < 0)
+ return rv;
- if (rv >= 0) {
- file = handle_to_file(rv);
- filedata->size = file->inode->size;
- filedata->blocklg2 = SECTOR_SHIFT(file->fs);
- filedata->handle = rv;
+ file = handle_to_file(rv);
+
+ if (file->inode->mode != DT_REG) {
+ _close_file(file);
+ return -1;
}
+
+ filedata->size = file->inode->size;
+ filedata->blocklg2 = SECTOR_SHIFT(file->fs);
+ filedata->handle = rv;
+
return rv;
}
@@ -409,10 +427,8 @@ void fs_init(com32sys_t *regs)
/* ops is a ptr list for several fs_ops */
const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l;
- mp("enter");
-
/* Initialize malloc() */
- //mem_init();
+ mem_init();
/* Default name for the root directory */
fs.cwd_name[0] = '/';
diff --git a/core/fs/getcwd.c b/core/fs/getcwd.c
new file mode 100644
index 00000000..a7b6c7a9
--- /dev/null
+++ b/core/fs/getcwd.c
@@ -0,0 +1,13 @@
+#include <string.h>
+#include "fs.h"
+
+char *getcwd(char *buf, size_t size)
+{
+ char *ret = NULL;
+
+ if((buf != NULL) && (strlen(this_fs->cwd_name) < size)) {
+ strcpy(buf, this_fs->cwd_name);
+ ret = buf;
+ }
+ return ret;
+}
diff --git a/core/fs/getfssec.c b/core/fs/getfssec.c
index 3d62d4e6..e099b64e 100644
--- a/core/fs/getfssec.c
+++ b/core/fs/getfssec.c
@@ -144,6 +144,10 @@ uint32_t generic_getfssec(struct file *file, char *buf,
if (!inode->this_extent.len) {
/* Doesn't matter if it's contiguous... */
inode->this_extent = inode->next_extent;
+ if (!inode->next_extent.len) {
+ sectors = 0; /* Failed to get anything... we're dead */
+ break;
+ }
} else if (inode->next_extent.len &&
inode->next_extent.pstart == next_pstart(&inode->this_extent)) {
/* Coalesce extents and loop */
diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
index d695e439..62137d0d 100644
--- a/core/fs/iso9660/iso9660.c
+++ b/core/fs/iso9660/iso9660.c
@@ -273,30 +273,21 @@ static int iso_readdir(struct file *file, struct dirent *dirent)
/* Load the config file, return 1 if failed, or 0 */
static int iso_load_config(void)
{
- const char *search_directories[] = {
+ static const char *search_directories[] = {
"/boot/isolinux",
"/isolinux",
+ "/boot/syslinux",
+ "/syslinux",
"/",
NULL
};
- com32sys_t regs;
- int i;
-
- for (i = 0; search_directories[i]; i++) {
- memset(&regs, 0, sizeof regs);
- snprintf(ConfigName, FILENAME_MAX, "%s/isolinux.cfg",
- search_directories[i]);
- regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
- call16(core_open, &regs, &regs);
- if (!(regs.eflags.l & EFLAGS_ZF))
- break;
- }
- if (!search_directories[i])
- return -1;
-
- /* Set the current working directory */
- chdir(search_directories[i]);
- return 0;
+ static const char *filenames[] = {
+ "isolinux.cfg",
+ "syslinux.cfg",
+ NULL
+ };
+
+ return search_config(search_directories, filenames);
}
static int iso_fs_init(struct fs_info *fs)
diff --git a/core/fs/lib/loadconfig.c b/core/fs/lib/loadconfig.c
index 9318c1c3..c9652b6c 100644
--- a/core/fs/lib/loadconfig.c
+++ b/core/fs/lib/loadconfig.c
@@ -5,20 +5,30 @@
#include <fs.h>
/*
- * Standard version of load_config for extlinux-installed filesystems
+ * Standard version of load_config for extlinux/syslinux filesystems.
+ *
+ * This searches for extlinux.conf and syslinux.cfg in the install
+ * directory, followed by a set of fallback directories. If found,
+ * set the current working directory to match.
*/
int generic_load_config(void)
{
- com32sys_t regs;
+ static const char *search_directories[] = {
+ NULL, /* CurrentDirName */
+ "/boot/syslinux",
+ "/syslinux",
+ "/",
+ NULL
+ };
+ static const char *filenames[] = {
+ "extlinux.conf",
+ "syslinux.cfg",
+ NULL
+ };
- chdir(CurrentDirName);
- realpath(ConfigName, "extlinux.conf", FILENAME_MAX);
+ search_directories[0] = CurrentDirName;
- dprintf("Config = %s\n", ConfigName);
+ dprintf("CurrentDirName: \"%s\"\n", CurrentDirName);
- memset(&regs, 0, sizeof regs);
- regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
- call16(core_open, &regs, &regs);
-
- return (regs.eflags.l & EFLAGS_ZF) ? -1 : 0;
+ return search_config(search_directories, filenames);
}
diff --git a/core/fs/lib/searchconfig.c b/core/fs/lib/searchconfig.c
new file mode 100644
index 00000000..24bfde31
--- /dev/null
+++ b/core/fs/lib/searchconfig.c
@@ -0,0 +1,40 @@
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+
+/*
+ * Common implementation of load_config
+ *
+ * This searches for a specified set of filenames in a specified set
+ * of directories. If found, set the current working directory to
+ * match.
+ */
+int search_config(const char *search_directories[], const char *filenames[])
+{
+ char confignamebuf[FILENAME_MAX];
+ com32sys_t regs;
+ const char *sd, **sdp;
+ const char *sf, **sfp;
+
+ for (sdp = search_directories; (sd = *sdp); sdp++) {
+ for (sfp = filenames; (sf = *sfp); sfp++) {
+ memset(&regs, 0, sizeof regs);
+ snprintf(confignamebuf, sizeof confignamebuf,
+ "%s%s%s",
+ sd, (*sd && sd[strlen(sd)-1] == '/') ? "" : "/",
+ sf);
+ realpath(ConfigName, confignamebuf, FILENAME_MAX);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ dprintf("Config search: %s\n", ConfigName);
+ call16(core_open, &regs, &regs);
+ if (!(regs.eflags.l & EFLAGS_ZF)) {
+ chdir(sd);
+ return 0; /* Got it */
+ }
+ }
+ }
+
+ return -1;
+}
diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
index e18b605d..50f2de04 100644
--- a/core/fs/pxe/dhcp_option.c
+++ b/core/fs/pxe/dhcp_option.c
@@ -8,93 +8,87 @@ char LocalDomain[256];
int over_load;
uint8_t uuid_type;
-char uuid[17];
+uint8_t uuid[16];
-static void parse_dhcp_options(void *, int, uint8_t);
+static void parse_dhcp_options(const void *, int, uint8_t);
-static void subnet_mask(void *data, int opt_len)
+static void subnet_mask(const void *data, int opt_len)
{
if (opt_len != 4)
return;
- net_mask = *(uint32_t *)data;
+ IPInfo.netmask = *(const uint32_t *)data;
}
-static void router(void *data, int opt_len)
+static void router(const void *data, int opt_len)
{
if (opt_len != 4)
return;
- gate_way = *(uint32_t *)data;
+ IPInfo.gateway = *(const uint32_t *)data;
}
-static void dns_servers(void *data, int opt_len)
+static void dns_servers(const void *data, int opt_len)
{
- int num = opt_len >> 2;
- int i;
+ const uint32_t *dp = data;
+ int num = 0;
- if (num > DNS_MAX_SERVERS)
- num = DNS_MAX_SERVERS;
+ while (num < DNS_MAX_SERVERS) {
+ uint32_t ip;
- for (i = 0; i < num; i++) {
- dns_server[i] = *(uint32_t *)data;
- data += 4;
- }
+ if (opt_len < 4)
+ break;
-#if 0
- /*
- * if you find you got no corret DNS server, you can add
- * it here manually. BUT be carefull the DNS_MAX_SERVERS
- */
- if (i < DNS_MAX_SERVERS ) {
- dns_server[i++] = your_master_dns_server;
- dns_server[i++] = your_second_dns_server;
+ opt_len -= 4;
+ ip = *dp++;
+ if (ip_ok(ip))
+ dns_server[num++] = ip;
}
-#endif
+ while (num < DNS_MAX_SERVERS)
+ dns_server[num++] = 0;
}
-static void local_domain(void *data, int opt_len)
+static void local_domain(const void *data, int opt_len)
{
- char *p = (char *)data + opt_len;
+ char buffer[256];
char *ld = LocalDomain;
- char end = *p;
-
- *p = '\0'; /* Zero-terminate option */
- dns_mangle(&ld, data);
- *p = end; /* Restore ending byte */
+
+ memcpy(buffer, data, opt_len);
+ buffer[opt_len] = 0;
+
+ dns_mangle(&ld, buffer);
}
-static void vendor_encaps(void *data, int opt_len)
+static void vendor_encaps(const void *data, int opt_len)
{
- /* Only recongnize PXELINUX options */
+ /* Only recognize PXELINUX options */
parse_dhcp_options(data, opt_len, 208);
}
-static void option_overload(void *data, int opt_len)
+static void option_overload(const void *data, int opt_len)
{
if (opt_len != 1)
return;
over_load = *(uint8_t *)data;
}
-
-static void server(void *data, int opt_len)
+static void server(const void *data, int opt_len)
{
uint32_t ip;
if (opt_len != 4)
return;
-
- if (server_ip)
+
+ if (IPInfo.serverip)
return;
-
+
ip = *(uint32_t *)data;
if (ip_ok(ip))
- server_ip = ip;
+ IPInfo.serverip = ip;
}
-static void client_identifier(void *data, int opt_len)
+static void client_identifier(const void *data, int opt_len)
{
if (opt_len > MAC_MAX || opt_len < 2 ||
- MAC_len != (opt_len >> 8) ||
+ MAC_len != (opt_len >> 8) ||
*(uint8_t *)data != MAC_type)
return;
@@ -104,54 +98,53 @@ static void client_identifier(void *data, int opt_len)
MAC[opt_len] = 0;
}
-static void bootfile_name(void *data, int opt_len)
+static void bootfile_name(const void *data, int opt_len)
{
- strncpy(boot_file, data, opt_len);
+ memcpy(boot_file, data, opt_len);
boot_file[opt_len] = 0;
}
-
-static void uuid_client_identifier(void *data, int opt_len)
+
+static void uuid_client_identifier(const void *data, int opt_len)
{
- int type = *(uint8_t *)data;
+ int type = *(const uint8_t *)data;
if (opt_len != 17 || type != 0 || have_uuid)
return;
have_uuid = true;
uuid_type = type;
memcpy(uuid, data+1, 16);
- uuid[16] = 0;
}
-static void pxelinux_configfile(void *data, int opt_len)
+static void pxelinux_configfile(const void *data, int opt_len)
{
DHCPMagic |= 2;
- strncpy(ConfigName, data, opt_len);
+ memcpy(ConfigName, data, opt_len);
ConfigName[opt_len] = 0;
}
-static void pxelinux_pathprefix(void *data, int opt_len)
+static void pxelinux_pathprefix(const void *data, int opt_len)
{
DHCPMagic |= 4;
- strncpy(path_prefix, data, opt_len);
+ memcpy(path_prefix, data, opt_len);
path_prefix[opt_len] = 0;
}
-static void pxelinux_reboottime(void *data, int opt_len)
+static void pxelinux_reboottime(const void *data, int opt_len)
{
- if ((opt_len && 0xff) != 4)
- return ;
-
- RebootTime = ntohl(*(uint32_t *)data);
+ if (opt_len != 4)
+ return;
+
+ RebootTime = ntohl(*(const uint32_t *)data);
DHCPMagic |= 8; /* Got reboot time */
}
struct dhcp_options {
int opt_num;
- void (*fun) (void *, int);
+ void (*fun)(const void *, int);
};
-static struct dhcp_options dhcp_opts[] = {
+static const struct dhcp_options dhcp_opts[] = {
{1, subnet_mask},
{3, router},
{6, dns_servers},
@@ -168,56 +161,54 @@ static struct dhcp_options dhcp_opts[] = {
};
/*
- * Parse a sequence of DHCP options, pointed to by _option_;
+ * Parse a sequence of DHCP options, pointed to by _option_;
* -- some DHCP servers leave option fields unterminated
* in violation of the spec.
*
* filter contains the minimum value for the option to recognize
* -- this is used to restrict parsing to PXELINUX-specific options only.
- */
-static void parse_dhcp_options(void *option, int size, uint8_t opt_filter)
+ */
+static void parse_dhcp_options(const void *option, int size, uint8_t opt_filter)
{
- uint8_t opt_num;
- uint8_t opt_len;
- int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]);
+ int opt_num;
+ int opt_len;
+ const int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]);
int i = 0;
- char *p = option;
- struct dhcp_options *opt;
-
- while (size--) {
+ const uint8_t *p = option;
+ const struct dhcp_options *opt;
+
+ /* The only 1-byte options are 00 and FF, neither of which matter */
+ while (size >= 2) {
opt_num = *p++;
+ size--;
- if (!size)
- break;
if (opt_num == 0)
continue;
if (opt_num == 0xff)
break;
-
- /* Anything else will have a lenght filed */
+
+ /* Anything else will have a length field */
opt_len = *p++; /* c <- option lenght */
- size = size - opt_len - 1;
+ size -= opt_len + 1;
if (size < 0)
break;
- if (opt_num < opt_filter) { /* Is the option value valid */
- option += opt_len; /* Try next */
- continue;
- }
-
- opt = dhcp_opts;
- for (i = 0; i < opt_entries; i++) {
- if (opt_num == opt->opt_num) {
- opt->fun(p, opt_len);
- break;
- }
- opt ++;
- }
-
+
+ if (opt_num >= opt_filter) {
+ opt = dhcp_opts;
+ for (i = 0; i < opt_entries; i++) {
+ if (opt_num == opt->opt_num) {
+ opt->fun(p, opt_len);
+ break;
+ }
+ opt++;
+ }
+ }
+
/* parse next */
p += opt_len;
}
}
-
+
/*
* parse_dhcp
*
@@ -244,22 +235,24 @@ void parse_dhcp(int pkt_len)
struct bootp_t *dhcp = (struct bootp_t *)trackbuf;
int opt_len;
+ IPInfo.ipv4 = 4; /* This is IPv4 only for now... */
+
over_load = 0;
if (ip_ok(dhcp->yip))
- MyIP = dhcp->yip;
-
+ IPInfo.myip = dhcp->yip;
+
if (ip_ok(dhcp->sip))
- server_ip = dhcp->sip;
-
+ IPInfo.serverip = dhcp->sip;
+
opt_len = (char *)dhcp + pkt_len - (char *)&dhcp->options;
- if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC))
+ if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC))
parse_dhcp_options(&dhcp->options, opt_len, 0);
- if (over_load & 1)
+ if (over_load & 1)
parse_dhcp_options(&dhcp->bootfile, 128, 0);
- else if (dhcp->bootfile[0])
- strcpy(boot_file, dhcp->bootfile);
-
- if (over_load & 2)
+ else if (dhcp->bootfile[0])
+ strcpy(boot_file, dhcp->bootfile);
+
+ if (over_load & 2)
parse_dhcp_options(dhcp->sname, 64, 0);
-}
+}
diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c
index df7f33c1..2b263fad 100644
--- a/core/fs/pxe/dnsresolv.c
+++ b/core/fs/pxe/dnsresolv.c
@@ -35,7 +35,7 @@ struct dnsquery {
} __attribute__ ((packed));
/*
- * The DNS Resource recodes structure
+ * The DNS Resource recodes structure
*/
struct dnsrr {
uint16_t type;
@@ -50,7 +50,7 @@ uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
/*
- * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
+ * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
* number of dots encountered. On return, *dst is updated.
*/
int dns_mangle(char **dst, const char *p)
@@ -58,14 +58,14 @@ int dns_mangle(char **dst, const char *p)
char *q = *dst;
char *count_ptr;
char c;
- int dots = 0;
+ int dots = 0;
count_ptr = q;
*q++ = 0;
while (1) {
c = *p++;
- if (c == 0 || c == ':')
+ if (c == 0 || c == ':' || c == '/')
break;
if (c == '.') {
dots++;
@@ -73,7 +73,7 @@ int dns_mangle(char **dst, const char *p)
*q++ = 0;
continue;
}
-
+
*count_ptr += 1;
*q++ = c;
}
@@ -85,7 +85,7 @@ int dns_mangle(char **dst, const char *p)
*dst = q;
return dots;
}
-
+
/*
* Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_
@@ -126,7 +126,7 @@ static void *dns_copylabel(void *dst, const void *src, const void *buf)
uint8_t *q = dst;
const uint8_t *p = src;
unsigned int c0, c1;
-
+
while (1) {
c0 = p[0];
if (c0 >= 0xc0) {
@@ -151,7 +151,7 @@ static void *dns_copylabel(void *dst, const void *src, const void *buf)
static char *dns_skiplabel(char *label)
{
uint8_t c;
-
+
while (1) {
c = *label++;
if (c >= 0xc0)
@@ -184,16 +184,20 @@ uint32_t dns_resolv(const char *name)
const uint8_t *timeout_ptr = TimeoutTable;
uint32_t oldtime;
uint32_t srv;
- uint32_t *srv_ptr = dns_server;
+ uint32_t *srv_ptr;
struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf;
- struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf;
+ struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf;
struct dnsquery *query;
struct dnsrr *rr;
static __lowmem struct s_PXENV_UDP_WRITE udp_write;
- static __lowmem struct s_PXENV_UDP_READ udp_read;
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
uint16_t local_port;
uint32_t result = 0;
+ /* Make sure we have at least one valid DNS server */
+ if (!dns_server[0])
+ return 0;
+
/* Get a local port number */
local_port = get_port();
@@ -204,68 +208,61 @@ uint32_t dns_resolv(const char *name)
hd1->ancount = 0; /* No answers */
hd1->nscount = 0; /* No NS */
hd1->arcount = 0; /* No AR */
-
+
p = DNSSendBuf + sizeof(struct dnshdr);
dots = dns_mangle(&p, name); /* store the CNAME */
-
+
if (!dots) {
p--; /* Remove final null */
/* Uncompressed DNS label set so it ends in null */
- strcpy(p, LocalDomain);
+ strcpy(p, LocalDomain);
}
-
+
/* Fill the DNS query packet */
query = (struct dnsquery *)p;
query->qtype = htons(TYPE_A);
query->qclass = htons(CLASS_IN);
p += sizeof(struct dnsquery);
-
+
/* Now send it to name server */
timeout_ptr = TimeoutTable;
timeout = *timeout_ptr++;
- while (srv_ptr < dns_server + DNS_MAX_SERVERS) {
- srv = *srv_ptr++;
- if (!srv)
- continue; /* just move on before runing the time out */
+ srv_ptr = dns_server;
+ while (timeout) {
+ srv = *srv_ptr++;
+ if (!srv) {
+ srv_ptr = dns_server;
+ srv = *srv_ptr++;
+ }
+
udp_write.status = 0;
udp_write.ip = srv;
- udp_write.gw = ((srv ^ MyIP) & net_mask) ? gate_way : 0;
+ udp_write.gw = gateway(srv);
udp_write.src_port = local_port;
udp_write.dst_port = DNS_PORT;
udp_write.buffer_size = p - DNSSendBuf;
udp_write.buffer = FAR_PTR(DNSSendBuf);
err = pxe_call(PXENV_UDP_WRITE, &udp_write);
- if (err || udp_write.status != 0)
+ if (err || udp_write.status)
continue;
-
+
oldtime = jiffies();
- while (1) {
+ do {
+ if (jiffies() - oldtime >= timeout)
+ goto again;
+
udp_read.status = 0;
udp_read.src_ip = srv;
- udp_read.dest_ip = MyIP;
+ udp_read.dest_ip = IPInfo.myip;
udp_read.s_port = DNS_PORT;
udp_read.d_port = local_port;
- udp_read.buffer_size = DNS_MAX_PACKET;
+ udp_read.buffer_size = PKTBUF_SIZE;
udp_read.buffer = FAR_PTR(DNSRecvBuf);
err = pxe_call(PXENV_UDP_READ, &udp_read);
- if (err || udp_read.status)
- continue;
-
- /* Got a packet, deal with it... */
- if (hd2->id == hd1->id)
- break;
-
- if (jiffies()-oldtime >= timeout) {
- /* time out */
- timeout = *timeout_ptr++;
- if (!timeout)
- goto done; /* All time ticks run out */
- else
- goto again;
- }
- }
+ } while (err || udp_read.status || hd2->id != hd1->id);
+
if ((hd2->flags ^ 0x80) & htons(0xf80f))
- goto badness;
+ goto badness;
ques = htons(hd2->qdcount); /* Questions */
reps = htons(hd2->ancount); /* Replies */
@@ -302,7 +299,7 @@ uint32_t dns_resolv(const char *name)
default:
break;
}
- }
+ }
/* not the one we want, try next */
p += sizeof(struct dnsrr) + rd_len;
@@ -319,13 +316,13 @@ uint32_t dns_resolv(const char *name)
; domain doesn't exist. If this turns out to be a
; problem, we may want to add code to go through all
; the servers before giving up.
-
+
; If the DNS server wasn't capable of recursion, and
; isn't capable of giving us an authoritative reply
; (i.e. neither AA or RA set), then at least try a
; different setver...
*/
- if (hd2->flags == htons(0x480))
+ if (hd2->flags == htons(0x480))
continue;
break; /* failed */
@@ -339,10 +336,10 @@ done:
return result;
}
-
-
+
+
/*
- * the one should be called from ASM file
+ * the one should be called from ASM file
*/
void pxe_dns_resolv(com32sys_t *regs)
{
diff --git a/core/fs/pxe/idle.c b/core/fs/pxe/idle.c
index 0538b163..52a87c34 100644
--- a/core/fs/pxe/idle.c
+++ b/core/fs/pxe/idle.c
@@ -27,7 +27,7 @@ static int pxe_idle_poll(void)
memset(&read_buf, 0, sizeof read_buf);
read_buf.src_ip = 0; /* Any destination */
- read_buf.dest_ip = MyIP;
+ read_buf.dest_ip = IPInfo.myip;
read_buf.s_port = 0; /* Any source port */
read_buf.d_port = htons(9); /* Discard port (not used...) */
read_buf.buffer_size = sizeof junk_pkt;
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index 011ef293..25bd094d 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -9,17 +9,16 @@
#define GPXE 1
-uint32_t server_ip = 0; /* IP address of boot server */
-uint32_t net_mask = 0; /* net_mask of this subnet */
-uint32_t gate_way = 0; /* Default router */
-uint16_t real_base_mem; /* Amount of DOS memory after freeing */
+static uint16_t real_base_mem; /* Amount of DOS memory after freeing */
uint8_t MAC[MAC_MAX]; /* Actual MAC address */
uint8_t MAC_len; /* MAC address len */
uint8_t MAC_type; /* MAC address type */
char __bss16 BOOTIFStr[7+3*(MAC_MAX+1)];
-#define MAC_str (BOOTIFStr+7)
+#define MAC_str (BOOTIFStr+7) /* The actual hardware address */
+char __bss16 SYSUUIDStr[8+32+5];
+#define UUID_str (SYSUUIDStr+8) /* The actual UUID */
char boot_file[256]; /* From DHCP */
char path_prefix[256]; /* From DHCP */
@@ -27,7 +26,6 @@ char dot_quad_buf[16];
static bool has_gpxe;
static uint32_t gpxe_funcs;
-static uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0};
bool have_uuid = false;
/* Common receive buffer */
@@ -70,6 +68,7 @@ static struct inode *allocate_socket(struct fs_info *fs)
} else {
struct pxe_pvt_inode *socket = PVT(inode);
socket->tftp_localport = get_port();
+ inode->mode = DT_REG; /* No other types relevant for PXE */
}
return inode;
@@ -175,15 +174,17 @@ static int hexbyte(const char *p)
* assignable unicast addresses in the near future.
*
*/
-int ip_ok(uint32_t ip)
+bool ip_ok(uint32_t ip)
{
- if (ip == -1 || /* Refuse the all-one address */
- (ip & 0xff) == 0 || /* Refuse network zero */
- (ip & 0xff) == 0xff || /* Refuse loopback */
- (ip & 0xf0) == 0xe0 ) /* Refuse class D */
- return 0;
+ uint8_t ip_hi = (uint8_t)ip; /* First octet of the ip address */
+
+ if (ip == 0xffffffff || /* Refuse the all-ones address */
+ ip_hi == 0 || /* Refuse network zero */
+ ip_hi == 127 || /* Refuse the loopback network */
+ (ip_hi & 240) == 224) /* Refuse class D */
+ return false;
- return 1;
+ return true;
}
@@ -297,7 +298,7 @@ static void tftp_error(struct inode *inode, uint16_t errnum,
udp_write.src_port = socket->tftp_localport;
udp_write.dst_port = socket->tftp_remoteport;
udp_write.ip = socket->tftp_remoteip;
- udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0;
+ udp_write.gw = gateway(udp_write.ip);
udp_write.buffer = FAR_PTR(&err_buf);
udp_write.buffer_size = 4 + len + 1;
@@ -326,7 +327,7 @@ static void ack_packet(struct inode *inode, uint16_t ack_num)
udp_write.src_port = socket->tftp_localport;
udp_write.dst_port = socket->tftp_remoteport;
udp_write.ip = socket->tftp_remoteip;
- udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0;
+ udp_write.gw = gateway(udp_write.ip);
udp_write.buffer = FAR_PTR(ack_packet_buf);
udp_write.buffer_size = 4;
@@ -390,7 +391,7 @@ static enum pxe_path_type pxe_path_type(const char *str)
else
return PXE_TFTP;
} else if (p > str && p[1] == '/' && p[2] == '/') {
- if (strncasecmp(str, "tftp://", 7))
+ if (!strncasecmp(str, "tftp://", 7))
return PXE_URL_TFTP;
else
return PXE_URL;
@@ -480,7 +481,7 @@ static void fill_buffer(struct inode *inode)
{
int err;
int last_pkt;
- const uint8_t *timeout_ptr = TimeoutTable;
+ const uint8_t *timeout_ptr;
uint8_t timeout;
uint16_t buffersize;
uint32_t oldtime;
@@ -513,7 +514,7 @@ static void fill_buffer(struct inode *inode)
udp_read.buffer = FAR_PTR(packet_buf);
udp_read.buffer_size = PKTBUF_SIZE;
udp_read.src_ip = socket->tftp_remoteip;
- udp_read.dest_ip = MyIP;
+ udp_read.dest_ip = IPInfo.myip;
udp_read.s_port = socket->tftp_remoteport;
udp_read.d_port = socket->tftp_localport;
err = pxe_call(PXENV_UDP_READ, &udp_read);
@@ -638,7 +639,7 @@ static uint32_t pxe_getfssec(struct file *file, char *buf,
* @param:filename, the file we wanna open
*
* @out: open_file_t structure, stores in file->open_file
- * @ouT: the lenght of this file, stores in file->file_len
+ * @out: the lenght of this file, stores in file->file_len
*
*/
static void pxe_searchdir(const char *filename, struct file *file)
@@ -660,6 +661,7 @@ static void pxe_searchdir(const char *filename, struct file *file)
int i = 0;
int err;
int buffersize;
+ int rrq_len;
const uint8_t *timeout_ptr;
uint32_t timeout;
uint32_t oldtime;
@@ -688,12 +690,12 @@ static void pxe_searchdir(const char *filename, struct file *file)
case PXE_RELATIVE: /* Really shouldn't happen... */
case PXE_URL:
buf = stpcpy(buf, filename);
- ip = server_ip; /* Default server */
+ ip = IPInfo.serverip; /* Default server */
break;
case PXE_HOMESERVER:
buf = stpcpy(buf, filename+2);
- ip = server_ip;
+ ip = IPInfo.serverip;
break;
case PXE_TFTP:
@@ -708,8 +710,8 @@ static void pxe_searchdir(const char *filename, struct file *file)
while (*np && *np != '/' && *np != ':')
np++;
if (np > filename + 7) {
- if (parse_dotquad(filename, &ip) != np)
- ip = dns_resolv(filename);
+ if (parse_dotquad(filename + 7, &ip) != np)
+ ip = dns_resolv(filename + 7);
}
if (*np == ':') {
np++;
@@ -733,6 +735,7 @@ static void pxe_searchdir(const char *filename, struct file *file)
*buf++ = *np++;
}
}
+ *buf = '\0';
break;
}
@@ -743,16 +746,13 @@ static void pxe_searchdir(const char *filename, struct file *file)
memcpy(buf, rrq_tail, sizeof rrq_tail);
buf += sizeof rrq_tail;
+ rrq_len = buf - rrq_packet_buf;
+
inode = allocate_socket(fs);
if (!inode)
return; /* Allocation failure */
socket = PVT(inode);
- timeout_ptr = TimeoutTable; /* Reset timeout */
- timeout = *timeout_ptr;
- oldtime = jiffies();
-
-sendreq:
#if GPXE
if (path_type == PXE_URL) {
if (has_gpxe) {
@@ -777,36 +777,44 @@ sendreq:
}
#endif /* GPXE */
+ timeout_ptr = TimeoutTable; /* Reset timeout */
+
+sendreq:
+ timeout = *timeout_ptr++;
+ if (!timeout)
+ return; /* No file available... */
+ oldtime = jiffies();
+
socket->tftp_remoteip = ip;
tid = socket->tftp_localport; /* TID(local port No) */
udp_write.buffer = FAR_PTR(rrq_packet_buf);
udp_write.ip = ip;
- udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0;
+ udp_write.gw = gateway(udp_write.ip);
udp_write.src_port = tid;
udp_write.dst_port = server_port;
- udp_write.buffer_size = buf - rrq_packet_buf;
- err = pxe_call(PXENV_UDP_WRITE, &udp_write);
+ udp_write.buffer_size = rrq_len;
+ pxe_call(PXENV_UDP_WRITE, &udp_write);
/* If the WRITE call fails, we let the timeout take care of it... */
wait_pkt:
for (;;) {
buf = packet_buf;
+ udp_read.status = 0;
udp_read.buffer = FAR_PTR(buf);
udp_read.buffer_size = PKTBUF_SIZE;
- udp_read.dest_ip = MyIP;
+ udp_read.dest_ip = IPInfo.myip;
udp_read.d_port = tid;
err = pxe_call(PXENV_UDP_READ, &udp_read);
- if (err) {
+ if (err || udp_read.status) {
uint32_t now = jiffies();
- if (now-oldtime >= timeout)
- goto failure;
- continue;
- }
-
- /* Make sure the packet actually came from the server */
- if (udp_read.src_ip == socket->tftp_remoteip)
- break;
+ if (now - oldtime >= timeout)
+ goto sendreq;
+ } else {
+ /* Make sure the packet actually came from the server */
+ if (udp_read.src_ip == socket->tftp_remoteip)
+ break;
+ }
}
socket->tftp_remoteport = udp_read.s_port;
@@ -817,7 +825,7 @@ wait_pkt:
socket->tftp_blksize = TFTP_BLOCKSIZE;
buffersize = udp_read.buffer_size - 2; /* bytes after opcode */
if (buffersize < 0)
- goto failure; /* Garbled reply */
+ goto wait_pkt; /* Garbled reply */
/*
* Get the opcode type, and parse it
@@ -841,12 +849,12 @@ wait_pkt:
*/
buffersize -= 2;
if (buffersize < 0)
- goto failure;
+ goto wait_pkt;
data = packet_buf + 2;
blk_num = *(uint16_t *)data;
data += 2;
if (blk_num != htons(1))
- goto failure;
+ goto wait_pkt;
socket->tftp_lastpkt = blk_num;
if (buffersize > TFTP_BLOCKSIZE)
goto err_reply; /* Corrupt */
@@ -955,15 +963,6 @@ err_reply:
tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
printf("TFTP server sent an incomprehesible reply\n");
kaboom();
-
-failure:
- if (jiffies() - oldtime < timeout)
- goto wait_pkt;
-
- /* Otherwise, we need to try again */
- timeout_ptr++;
- if (*timeout_ptr)
- goto sendreq; /* Try again */
}
@@ -1048,6 +1047,7 @@ static int try_load(char *config_name)
regs.edi.w[0] = OFFS_WRT(KernelName, 0);
call16(core_open, &regs, &regs);
if (regs.eflags.l & EFLAGS_ZF) {
+ strcpy(ConfigName, KernelName);
printf("\r");
return 0;
} else {
@@ -1064,39 +1064,23 @@ static int pxe_load_config(void)
const char *default_str = "default";
char *config_file;
char *last;
- char *p;
- uint8_t *uuid_ptr;
int tries = 8;
get_prefix();
if (DHCPMagic & 0x02) {
/* We got a DHCP option, try it first */
- if (try_load(boot_file))
+ if (try_load(ConfigName))
return 0;
}
/*
* Have to guess config file name ...
*/
- memcpy(ConfigName, cfgprefix, strlen(cfgprefix));
- config_file = ConfigName + strlen(cfgprefix);
+ config_file = stpcpy(ConfigName, cfgprefix);
/* Try loading by UUID */
if (have_uuid) {
- uuid_ptr = uuid_dashes;
- p = config_file;
- while (*uuid_ptr) {
- int len = *uuid_ptr;
- char *src = uuid;
-
- lchexbytes(p, src, len);
- p += len * 2;
- src += len;
- uuid_ptr++;
- *p++ = '-';
- }
- /* Remove last dash and zero-terminate */
- *--p = '\0';
+ strcpy(config_file, UUID_str);
if (try_load(ConfigName))
return 0;
}
@@ -1107,7 +1091,7 @@ static int pxe_load_config(void)
return 0;
/* Nope, try hexadecimal IP prefixes... */
- uchexbytes(config_file, (uint8_t *)&MyIP, 4); /* Convet to hex string */
+ uchexbytes(config_file, (uint8_t *)&IPInfo.myip, 4);
last = &config_file[8];
while (tries) {
*last = '\0'; /* Zero-terminate string */
@@ -1127,7 +1111,7 @@ static int pxe_load_config(void)
}
/*
- * Generate the botif string, and the hardware-based config string
+ * Generate the bootif string.
*/
static void make_bootif_string(void)
{
@@ -1140,6 +1124,35 @@ static void make_bootif_string(void)
for (i = MAC_len; i; i--)
dst += sprintf(dst, "-%02x", *src++);
}
+/*
+ * Generate the SYSUUID string, if we have one...
+ */
+static void make_sysuuid_string(void)
+{
+ static const uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0};
+ const uint8_t *src = uuid;
+ const uint8_t *uuid_ptr = uuid_dashes;
+ char *dst;
+
+ SYSUUIDStr[0] = '\0'; /* If nothing there... */
+
+ /* Try loading by UUID */
+ if (have_uuid) {
+ dst = stpcpy(SYSUUIDStr, "SYSUUID=");
+
+ while (*uuid_ptr) {
+ int len = *uuid_ptr;
+
+ lchexbytes(dst, src, len);
+ dst += len * 2;
+ src += len;
+ uuid_ptr++;
+ *dst++ = '-';
+ }
+ /* Remove last dash and zero-terminate */
+ *--dst = '\0';
+ }
+}
/*
* Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask>
@@ -1151,33 +1164,46 @@ char __bss16 IPOption[3+4*16];
static void genipopt(void)
{
char *p = IPOption;
+ const uint32_t *v = &IPInfo.myip;
+ int i;
p = stpcpy(p, "ip=");
- p += gendotquad(p, MyIP);
- *p++ = ':';
-
- p += gendotquad(p, server_ip);
- *p++ = ':';
-
- p += gendotquad(p, gate_way);
- *p++ = ':';
-
- gendotquad(p, net_mask);
+ for (i = 0; i < 4; i++) {
+ p += gendotquad(p, *v++);
+ *p++ = ':';
+ }
+ *--p = '\0';
}
/* Generate ip= option and print the ip adress */
static void ip_init(void)
{
- uint32_t ip = MyIP;
+ uint32_t ip = IPInfo.myip;
genipopt();
gendotquad(dot_quad_buf, ip);
ip = ntohl(ip);
printf("My IP address seems to be %08X %s\n", ip, dot_quad_buf);
- printf("%s\n", IPOption);
+}
+
+/*
+ * Print the IPAPPEND strings, in order
+ */
+extern const uint16_t IPAppends[];
+extern const char numIPAppends[];
+
+static void print_ipappend(void)
+{
+ size_t i;
+
+ for (i = 0; i < (size_t)numIPAppends; i++) {
+ const char *p = (const char *)(size_t)IPAppends[i];
+ if (*p)
+ printf("%s\n", p);
+ }
}
/*
@@ -1412,7 +1438,7 @@ static void udp_init(void)
{
int err;
static __lowmem struct s_PXENV_UDP_OPEN udp_open;
- udp_open.src_ip = MyIP;
+ udp_open.src_ip = IPInfo.myip;
err = pxe_call(PXENV_UDP_OPEN, &udp_open);
if (err || udp_open.status) {
printf("Failed to initialize UDP stack ");
@@ -1473,7 +1499,9 @@ static void network_init(void)
printf("\n");
make_bootif_string();
+ make_sysuuid_string();
ip_init();
+ print_ipappend();
/*
* Check to see if we got any PXELINUX-specific DHCP options; in particular,
@@ -1627,12 +1655,17 @@ void unload_pxe(void)
PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_UNDI_CLEANUP, 0
};
- uint8_t api;
+ unsigned int api;
const uint8_t *api_ptr;
- uint16_t flag = 0;
int err;
size_t int_addr;
- static __lowmem struct s_PXENV_UNLOAD_STACK unload_stack;
+ static __lowmem union {
+ struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
+ struct s_PXENV_UNLOAD_STACK unload_stack;
+ struct s_PXENV_STOP_UNDI stop_undi;
+ struct s_PXENV_UNDI_CLEANUP undi_cleanup;
+ uint16_t Status; /* All calls have this as the first member */
+ } unload_call;
dprintf("FBM before unload = %d\n", BIOS_fbm);
@@ -1644,22 +1677,25 @@ void unload_pxe(void)
if (KeepPXE || err)
return;
- api_ptr = major_ver(APIVer) >= 2 ? new_api_unload : old_api_unload;
+ dprintf("APIVer = %04x\n", APIVer);
+
+ api_ptr = APIVer >= 0x0200 ? new_api_unload : old_api_unload;
while((api = *api_ptr++)) {
- memset(&unload_stack, 0, sizeof unload_stack);
- err = pxe_call(api, &unload_stack);
- if (err || unload_stack.Status != PXENV_STATUS_SUCCESS) {
+ dprintf("PXE call %04x\n", api);
+ memset(&unload_call, 0, sizeof unload_call);
+ err = pxe_call(api, &unload_call);
+ if (err || unload_call.Status != PXENV_STATUS_SUCCESS) {
dprintf("PXE unload API call %04x failed\n", api);
goto cant_free;
}
}
- flag = 0xff00;
- if (real_base_mem <= BIOS_fbm) { /* Santiy check */
+ api = 0xff00;
+ if (real_base_mem <= BIOS_fbm) { /* Sanity check */
dprintf("FBM %d < real_base_mem %d\n", BIOS_fbm, real_base_mem);
goto cant_free;
}
- flag++;
+ api++;
/* Check that PXE actually unhooked the INT 0x1A chain */
int_addr = (size_t)GET_PTR(*(far_ptr_t *)(4 * 0x1a));
@@ -1670,13 +1706,14 @@ void unload_pxe(void)
return;
}
- dprintf("Can't free FBM, real_base_mem = %d, FBM = %d, INT 1A = %08x (%d)\n",
- real_base_mem, BIOS_fbm, *(uint32_t *)(4 * 0x1a), int_addr);
+ dprintf("Can't free FBM, real_base_mem = %d, "
+ "FBM = %d, INT 1A = %08x (%d)\n",
+ real_base_mem, BIOS_fbm,
+ *(uint32_t *)(4 * 0x1a), int_addr);
cant_free:
-
- printf("Failed to free base memory error %04x-%08x\n",
- flag, *(uint32_t *)(4 * 0x1a));
+ printf("Failed to free base memory error %04x-%08x (%d/%dK)\n",
+ api, *(uint32_t *)(4 * 0x1a), BIOS_fbm, real_base_mem);
return;
}
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index e801aea5..1e6fa76a 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -32,7 +32,6 @@
#define PKTBUF_SIZE 2048 /* */
#define is_digit(c) (((c) >= '0') && ((c) <= '9'))
-#define major_ver(v) (((v) >> 8) && 0xff)
static inline bool is_hex(char c)
{
@@ -170,13 +169,20 @@ struct pxe_pvt_inode {
#define PVT(i) ((struct pxe_pvt_inode *)((i)->pvt))
/*
+ * Network boot information
+ */
+struct ip_info {
+ uint32_t ipv4;
+ uint32_t myip;
+ uint32_t serverip;
+ uint32_t gateway;
+ uint32_t netmask;
+};
+
+/*
* Variable externs
*/
-extern uint32_t server_ip;
-extern uint32_t MyIP;
-extern uint32_t net_mask;
-extern uint32_t gate_way;
-extern uint16_t server_port;
+extern struct ip_info IPInfo;
extern uint8_t MAC[];
extern char BOOTIFStr[];
@@ -195,7 +201,6 @@ extern char dot_quad_buf[];
extern uint32_t dns_server[];
-extern uint16_t real_base_mem;
extern uint16_t APIVer;
extern far_ptr_t PXEEntry;
extern uint8_t KeepPXE;
@@ -204,18 +209,29 @@ extern far_ptr_t InitStack;
extern bool have_uuid;
extern uint8_t uuid_type;
-extern char uuid[];
+extern uint8_t uuid[];
extern uint16_t BIOS_fbm;
extern const uint8_t TimeoutTable[];
+/*
+ * Compute the suitable gateway for a specific route -- too many
+ * vendor PXE stacks don't do this correctly...
+ */
+static inline uint32_t gateway(uint32_t ip)
+{
+ if ((ip ^ IPInfo.myip) & IPInfo.netmask)
+ return IPInfo.gateway;
+ else
+ return 0;
+}
/*
* functions
*/
/* pxe.c */
-int ip_ok(uint32_t);
+bool ip_ok(uint32_t);
int pxe_call(int, void *);
/* dhcp_options.c */
diff --git a/core/fs/readdir.c b/core/fs/readdir.c
index d20fc33b..d071affd 100644
--- a/core/fs/readdir.c
+++ b/core/fs/readdir.c
@@ -10,13 +10,20 @@
DIR *opendir(const char *path)
{
int rv;
+ struct file *file;
rv = searchdir(path);
if (rv < 0)
return NULL;
- /* XXX: check for a directory handle here */
- return (DIR *)handle_to_file(rv);
+ file = handle_to_file(rv);
+
+ if (file->inode->mode != DT_DIR) {
+ _close_file(file);
+ return NULL;
+ }
+
+ return (DIR *)file;
}
/*
diff --git a/core/include/fs.h b/core/include/fs.h
index f1d35bbb..da247a98 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -94,6 +94,7 @@ struct extent {
*/
struct inode {
struct fs_info *fs; /* The filesystem this inode is associated with */
+ struct inode *parent; /* Parent directory, if any */
int refcnt;
int mode; /* FILE , DIR or SYMLINK */
uint32_t size;
@@ -157,11 +158,8 @@ static inline struct inode *get_inode(struct inode *inode)
inode->refcnt++;
return inode;
}
-static inline void put_inode(struct inode *inode)
-{
- if (! --inode->refcnt)
- free(inode);
-}
+
+void put_inode(struct inode *inode);
static inline void malloc_error(char *obj)
{
@@ -204,6 +202,9 @@ DIR *opendir(const char *pathname);
struct dirent *readdir(DIR *dir);
int closedir(DIR *dir);
+/* getcwd.c */
+char *getcwd(char *buf, size_t size);
+
/*
* Generic functions that filesystem drivers may choose to use
*/
@@ -212,6 +213,7 @@ int closedir(DIR *dir);
void generic_mangle_name(char *, const char *);
/* loadconfig.c */
+int search_config(const char *search_directores[], const char *filenames[]);
int generic_load_config(void);
/* close.c */
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index 0b87e735..8084ac9a 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -530,7 +530,15 @@ exten_table_end:
KeepPXE db 0 ; Should PXE be kept around?
;
-; IP information (initialized to "unknown" values)
- alignz 4
- global MyIP
-MyIP dd 0 ; My IP address
+; IP information. Note that the field are in the same order as the
+; Linux kernel expects in the ip= option.
+;
+ section .bss16
+ alignb 4
+ global IPInfo
+IPInfo:
+.IPv4 resd 1 ; IPv4 information
+.MyIP resd 1 ; My IP address
+.ServerIP resd 1
+.GatewayIP resd 1
+.Netmask resd 1