[syslinux:elflink] elflink: merge 4.01 fs part

syslinux-bot for Feng Tang feng.tang at intel.com
Thu Aug 12 21:04:02 PDT 2010


Commit-ID:  29f87cf47dd49d5bb715722329c45260a571214c
Gitweb:     http://syslinux.zytor.com/commit/29f87cf47dd49d5bb715722329c45260a571214c
Author:     Feng Tang <feng.tang at intel.com>
AuthorDate: Wed, 14 Jul 2010 14:43:01 +0800
Committer:  Feng Tang <feng.tang at intel.com>
CommitDate: Tue, 20 Jul 2010 11:10:04 +0800

elflink: merge 4.01 fs part

changes including:

modified:   core/cmdline.inc
modified:   core/comboot.inc
modified:   core/fs/btrfs/btrfs.c
modified:   core/fs/chdir.c
modified:   core/fs/diskio.c
modified:   core/fs/fat/fat.c
modified:   core/fs/fs.c
modified:   core/fs/getfssec.c
modified:   core/fs/iso9660/iso9660.c
modified:   core/fs/lib/loadconfig.c
modified:   core/fs/pxe/dhcp_option.c
modified:   core/fs/pxe/dnsresolv.c
modified:   core/fs/pxe/idle.c
modified:   core/fs/pxe/pxe.c
modified:   core/fs/pxe/pxe.h
modified:   core/fs/readdir.c
modified:   core/include/fs.h
modified:   core/pxelinux.asm


---
 core/cmdline.inc           |    4 +-
 core/comboot.inc           |    4 +-
 core/fs/btrfs/btrfs.c      |   68 ++++--------
 core/fs/chdir.c            |   59 +++++++++--
 core/fs/diskio.c           |  156 +++++++++++++++++++---------
 core/fs/fat/fat.c          |   81 ++++++---------
 core/fs/fs.c               |   68 ++++++++-----
 core/fs/getcwd.c           |   13 +++
 core/fs/getfssec.c         |    4 +
 core/fs/iso9660/iso9660.c  |   29 ++----
 core/fs/lib/loadconfig.c   |   30 ++++--
 core/fs/lib/searchconfig.c |   40 +++++++
 core/fs/pxe/dhcp_option.c  |  193 +++++++++++++++++------------------
 core/fs/pxe/dnsresolv.c    |   95 +++++++++---------
 core/fs/pxe/idle.c         |    2 +-
 core/fs/pxe/pxe.c          |  241 +++++++++++++++++++++++++-------------------
 core/fs/pxe/pxe.h          |   34 +++++--
 core/fs/readdir.c          |   11 ++-
 core/include/fs.h          |   12 ++-
 core/pxelinux.asm          |   16 ++-
 20 files changed, 675 insertions(+), 485 deletions(-)

diff --git a/core/cmdline.inc b/core/cmdline.inc
index 7fa5381..3e63f9a 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 45b770f..0c9956a 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 72dcbe9..b6a14e3 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 bfce9bc..9e8dfd2 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 464cca6..d4901c3 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 a21f431..5902f48 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 9b8e30f..48856c9 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 0000000..a7b6c7a
--- /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 3d62d4e..e099b64 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 d695e43..62137d0 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 9318c1c..c9652b6 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 0000000..24bfde3
--- /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 e18b605..50f2de0 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 df7f33c..2b263fa 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 0538b16..52a87c3 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 011ef29..25bd094 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 e801aea..1e6fa76 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 d20fc33..d071aff 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 f1d35bb..da247a9 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 0b87e73..8084ac9 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



More information about the Syslinux-commits mailing list