aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-03-20 17:14:21 +0000
committerMatt Fleming <matt.fleming@intel.com>2013-03-22 13:57:44 +0000
commit37d43cf9dd5dd2d2cef1e86aa651097473fd0b48 (patch)
tree07a7df546f178c4e1576f4cbcc0bb4db3a8e18b4
parentbf20364b582c383b4927f898de213b1cc0981a80 (diff)
parenta107cb3b6fa219cf5f65bef366c9b00b108e9a3a (diff)
downloadsyslinux-37d43cf9dd5dd2d2cef1e86aa651097473fd0b48.tar.gz
syslinux-37d43cf9dd5dd2d2cef1e86aa651097473fd0b48.tar.xz
syslinux-37d43cf9dd5dd2d2cef1e86aa651097473fd0b48.zip
Merge tag 'syslinux-5.10-pre2' into for-hpa/elflink/firmware
syslinux-5.10-pre2 Conflicts: NEWS com32/include/netinet/in.h com32/include/sys/cpu.h com32/lib/Makefile core/Makefile core/fs/diskio.c core/fs/pxe/pxe.h core/init.c core/mem/free.c core/mem/malloc.c mk/devel.mk version
-rw-r--r--Makefile7
-rw-r--r--NEWS14
-rw-r--r--com32/chain/Makefile7
-rw-r--r--com32/chain/chain.c171
-rw-r--r--com32/chain/chain.h19
-rw-r--r--com32/chain/common.h9
-rw-r--r--com32/chain/mangle.c244
-rw-r--r--com32/chain/mangle.h34
-rw-r--r--com32/chain/options.c230
-rw-r--r--com32/chain/options.h54
-rw-r--r--com32/chain/partiter.c619
-rw-r--r--com32/chain/partiter.h85
-rw-r--r--com32/chain/utility.c96
-rw-r--r--com32/chain/utility.h79
-rw-r--r--com32/elflink/ldlinux/chainboot.c3
-rw-r--r--com32/elflink/ldlinux/execute.c41
-rw-r--r--com32/elflink/ldlinux/kernel.c17
-rw-r--r--com32/elflink/ldlinux/ldlinux.c36
-rw-r--r--com32/elflink/ldlinux/readconfig.c67
-rw-r--r--com32/gfxboot/gfxboot.c2
-rw-r--r--com32/include/byteswap.h58
-rw-r--r--com32/include/com32.h2
-rw-r--r--com32/include/errno.h21
-rw-r--r--com32/include/fcntl.h1
-rw-r--r--com32/include/linux/list.h12
-rw-r--r--com32/include/netinet/in.h58
-rw-r--r--com32/include/stddef.h8
-rw-r--r--com32/include/sys/cpu.h41
-rw-r--r--com32/include/sys/i386/cpu.h29
-rw-r--r--com32/include/sys/x86_64/cpu.h28
-rw-r--r--com32/include/syslinux/config.h2
-rw-r--r--com32/include/syslinux/pmapi.h5
-rw-r--r--com32/include/syslinux/pxe_api.h22
-rw-r--r--com32/include/syslinux/sysappend.h59
-rw-r--r--com32/lib/errno.c7
-rw-r--r--com32/lib/sys/file.h2
-rw-r--r--com32/lib/sys/open.c2
-rw-r--r--com32/lib/syslinux/ipappend.c13
-rw-r--r--com32/lib/syslinux/load_linux.c30
-rw-r--r--com32/lib/syslinux/run_command.c2
-rw-r--r--com32/lib/syslinux/runimage.c8
-rw-r--r--com32/lib/syslinux/shuffle.c4
-rw-r--r--com32/menu/menumain.c4
-rw-r--r--com32/menu/readconfig.c35
-rw-r--r--com32/modules/Makefile2
-rw-r--r--com32/modules/cmd.c2
-rw-r--r--com32/modules/cptime.c284
-rw-r--r--com32/modules/poweroff.c88
-rw-r--r--core/Makefile91
-rw-r--r--core/bios.c6
-rw-r--r--core/callback.inc13
-rw-r--r--core/debug.c9
-rw-r--r--core/diskfs.inc30
-rw-r--r--core/dmi.c383
-rw-r--r--core/elflink/load_env32.c51
-rw-r--r--core/errno.c4
-rw-r--r--core/extern.inc20
-rw-r--r--core/fs/chdir.c5
-rw-r--r--core/fs/diskio.c8
-rw-r--r--core/fs/fs.c12
-rw-r--r--core/fs/lib/searchconfig.c3
-rw-r--r--core/fs/pxe/core.c207
-rw-r--r--core/fs/pxe/dhcp_option.c10
-rw-r--r--core/fs/pxe/dnsresolv.c321
-rw-r--r--core/fs/pxe/ftp.c280
-rw-r--r--core/fs/pxe/ftp_readdir.c141
-rw-r--r--core/fs/pxe/gpxeurl.c88
-rw-r--r--core/fs/pxe/http.c400
-rw-r--r--core/fs/pxe/http_readdir.c471
-rw-r--r--core/fs/pxe/idle.c83
-rw-r--r--core/fs/pxe/isr.c278
-rw-r--r--core/fs/pxe/pxe.c1039
-rw-r--r--core/fs/pxe/pxe.h158
-rw-r--r--core/fs/pxe/tcp.c78
-rw-r--r--core/fs/pxe/tftp.c443
-rw-r--r--core/fs/pxe/tftp.h54
-rw-r--r--core/fs/pxe/url.h33
-rw-r--r--core/fs/pxe/urlparse.c223
-rw-r--r--core/fs/readdir.c3
-rw-r--r--core/head.inc1
-rw-r--r--core/idle.c6
-rw-r--r--core/include/core.h46
-rw-r--r--core/include/ctype.h12
-rw-r--r--core/include/fs.h13
-rw-r--r--core/include/kaboom.h11
-rw-r--r--core/include/mbox.h59
-rw-r--r--core/include/net.h33
-rw-r--r--core/include/thread.h115
-rw-r--r--core/include/timer.h21
-rw-r--r--core/isolinux.asm28
-rw-r--r--core/keywords2
-rw-r--r--core/keywords.inc6
-rw-r--r--core/layout.inc1
-rw-r--r--core/legacynet/core.c186
-rw-r--r--core/legacynet/dnsresolv.c353
-rw-r--r--core/legacynet/idle.c112
-rw-r--r--core/legacynet/portnum.c (renamed from core/fs/pxe/portnum.c)2
-rw-r--r--core/lwip/CHANGELOG3050
-rw-r--r--core/lwip/COPYING33
-rw-r--r--core/lwip/FILES4
-rw-r--r--core/lwip/README89
-rw-r--r--core/lwip/UPGRADING144
-rw-r--r--core/lwip/doc/FILES6
-rw-r--r--core/lwip/doc/contrib.txt63
-rw-r--r--core/lwip/doc/rawapi.txt505
-rw-r--r--core/lwip/doc/savannah.txt135
-rw-r--r--core/lwip/doc/snmp_agent.txt181
-rw-r--r--core/lwip/doc/sys_arch.txt216
-rw-r--r--core/lwip/src/FILES13
-rw-r--r--core/lwip/src/api/api_lib.c740
-rw-r--r--core/lwip/src/api/api_msg.c1535
-rw-r--r--core/lwip/src/api/err.c75
-rw-r--r--core/lwip/src/api/netbuf.c245
-rw-r--r--core/lwip/src/api/netdb.c352
-rw-r--r--core/lwip/src/api/netifapi.c160
-rw-r--r--core/lwip/src/api/sockets.c2347
-rw-r--r--core/lwip/src/api/tcpip.c460
-rw-r--r--core/lwip/src/arch/sys_arch.c128
-rw-r--r--core/lwip/src/core/def.c108
-rw-r--r--core/lwip/src/core/dhcp.c1745
-rw-r--r--core/lwip/src/core/dns.c975
-rw-r--r--core/lwip/src/core/init.c306
-rw-r--r--core/lwip/src/core/ipv4/autoip.c536
-rw-r--r--core/lwip/src/core/ipv4/icmp.c335
-rw-r--r--core/lwip/src/core/ipv4/igmp.c817
-rw-r--r--core/lwip/src/core/ipv4/inet.c42
-rw-r--r--core/lwip/src/core/ipv4/inet_chksum.c450
-rw-r--r--core/lwip/src/core/ipv4/ip.c857
-rw-r--r--core/lwip/src/core/ipv4/ip_addr.c312
-rw-r--r--core/lwip/src/core/ipv4/ip_frag.c863
-rw-r--r--core/lwip/src/core/mem.c642
-rw-r--r--core/lwip/src/core/memp.c469
-rw-r--r--core/lwip/src/core/netif.c752
-rw-r--r--core/lwip/src/core/pbuf.c1156
-rw-r--r--core/lwip/src/core/raw.c354
-rw-r--r--core/lwip/src/core/snmp/asn1_dec.c657
-rw-r--r--core/lwip/src/core/snmp/asn1_enc.c611
-rw-r--r--core/lwip/src/core/snmp/mib2.c4146
-rw-r--r--core/lwip/src/core/snmp/mib_structs.c1174
-rw-r--r--core/lwip/src/core/snmp/msg_in.c1437
-rw-r--r--core/lwip/src/core/snmp/msg_out.c681
-rw-r--r--core/lwip/src/core/stats.c176
-rw-r--r--core/lwip/src/core/sys.c66
-rw-r--r--core/lwip/src/core/tcp.c1635
-rw-r--r--core/lwip/src/core/tcp_in.c1567
-rw-r--r--core/lwip/src/core/tcp_out.c1468
-rw-r--r--core/lwip/src/core/timers.c483
-rw-r--r--core/lwip/src/core/udp.c966
-rw-r--r--core/lwip/src/include/arch/cc.h40
-rw-r--r--core/lwip/src/include/arch/perf.h7
-rw-r--r--core/lwip/src/include/arch/sys_arch.h85
-rw-r--r--core/lwip/src/include/ipv4/lwip/autoip.h119
-rw-r--r--core/lwip/src/include/ipv4/lwip/icmp.h111
-rw-r--r--core/lwip/src/include/ipv4/lwip/igmp.h106
-rw-r--r--core/lwip/src/include/ipv4/lwip/inet.h105
-rw-r--r--core/lwip/src/include/ipv4/lwip/inet_chksum.h90
-rw-r--r--core/lwip/src/include/ipv4/lwip/ip.h213
-rw-r--r--core/lwip/src/include/ipv4/lwip/ip_addr.h244
-rw-r--r--core/lwip/src/include/ipv4/lwip/ip_frag.h88
-rw-r--r--core/lwip/src/include/lwip/api.h284
-rw-r--r--core/lwip/src/include/lwip/api_msg.h174
-rw-r--r--core/lwip/src/include/lwip/arch.h238
-rw-r--r--core/lwip/src/include/lwip/debug.h98
-rw-r--r--core/lwip/src/include/lwip/def.h127
-rw-r--r--core/lwip/src/include/lwip/dhcp.h242
-rw-r--r--core/lwip/src/include/lwip/dns.h124
-rw-r--r--core/lwip/src/include/lwip/err.h85
-rw-r--r--core/lwip/src/include/lwip/init.h72
-rw-r--r--core/lwip/src/include/lwip/mem.h122
-rw-r--r--core/lwip/src/include/lwip/memp.h116
-rw-r--r--core/lwip/src/include/lwip/memp_std.h122
-rw-r--r--core/lwip/src/include/lwip/netbuf.h101
-rw-r--r--core/lwip/src/include/lwip/netdb.h124
-rw-r--r--core/lwip/src/include/lwip/netif.h315
-rw-r--r--core/lwip/src/include/lwip/netifapi.h108
-rw-r--r--core/lwip/src/include/lwip/opt.h2043
-rw-r--r--core/lwip/src/include/lwip/pbuf.h154
-rw-r--r--core/lwip/src/include/lwip/raw.h98
-rw-r--r--core/lwip/src/include/lwip/sio.h141
-rw-r--r--core/lwip/src/include/lwip/snmp.h367
-rw-r--r--core/lwip/src/include/lwip/snmp_asn1.h101
-rw-r--r--core/lwip/src/include/lwip/snmp_msg.h315
-rw-r--r--core/lwip/src/include/lwip/snmp_structs.h268
-rw-r--r--core/lwip/src/include/lwip/sockets.h376
-rw-r--r--core/lwip/src/include/lwip/stats.h292
-rw-r--r--core/lwip/src/include/lwip/sys.h331
-rw-r--r--core/lwip/src/include/lwip/tcp.h377
-rw-r--r--core/lwip/src/include/lwip/tcp_impl.h471
-rw-r--r--core/lwip/src/include/lwip/tcpip.h159
-rw-r--r--core/lwip/src/include/lwip/timers.h98
-rw-r--r--core/lwip/src/include/lwip/udp.h171
-rw-r--r--core/lwip/src/include/lwipopts.h73
-rw-r--r--core/lwip/src/include/netif/etharp.h221
-rw-r--r--core/lwip/src/include/netif/ppp_oe.h190
-rw-r--r--core/lwip/src/include/netif/slipif.h51
-rw-r--r--core/lwip/src/netif/FILES29
-rw-r--r--core/lwip/src/netif/etharp.c1318
-rw-r--r--core/lwip/src/netif/ethernetif.c318
-rw-r--r--core/lwip/src/netif/ppp/auth.c1334
-rw-r--r--core/lwip/src/netif/ppp/auth.h111
-rw-r--r--core/lwip/src/netif/ppp/chap.c908
-rw-r--r--core/lwip/src/netif/ppp/chap.h150
-rw-r--r--core/lwip/src/netif/ppp/chpms.c396
-rw-r--r--core/lwip/src/netif/ppp/chpms.h64
-rw-r--r--core/lwip/src/netif/ppp/fsm.c890
-rw-r--r--core/lwip/src/netif/ppp/fsm.h157
-rw-r--r--core/lwip/src/netif/ppp/ipcp.c1411
-rw-r--r--core/lwip/src/netif/ppp/ipcp.h106
-rw-r--r--core/lwip/src/netif/ppp/lcp.c2066
-rw-r--r--core/lwip/src/netif/ppp/lcp.h151
-rw-r--r--core/lwip/src/netif/ppp/magic.c80
-rw-r--r--core/lwip/src/netif/ppp/magic.h63
-rw-r--r--core/lwip/src/netif/ppp/md5.c320
-rw-r--r--core/lwip/src/netif/ppp/md5.h55
-rw-r--r--core/lwip/src/netif/ppp/pap.c628
-rw-r--r--core/lwip/src/netif/ppp/pap.h118
-rw-r--r--core/lwip/src/netif/ppp/ppp.c2020
-rw-r--r--core/lwip/src/netif/ppp/ppp.h483
-rw-r--r--core/lwip/src/netif/ppp/ppp_oe.c1132
-rw-r--r--core/lwip/src/netif/ppp/pppdebug.h73
-rw-r--r--core/lwip/src/netif/ppp/randm.c249
-rw-r--r--core/lwip/src/netif/ppp/randm.h81
-rw-r--r--core/lwip/src/netif/ppp/vj.c652
-rw-r--r--core/lwip/src/netif/ppp/vj.h156
-rw-r--r--core/lwip/src/netif/slipif.c367
-rw-r--r--core/lwip/src/netif/undiif.c1388
-rw-r--r--core/mem/free.c16
-rw-r--r--core/mem/init.c6
-rw-r--r--core/mem/malloc.c17
-rw-r--r--core/mem/malloc.h18
-rw-r--r--core/pm.inc20
-rw-r--r--core/pmapi.c3
-rw-r--r--core/pxe.inc8
-rw-r--r--core/pxeisr.inc172
-rw-r--r--core/pxelinux.asm58
-rw-r--r--core/sysappend.c120
-rw-r--r--core/syslinux.ld15
-rw-r--r--core/thread/exit_thread.c30
-rw-r--r--core/thread/idle_thread.c27
-rw-r--r--core/thread/kill_thread.c42
-rw-r--r--core/thread/mbox.c57
-rw-r--r--core/thread/root_thread.c11
-rw-r--r--core/thread/schedule.c91
-rw-r--r--core/thread/sem_asm.S16
-rw-r--r--core/thread/semaphore.c81
-rw-r--r--core/thread/start_thread.c69
-rw-r--r--core/thread/thread_asm.S37
-rw-r--r--core/thread/timeout.c41
-rw-r--r--core/vkernel.inc35
-rw-r--r--doc/chain.txt41
-rw-r--r--doc/cptime.txt50
-rw-r--r--doc/pxelinux.txt41
-rw-r--r--doc/syslinux.txt111
-rw-r--r--dos/free.c4
-rw-r--r--efi/Makefile10
-rw-r--r--efi/main.c9
-rw-r--r--mbr/gptmbr.S73
-rw-r--r--mk/devel.mk1
-rw-r--r--mk/lib.mk11
-rw-r--r--mk/syslinux.mk11
260 files changed, 70969 insertions, 2496 deletions
diff --git a/Makefile b/Makefile
index e7d89d90..e039e347 100644
--- a/Makefile
+++ b/Makefile
@@ -147,7 +147,8 @@ INSTALLABLE_MODULES = $(MODULES)
BTARGET = version.gen version.h $(OBJDIR)/version.mk
BOBJECTS = $(BTARGET) \
mbr/*.bin \
- core/pxelinux.0 core/isolinux.bin core/isolinux-debug.bin \
+ core/pxelinux.0 core/lpxelinux.0 \
+ core/isolinux.bin core/isolinux-debug.bin \
gpxe/gpxelinux.0 dos/syslinux.com \
win32/syslinux.exe win64/syslinux64.exe \
dosutil/*.com dosutil/*.sys \
@@ -185,7 +186,7 @@ INSTALL_SBIN = extlinux/extlinux
# Things to install in /usr/lib/syslinux
INSTALL_AUX = core/pxelinux.0 gpxe/gpxelinux.0 gpxe/gpxelinuxk.0 \
core/isolinux.bin core/isolinux-debug.bin \
- dos/syslinux.com \
+ dos/syslinux.com core/lpxelinux.0 \
mbr/*.bin $(INSTALLABLE_MODULES)
INSTALL_AUX_OPT = win32/syslinux.exe win64/syslinux64.exe
INSTALL_DIAG = diag/mbr/handoff.bin \
@@ -198,7 +199,7 @@ INSTALLSUBDIRS = com32 utils dosutil
EXTBOOTINSTALL = $(INSTALLABLE_MODULES)
# Things to install in /tftpboot
-NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 \
+NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 core/lpxelinux.0 \
$(INSTALLABLE_MODULES)
endif # ifdef EFI_BUILD
diff --git a/NEWS b/NEWS
index 11e692d7..f486bcbe 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,20 @@ to all derivatives.
Changes in 6.00:
* Add support for booting from EFI.
+Changes in 5.10:
+ * PXELINUX: An entirely new network implementation based on
+ the lwIP embedded TCP/IP stack. As a result, plain PXELINUX
+ can now support HTTP and FTP without gPXE/iPXE. ls/readdir
+ functionality is supported over HTTP with an indexing
+ webserver, or over FTP with most common FTP servers.
+ * Rename the "ipappend" option to "sysappend" ("ipappend" is
+ still accepted as an alias) and make it available for all
+ derivatives. Add additional strings derived from the system
+ DMI/SMBIOS information if available.
+ * "sysappend" strings are also sent as http cookies, with the
+ prefix _Syslinux_ added, on all http transfers. This can be
+ overridden with the SENDCOOKIES configuration file command.
+
Changes in 5.01:
* txt/: A new AsciiDoc documentation set (work-in-progress)
(Gene Cumm).
diff --git a/com32/chain/Makefile b/com32/chain/Makefile
index 1a7ac9e6..4a5af919 100644
--- a/com32/chain/Makefile
+++ b/com32/chain/Makefile
@@ -1,7 +1,9 @@
## -----------------------------------------------------------------------
##
-## Copyright 2001-2010 H. Peter Anvin - All Rights Reserved
-## Copyright 2010 Michal Soltys
+## Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+## Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+## Copyright 2010 Shao Miller
+## Copyright 2010-2012 Michal Soltys
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
@@ -15,6 +17,7 @@ VPATH = $(SRC)
include $(MAKEDIR)/elf.mk
OBJS = chain.o partiter.o utility.o options.o mangle.o
+CFLAGS += -fno-strict-aliasing
all: chain.c32
diff --git a/com32/chain/chain.c b/com32/chain/chain.c
index 30153c4d..ae95d45c 100644
--- a/com32/chain/chain.c
+++ b/com32/chain/chain.c
@@ -3,7 +3,7 @@
* Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
* Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
* Copyright 2010 Shao Miller
- * Copyright 2010 Michal Soltys
+ * Copyright 2010-2012 Michal Soltys
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,7 +34,6 @@
#include <syslinux/config.h>
#include <syslinux/disk.h>
#include <syslinux/video.h>
-#include "common.h"
#include "chain.h"
#include "utility.h"
#include "options.h"
@@ -72,14 +71,14 @@ static int find_by_sig(uint32_t mbr_sig,
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
if (disk_get_params(drive, &diskinfo))
continue; /* Drive doesn't exist */
- if (!(boot_part = pi_begin(&diskinfo, 0)))
+ if (!(boot_part = pi_begin(&diskinfo, opt.piflags)))
continue;
/* Check for a MBR disk */
if (boot_part->type != typedos) {
pi_del(&boot_part);
continue;
}
- if (boot_part->sub.dos.disk_sig == mbr_sig) {
+ if (boot_part->dos.disk_sig == mbr_sig) {
goto ok;
}
}
@@ -103,22 +102,18 @@ static int find_by_guid(const struct guid *gpt_guid,
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
if (disk_get_params(drive, &diskinfo))
continue; /* Drive doesn't exist */
- if (!(boot_part = pi_begin(&diskinfo, 0)))
+ if (!(boot_part = pi_begin(&diskinfo, opt.piflags)))
continue;
/* Check for a GPT disk */
if (boot_part->type != typegpt) {
pi_del(&boot_part);
continue;
}
- /* Check for a matching GPT disk guid */
- if (!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) {
- goto ok;
- }
- /* disk guid doesn't match, maybe partition guid will */
- while (!pi_next(&boot_part)) {
- if (!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid)))
+ /* Check for a matching GPT disk/partition guid */
+ do {
+ if (!memcmp(&boot_part->gpt.part_guid, gpt_guid, sizeof *gpt_guid))
goto ok;
- }
+ } while (!pi_next(boot_part));
}
drive = -1;
ok:
@@ -139,7 +134,7 @@ static int find_by_label(const char *label, struct part_iter **_boot_part)
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
if (disk_get_params(drive, &diskinfo))
continue; /* Drive doesn't exist */
- if (!(boot_part = pi_begin(&diskinfo, 0)))
+ if (!(boot_part = pi_begin(&diskinfo, opt.piflags)))
continue;
/* Check for a GPT disk */
if (!(boot_part->type == typegpt)) {
@@ -147,8 +142,8 @@ static int find_by_label(const char *label, struct part_iter **_boot_part)
continue;
}
/* Check for a matching partition */
- while (!pi_next(&boot_part)) {
- if (!strcmp(label, boot_part->sub.gpt.part_label))
+ while (!pi_next(boot_part)) {
+ if (!strcmp(label, boot_part->gpt.part_label))
goto ok;
}
}
@@ -160,8 +155,6 @@ ok:
static void do_boot(struct data_area *data, int ndata)
{
- uint16_t *const bios_fbm = (uint16_t *) 0x413;
- addr_t dosmem = (addr_t)(*bios_fbm << 10); /* Technically a low bound */
struct syslinux_memmap *mmap;
struct syslinux_movelist *mlist = NULL;
addr_t endimage;
@@ -172,7 +165,7 @@ static void do_boot(struct data_area *data, int ndata)
mmap = syslinux_memory_map();
if (!mmap) {
- error("Cannot read system memory map\n");
+ error("Cannot read system memory map.");
return;
}
@@ -181,7 +174,7 @@ static void do_boot(struct data_area *data, int ndata)
if (data[i].base + data[i].size > endimage)
endimage = data[i].base + data[i].size;
}
- if (endimage > dosmem)
+ if (endimage > dosmax)
goto too_big;
for (i = 0; i < ndata; i++) {
@@ -227,7 +220,7 @@ static void do_boot(struct data_area *data, int ndata)
static uint8_t swapstub[1024];
uint8_t *p;
- /* Note: we can't rely on either INT 13h nor the dosmem
+ /* Note: we can't rely on either INT 13h nor the dosmax
vector to be correct at this stage, so we have to use an
installer stub to put things in the right place.
Round the installer location to a 1K boundary so the only
@@ -247,14 +240,14 @@ static void do_boot(struct data_area *data, int ndata)
/* Mapping table; start out with identity mapping everything */
for (i = 0; i < 256; i++)
- p[i] = (uint8_t)i;
+ p[i] = i;
/* And the actual swap */
p[driveno] = swapdrive;
p[swapdrive] = driveno;
/* Adjust registers */
- opt.regs.ds = opt.regs.cs = (uint16_t)(endimage >> 4);
+ opt.regs.ds = opt.regs.cs = endimage >> 4;
opt.regs.esi.l = opt.regs.es = 0;
opt.regs.ecx.l = sizeof swapstub >> 2;
opt.regs.ip = 0x10; /* Installer offset */
@@ -273,17 +266,17 @@ static void do_boot(struct data_area *data, int ndata)
/* Force text mode */
syslinux_force_text_mode();
- fputs("Booting...\n", stdout);
+ puts("Booting...");
syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs);
- error("Chainboot failed!\n");
+ error("Chainboot failed !");
return;
too_big:
- error("Loader file too large\n");
+ error("Loader file too large.");
return;
enomem:
- error("Out of memory\n");
+ error("Out of memory.");
return;
}
@@ -300,23 +293,23 @@ int find_dp(struct part_iter **_iter)
if (!strncmp(opt.drivename, "mbr", 3)) {
if (find_by_sig(strtoul(opt.drivename + 4, NULL, 0), &iter) < 0) {
- error("Unable to find requested MBR signature.\n");
+ error("Unable to find requested MBR signature.");
goto bail;
}
} else if (!strncmp(opt.drivename, "guid", 4)) {
if (str_to_guid(opt.drivename + 5, &gpt_guid))
goto bail;
if (find_by_guid(&gpt_guid, &iter) < 0) {
- error("Unable to find requested GPT disk or partition by guid.\n");
+ error("Unable to find requested GPT disk or partition by guid.");
goto bail;
}
} else if (!strncmp(opt.drivename, "label", 5)) {
if (!opt.drivename[6]) {
- error("No label specified.\n");
+ error("No label specified.");
goto bail;
}
if (find_by_label(opt.drivename + 6, &iter) < 0) {
- error("Unable to find requested GPT partition by label.\n");
+ error("Unable to find requested GPT partition by label.");
goto bail;
}
} else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') &&
@@ -328,13 +321,13 @@ int find_dp(struct part_iter **_iter)
if (disk_get_params(drive, &diskinfo))
goto bail;
/* this will start iteration over FDD, possibly raw */
- if (!(iter = pi_begin(&diskinfo, 0)))
+ if (!(iter = pi_begin(&diskinfo, opt.piflags)))
goto bail;
} else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) {
if (!is_phys(sdi->c.filesystem)) {
error("When syslinux is not booted from physical disk (or its emulation),\n"
- "'boot' and 'fs' are meaningless.\n");
+ "'boot' and 'fs' are meaningless.");
goto bail;
}
/* offsets match, but in case it changes in the future */
@@ -348,23 +341,23 @@ int find_dp(struct part_iter **_iter)
if (disk_get_params(drive, &diskinfo))
goto bail;
/* this will start iteration over disk emulation, possibly raw */
- if (!(iter = pi_begin(&diskinfo, 0)))
+ if (!(iter = pi_begin(&diskinfo, opt.piflags)))
goto bail;
/* 'fs' => we should lookup the syslinux partition number and use it */
if (!strcmp(opt.drivename, "fs")) {
- while (!pi_next(&iter)) {
- if (iter->start_lba == fs_lba)
+ do {
+ if (iter->abs_lba == fs_lba)
break;
- }
+ } while (!pi_next(iter));
/* broken part structure or other problems */
if (iter->status) {
- error("Can't find myself on the drive I booted from.\n");
+ error("Can't find myself on the drive I booted from.");
goto bail;
}
}
} else {
- error("Unparsable drive specification.\n");
+ error("Unparsable drive specification.");
goto bail;
}
/* main options done - only thing left is explicit partition specification,
@@ -377,15 +370,15 @@ int find_dp(struct part_iter **_iter)
do {
if (iter->index == partition)
break;
- } while (!pi_next(&iter));
+ } while (!pi_next(iter));
if (iter->status) {
- error("Requested disk / partition combination not found.\n");
+ error("Requested disk / partition combination not found.");
goto bail;
}
}
if (!(iter->di.disk & 0x80) && iter->index) {
- error("WARNING: Partitions on floppy devices may not work.\n");
+ warn("Partitions on floppy devices may not work.");
}
*_iter = iter;
@@ -401,51 +394,53 @@ static int setup_handover(const struct part_iter *iter,
struct data_area *data)
{
struct disk_dos_part_entry *ha;
- uint32_t synth_size;
- uint32_t *plen;
+ uint32_t synth_size = sizeof *ha;
- if (!iter->index) { /* implies typeraw or non-iterated */
+ /*
+ * we have to cover both non-iterated but otherwise properly detected
+ * gpt/dos schemes as well as raw disks; checking index for 0 covers both
+ */
+ if (iter->index == 0) {
uint32_t len;
/* RAW handover protocol */
- synth_size = sizeof(struct disk_dos_part_entry);
ha = malloc(synth_size);
if (!ha) {
- error("Could not build RAW hand-over record!\n");
+ critm();
goto bail;
}
len = ~0u;
if (iter->length < len)
- len = (uint32_t)iter->length;
- lba2chs(&ha->start, &iter->di, 0, l2c_cadd);
- lba2chs(&ha->end, &iter->di, len - 1, l2c_cadd);
+ len = iter->length;
+ lba2chs(&ha->start, &iter->di, 0, L2C_CADD);
+ lba2chs(&ha->end, &iter->di, len - 1, L2C_CADD);
ha->active_flag = 0x80;
ha->ostype = 0xDA; /* "Non-FS Data", anything is good here though ... */
ha->start_lba = 0;
ha->length = len;
} else if (iter->type == typegpt) {
+ uint32_t *plen;
/* GPT handover protocol */
- synth_size = sizeof(struct disk_dos_part_entry) +
- sizeof(uint32_t) + (uint32_t)iter->sub.gpt.pe_size;
+ synth_size += sizeof *plen + iter->gpt.pe_size;
ha = malloc(synth_size);
if (!ha) {
- error("Could not build GPT hand-over record!\n");
+ critm();
goto bail;
}
- lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
- lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
+ lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD);
+ lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD);
ha->active_flag = 0x80;
ha->ostype = 0xED;
/* All bits set by default */
ha->start_lba = ~0u;
ha->length = ~0u;
/* If these fit the precision, pass them on */
- if (iter->start_lba < ha->start_lba)
- ha->start_lba = (uint32_t)iter->start_lba;
+ if (iter->abs_lba < ha->start_lba)
+ ha->start_lba = iter->abs_lba;
if (iter->length < ha->length)
- ha->length = (uint32_t)iter->length;
+ ha->length = iter->length;
/* Next comes the GPT partition record length */
- plen = (uint32_t *) (ha + 1);
- plen[0] = (uint32_t)iter->sub.gpt.pe_size;
+ plen = (uint32_t *)(ha + 1);
+ plen[0] = iter->gpt.pe_size;
/* Next comes the GPT partition record copy */
memcpy(plen + 1, iter->record, plen[0]);
#ifdef DEBUG
@@ -453,20 +448,20 @@ static int setup_handover(const struct part_iter *iter,
disk_dos_part_dump(ha);
disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1));
#endif
+ /* the only possible case left is dos scheme */
} else if (iter->type == typedos) {
/* MBR handover protocol */
- synth_size = sizeof(struct disk_dos_part_entry);
ha = malloc(synth_size);
if (!ha) {
- error("Could not build MBR hand-over record!\n");
+ critm();
goto bail;
}
memcpy(ha, iter->record, synth_size);
/* make sure these match bios imaginations and are ebr agnostic */
- lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
- lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
- ha->start_lba = (uint32_t)iter->start_lba;
- ha->length = (uint32_t)iter->length;
+ lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD);
+ lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD);
+ ha->start_lba = iter->abs_lba;
+ ha->length = iter->length;
#ifdef DEBUG
dprintf("MBR handover:\n");
@@ -495,9 +490,9 @@ int main(int argc, char *argv[])
console_ansi_raw();
- memset(&fdat, 0, sizeof(fdat));
- memset(&hdat, 0, sizeof(hdat));
- memset(&sdat, 0, sizeof(sdat));
+ memset(&fdat, 0, sizeof fdat);
+ memset(&hdat, 0, sizeof hdat);
+ memset(&sdat, 0, sizeof sdat);
opt_set_defs();
if (opt_parse_args(argc, argv))
@@ -530,11 +525,11 @@ int main(int argc, char *argv[])
fdat.base = (opt.fseg << 4) + opt.foff;
if (loadfile(opt.file, &fdat.data, &fdat.size)) {
- error("Couldn't read the boot file.\n");
+ error("Couldn't read the boot file.");
goto bail;
}
- if (fdat.base + fdat.size - 1 > ADDRMAX) {
- error("The boot file is too big to load at this address.\n");
+ if (fdat.base + fdat.size > dosmax) {
+ error("The boot file is too big to load at this address.");
goto bail;
}
}
@@ -544,23 +539,23 @@ int main(int argc, char *argv[])
sdat.base = (opt.sseg << 4) + opt.soff;
sdat.size = iter->di.bps;
- if (sdat.base + sdat.size - 1 > ADDRMAX) {
- error("The sector cannot be loaded at such high address.\n");
+ if (sdat.base + sdat.size > dosmax) {
+ error("The sector cannot be loaded at such high address.");
goto bail;
}
- if (!(sdat.data = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
- error("Couldn't read the sector.\n");
+ if (!(sdat.data = disk_read_sectors(&iter->di, iter->abs_lba, 1))) {
+ error("Couldn't read the sector.");
goto bail;
}
if (opt.save) {
if (!(sbck = malloc(sdat.size))) {
- error("Couldn't allocate cmp-buf for option 'save'.\n");
+ critm();
goto bail;
}
memcpy(sbck, sdat.data, sdat.size);
}
if (opt.file && opt.maps && overlap(&fdat, &sdat)) {
- error("WARNING: The sector won't be mmapped, as it would conflict with the boot file.\n");
+ warn("The sector won't be mmapped, as it would conflict with the boot file.");
opt.maps = false;
}
}
@@ -572,8 +567,8 @@ int main(int argc, char *argv[])
/* Verify possible conflicts */
if ( ( opt.file && overlap(&fdat, &hdat)) ||
( opt.maps && overlap(&sdat, &hdat)) ) {
- error("WARNING: Handover area won't be prepared,\n"
- "as it would conflict with the boot file and/or the sector.\n");
+ warn("Handover area won't be prepared,\n"
+ "as it would conflict with the boot file and/or the sector.");
opt.hand = false;
}
}
@@ -617,22 +612,22 @@ int main(int argc, char *argv[])
*/
if (opt.file)
- memcpy(data + ndata++, &fdat, sizeof(fdat));
+ memcpy(data + ndata++, &fdat, sizeof fdat);
if (opt.maps)
- memcpy(data + ndata++, &sdat, sizeof(sdat));
+ memcpy(data + ndata++, &sdat, sizeof sdat);
if (opt.hand)
- memcpy(data + ndata++, &hdat, sizeof(hdat));
+ memcpy(data + ndata++, &hdat, sizeof hdat);
#ifdef DEBUG
- printf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n"
+ dprintf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n"
"iter->di C, H, S: %u, %u, %u\n",
iter->di.disk, iter->di.bps,
iter->di.lbacnt, iter->di.cyl * iter->di.head * iter->di.spt,
iter->di.cyl, iter->di.head, iter->di.spt);
- printf("iter idx: %d\n", iter->index);
- printf("iter lba: %"PRIu64"\n", iter->start_lba);
+ dprintf("iter idx: %d\n", iter->index);
+ dprintf("iter lba: %"PRIu64"\n", iter->abs_lba);
if (opt.hand)
- printf("hand lba: %u\n",
+ dprintf("hand lba: %u\n",
((struct disk_dos_part_entry *)hdat.data)->start_lba);
#endif
@@ -644,7 +639,7 @@ int main(int argc, char *argv[])
if (ndata && !opt.brkchain) /* boot only if we actually chainload */
do_boot(data, ndata);
else
- error("Service-only run completed, exiting.\n");
+ puts("Service-only run completed, exiting.");
bail:
pi_del(&iter);
/* Free allocated areas */
diff --git a/com32/chain/chain.h b/com32/chain/chain.h
index fc481bc6..fb5914b1 100644
--- a/com32/chain/chain.h
+++ b/com32/chain/chain.h
@@ -1,5 +1,20 @@
-#ifndef _COM32_CHAIN_CHAIN_H
-#define _COM32_CHAIN_CHAIN_H
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010-2012 Michal Soltys
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_CHAIN_H
+#define COM32_CHAIN_CHAIN_H
#include <syslinux/movebits.h>
diff --git a/com32/chain/common.h b/com32/chain/common.h
deleted file mode 100644
index b170a732..00000000
--- a/com32/chain/common.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _COM32_CHAIN_COMMON_H
-#define _COM32_CHAIN_COMMON_H
-
-#define ADDRMAX 0x9EFFFu
-#define ADDRMIN 0x500u
-
-#endif
-
-/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
index 8358106e..ffdaab8d 100644
--- a/com32/chain/mangle.c
+++ b/com32/chain/mangle.c
@@ -1,3 +1,33 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010-2012 Michal Soltys
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
#include <com32.h>
#include <stdlib.h>
#include <stdio.h>
@@ -5,7 +35,6 @@
#include <stdint.h>
#include <dprintf.h>
#include <syslinux/config.h>
-#include "common.h"
#include "chain.h"
#include "options.h"
#include "utility.h"
@@ -32,7 +61,7 @@ int manglef_isolinux(struct data_area *data)
sdi = syslinux_derivative_info();
if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) {
- error ("The isolinux= option is only valid when run from ISOLINUX.\n");
+ error("The isolinux= option is only valid when run from ISOLINUX.");
goto bail;
}
@@ -58,7 +87,7 @@ int manglef_isolinux(struct data_area *data)
file_lba = get_file_lba(opt.file);
if (file_lba == 0) {
- error("Failed to find LBA offset of the boot file\n");
+ error("Failed to find LBA offset of the boot file.");
goto bail;
}
/* Set it */
@@ -132,8 +161,8 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
if (!(opt.file && opt.grub))
return 0;
- if (data->size < sizeof(struct grub_stage2_patch_area)) {
- error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.\n");
+ if (data->size < sizeof *stage2) {
+ error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.");
goto bail;
}
stage2 = data->data;
@@ -144,7 +173,7 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
*/
if (stage2->compat_version_major != 3
|| stage2->compat_version_minor != 2) {
- error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.\n");
+ error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.");
goto bail;
}
@@ -174,7 +203,7 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
* 0-3: primary partitions
* 4-*: logical partitions
*/
- stage2->install_partition.part1 = (uint8_t)(iter->index - 1);
+ stage2->install_partition.part1 = iter->index - 1;
/*
* Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
@@ -182,8 +211,8 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
* the default config filename "/boot/grub/menu.lst".
*/
if (opt.grubcfg) {
- if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) {
- error ("The config filename length can't exceed 88 characters.\n");
+ if (strlen(opt.grubcfg) >= sizeof stage2->config_file) {
+ error("The config filename length can't exceed 88 characters.");
goto bail;
}
@@ -224,19 +253,19 @@ int manglef_drmk(struct data_area *data)
dprintf(" fs_lba offset is %d\n", fs_lba);
/* DRMK only uses a DWORD */
if (fs_lba > 0xffffffff) {
- error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n");
+ error("LBA very large; Only using lower 32 bits; DRMK will probably fail.");
}
opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */
if (!realloc(data->data, tsize)) {
- error("Failed to realloc for DRMK.\n");
+ error("Failed to realloc for DRMK.");
goto bail;
}
data->size = tsize;
/* ds:bp is assumed by DRMK to be the boot sector */
/* offset 28 is the FAT HiddenSectors value */
- opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2));
+ opt.regs.ds = (tsize >> 4) + (opt.fseg - 2);
/* "Patch" into tail of the new space */
- *(uint32_t *)((char*)data->data + tsize - 4) = (uint32_t)fs_lba;
+ *(uint32_t *)((char*)data->data + tsize - 4) = fs_lba;
return 0;
bail:
@@ -246,29 +275,32 @@ bail:
/* Adjust BPB common function */
static int mangle_bpb(const struct part_iter *iter, struct data_area *data, const char *tag)
{
- unsigned int off;
int type = bpb_detect(data->data, tag);
+ int off = drvoff_detect(type);
+ /* BPB: hidden sectors 64bit - exFAT only for now */
+ if (type == bpbEXF)
+ *(uint64_t *) ((char *)data->data + 0x40) = iter->abs_lba;
/* BPB: hidden sectors 32bit*/
- if (type >= bpbV34) {
- if (iter->start_lba < ~0u)
- *(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba;
+ else if (bpbV34 <= type && type <= bpbV70) {
+ if (iter->abs_lba < ~0u)
+ *(uint32_t *) ((char *)data->data + 0x1c) = iter->abs_lba;
else
/* won't really help much, but ... */
*(uint32_t *) ((char *)data->data + 0x1c) = ~0u;
- }
/* BPB: hidden sectors 16bit*/
- if (bpbV30 <= type && type <= bpbV32) {
- if (iter->start_lba < 0xFFFF)
- *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)iter->start_lba;
+ } else if (bpbV30 <= type && type <= bpbV32) {
+ if (iter->abs_lba < 0xFFFF)
+ *(uint16_t *) ((char *)data->data + 0x1c) = iter->abs_lba;
else
/* won't really help much, but ... */
*(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u;
}
+
/* BPB: legacy geometry */
- if (type >= bpbV30) {
+ if (bpbV30 <= type && type <= bpbV70) {
if (iter->di.cbios)
- *(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.spt);
+ *(uint32_t *)((char *)data->data + 0x18) = (iter->di.head << 16) | iter->di.spt;
else {
if (iter->di.disk & 0x80)
*(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F;
@@ -277,9 +309,8 @@ static int mangle_bpb(const struct part_iter *iter, struct data_area *data, cons
}
}
/* BPB: drive */
- if (drvoff_detect(type, &off)) {
- *(uint8_t *)((char *)data->data + off) = (uint8_t)
- (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
+ if (off >= 0) {
+ *(uint8_t *)((char *)data->data + off) = (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
}
return 0;
@@ -314,7 +345,7 @@ int mangles_bpb(const struct part_iter *iter, struct data_area *data)
int manglesf_bss(struct data_area *sec, struct data_area *fil)
{
int type1, type2;
- unsigned int cnt = 0;
+ size_t cnt = 0;
if (!(opt.sect && opt.file && opt.bss))
return 0;
@@ -323,12 +354,12 @@ int manglesf_bss(struct data_area *sec, struct data_area *fil)
type2 = bpb_detect(sec->data, "bss/sect");
if (!type1 || !type2) {
- error("Couldn't determine the BPB type for option 'bss'.\n");
+ error("Couldn't determine the BPB type for option 'bss'.");
goto bail;
}
if (type1 != type2) {
error("Option 'bss' can't be used,\n"
- "when a sector and a file have incompatible BPBs.\n");
+ "when a sector and a file have incompatible BPBs.");
goto bail;
}
@@ -348,6 +379,8 @@ int manglesf_bss(struct data_area *sec, struct data_area *fil)
cnt = 0x3C;
} else if (type1 <= bpbV70) {
cnt = 0x42;
+ } else if (type1 <= bpbEXF) {
+ cnt = 0x60;
}
memcpy((char *)fil->data + 0x18, (char *)sec->data + 0x18, cnt);
@@ -365,8 +398,8 @@ int mangles_save(const struct part_iter *iter, const struct data_area *data, voi
return 0;
if (memcmp(org, data->data, data->size)) {
- if (disk_write_sectors(&iter->di, iter->start_lba, data->data, 1)) {
- error("Cannot write the updated sector.\n");
+ if (disk_write_sectors(&iter->di, iter->abs_lba, data->data, 1)) {
+ error("Cannot write the updated sector.");
goto bail;
}
/* function can be called again */
@@ -388,7 +421,7 @@ int mangles_cmldr(struct data_area *data)
if (!(opt.sect && opt.cmldr))
return 0;
- memcpy((char *)data->data + 3, cmldr_signature, sizeof(cmldr_signature));
+ memcpy((char *)data->data + 3, cmldr_signature, sizeof cmldr_signature);
return 0;
}
@@ -397,18 +430,18 @@ int mangler_init(const struct part_iter *iter)
{
/* Set initial registry values */
if (opt.file) {
- opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.fseg;
- opt.regs.ip = (uint16_t)opt.fip;
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.fseg;
+ opt.regs.ip = opt.fip;
} else {
- opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg;
- opt.regs.ip = (uint16_t)opt.sip;
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.sseg;
+ opt.regs.ip = opt.sip;
}
if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
opt.regs.esp.l = 0x7C00;
/* DOS kernels want the drive number in BL instead of DL. Indulge them. */
- opt.regs.ebx.b[0] = opt.regs.edx.b[0] = (uint8_t)iter->di.disk;
+ opt.regs.ebx.b[0] = opt.regs.edx.b[0] = iter->di.disk;
return 0;
}
@@ -418,7 +451,7 @@ int mangler_handover(const struct part_iter *iter, const struct data_area *data)
{
if (opt.file && opt.maps && !opt.hptr) {
opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
- opt.regs.ds = (uint16_t)opt.sseg;
+ opt.regs.ds = opt.sseg;
opt.regs.eax.l = 0;
} else if (opt.hand) {
/* base is really 0x7be */
@@ -442,7 +475,7 @@ int mangler_handover(const struct part_iter *iter, const struct data_area *data)
int mangler_grldr(const struct part_iter *iter)
{
if (opt.grldr)
- opt.regs.edx.b[1] = (uint8_t)(iter->index - 1);
+ opt.regs.edx.b[1] = iter->index - 1;
return 0;
}
@@ -450,15 +483,15 @@ int mangler_grldr(const struct part_iter *iter)
/*
* try to copy values from temporary iterator, if positions match
*/
-static void push_embr(struct part_iter *diter, struct part_iter *siter)
+static void mbrcpy(struct part_iter *diter, struct part_iter *siter)
{
- if (diter->sub.dos.cebr_lba == siter->sub.dos.cebr_lba &&
+ if (diter->dos.cebr_lba == siter->dos.cebr_lba &&
diter->di.disk == siter->di.disk) {
memcpy(diter->data, siter->data, sizeof(struct disk_dos_mbr));
}
}
-static int mpe_sethide(struct part_iter *iter, struct part_iter *miter)
+static int fliphide(struct part_iter *iter, struct part_iter *miter)
{
struct disk_dos_part_entry *dp;
static const uint16_t mask =
@@ -471,8 +504,8 @@ static int mpe_sethide(struct part_iter *iter, struct part_iter *miter)
if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
/* It's a hideable partition type */
- if (miter->index == iter->index || opt.hide & 4)
- t &= (uint8_t)(~0x10u); /* unhide */
+ if (miter->index == iter->index || opt.hide & HIDE_REV)
+ t &= ~0x10u; /* unhide */
else
t |= 0x10u; /* hide */
}
@@ -494,69 +527,98 @@ int manglepe_hide(struct part_iter *miter)
{
int wb = 0, werr = 0;
struct part_iter *iter = NULL;
- struct disk_dos_part_entry *dp;
int ridx;
- if (!opt.hide)
+ if (!(opt.hide & HIDE_ON))
return 0;
if (miter->type != typedos) {
- error("Options '*hide*' is meaningful only for legacy partition scheme.\n");
+ error("Option '[un]hide[all]' works only for legacy (DOS) partition scheme.");
return -1;
}
- if (miter->index < 1)
- error("WARNING: It's impossible to unhide a disk.\n");
-
- if (miter->index > 4 && !(opt.hide & 2))
- error("WARNING: your partition is beyond mbr, so it can't be unhidden without '*hideall'.\n");
+ if (miter->index > 4 && !(opt.hide & HIDE_EXT))
+ warn("Specified partition is logical, so it can't be unhidden without 'unhideall'.");
- if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */
+ if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags)))
return -1;
- while (!pi_next(&iter) && !werr) {
- ridx = iter->rawindex;
- if (!(opt.hide & 2) && ridx > 4)
+ while (!pi_next(iter) && !werr) {
+ ridx = iter->index0;
+ if (!(opt.hide & HIDE_EXT) && ridx > 3)
break; /* skip when we're constrained to pri only */
- dp = (struct disk_dos_part_entry *)iter->record;
- if (dp->ostype)
- wb |= mpe_sethide(iter, miter);
+ if (iter->index != -1)
+ wb |= fliphide(iter, miter);
- if (ridx >= 4 && wb && !werr) {
- push_embr(miter, iter);
- werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ /*
+ * we have to update mbr and each extended partition, but only if
+ * changes (wb) were detected and there was no prior write error (werr)
+ */
+ if (ridx >= 3 && wb && !werr) {
+ mbrcpy(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
wb = 0;
}
}
- if (iter->status > PI_DONE)
+ if (pi_errored(iter))
goto bail;
- /* last write */
+ /* last update */
if (wb && !werr) {
- push_embr(miter, iter);
- werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ mbrcpy(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
}
if (werr)
- error("WARNING: failed to write E/MBR during '*hide*'\n");
+ warn("Failed to write E/MBR during '[un]hide[all]'.");
bail:
pi_del(&iter);
return 0;
}
-static int mpe_setchs(const struct disk_info *di,
- struct disk_dos_part_entry *dp,
- uint32_t lba1)
+static int updchs(struct part_iter *iter, int ext)
{
- uint32_t ochs1, ochs2;
+ struct disk_dos_part_entry *dp;
+ uint32_t ochs1, ochs2, lba;
+ dp = (struct disk_dos_part_entry *)iter->record;
+ if (!ext) {
+ /* primary or logical */
+ lba = (uint32_t)iter->abs_lba;
+ } else {
+ /* extended */
+ dp += 1;
+ lba = iter->dos.nebr_lba;
+ }
ochs1 = *(uint32_t *)dp->start;
ochs2 = *(uint32_t *)dp->end;
- lba2chs(&dp->start, di, lba1, l2c_cadd);
- lba2chs(&dp->end, di, lba1 + dp->length - 1, l2c_cadd);
+ /*
+ * We have to be a bit more careful here in case of 0 start and/or length;
+ * start = 0 would be converted to the beginning of the disk (C/H/S =
+ * 0/0/1) or the [B]EBR, length = 0 would actually set the end CHS to be
+ * lower than the start CHS.
+ *
+ * Both are harmless in case of a hole (and in non-hole case will make
+ * partiter complain about corrupt layout unless PIF_RELAX is set), but it
+ * makes everything look silly and not really correct.
+ *
+ * Thus the approach as seen below.
+ */
+
+ if (dp->start_lba || iter->index != -1) {
+ lba2chs(&dp->start, &iter->di, lba, L2C_CADD);
+ } else {
+ memset(&dp->start, 0, sizeof dp->start);
+ }
+
+ if ((dp->start_lba || iter->index != -1) && dp->length) {
+ lba2chs(&dp->end, &iter->di, lba + dp->length - 1, L2C_CADD);
+ } else {
+ memset(&dp->end, 0, sizeof dp->end);
+ }
return
*(uint32_t *)dp->start != ochs1 ||
@@ -570,45 +632,47 @@ int manglepe_fixchs(struct part_iter *miter)
{
int wb = 0, werr = 0;
struct part_iter *iter = NULL;
- struct disk_dos_part_entry *dp;
int ridx;
if (!opt.fixchs)
return 0;
if (miter->type != typedos) {
- error("Options 'fixchs' is meaningful only for legacy partition scheme.\n");
+ error("Option 'fixchs' works only for legacy (DOS) partition scheme.");
return -1;
}
- if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */
+ if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags)))
return -1;
- while (!pi_next(&iter) && !werr) {
- ridx = iter->rawindex;
- dp = (struct disk_dos_part_entry *)iter->record;
+ while (!pi_next(iter) && !werr) {
+ ridx = iter->index0;
- wb |= mpe_setchs(&iter->di, dp, (uint32_t)iter->start_lba);
- if (ridx > 4)
- wb |= mpe_setchs(&iter->di, dp + 1, iter->sub.dos.nebr_lba);
+ wb |= updchs(iter, 0);
+ if (ridx > 3)
+ wb |= updchs(iter, 1);
- if (ridx >= 4 && wb && !werr) {
- push_embr(miter, iter);
- werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ /*
+ * we have to update mbr and each extended partition, but only if
+ * changes (wb) were detected and there was no prior write error (werr)
+ */
+ if (ridx >= 3 && wb && !werr) {
+ mbrcpy(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
wb = 0;
}
}
- if (iter->status > PI_DONE)
+ if (pi_errored(iter))
goto bail;
- /* last write */
+ /* last update */
if (wb && !werr) {
- push_embr(miter, iter);
- werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ mbrcpy(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
}
if (werr)
- error("WARNING: failed to write E/MBR during 'fixchs'\n");
+ warn("Failed to write E/MBR during 'fixchs'.");
bail:
pi_del(&iter);
diff --git a/com32/chain/mangle.h b/com32/chain/mangle.h
index bcefea3b..d4a5b759 100644
--- a/com32/chain/mangle.h
+++ b/com32/chain/mangle.h
@@ -1,5 +1,35 @@
-#ifndef _COM32_CHAIN_MANGLE_H
-#define _COM32_CHAIN_MANGLE_H
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010-2012 Michal Soltys
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_MANGLE_H
+#define COM32_CHAIN_MANGLE_H
#include "chain.h"
#include "partiter.h"
diff --git a/com32/chain/options.c b/com32/chain/options.c
index 658a45ca..4e722a01 100644
--- a/com32/chain/options.c
+++ b/com32/chain/options.c
@@ -1,21 +1,55 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010-2012 Michal Soltys
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <syslinux/movebits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include "common.h"
#include "chain.h"
+#include "partiter.h"
#include "utility.h"
#include "options.h"
struct options opt;
-static int soi_s2n(char *ptr, unsigned int *seg,
- unsigned int *off,
- unsigned int *ip,
- unsigned int def)
+static int soi_s2n(char *ptr,
+ addr_t *seg,
+ addr_t *off,
+ addr_t *ip,
+ addr_t def)
{
- unsigned int segval = 0, offval, ipval, val;
+ addr_t segval, offval, ipval, val;
char *p;
+ /* defaults */
+ segval = 0;
offval = def;
ipval = def;
@@ -25,17 +59,22 @@ static int soi_s2n(char *ptr, unsigned int *seg,
if (p[0] == ':' && p[1] && p[1] != ':')
ipval = strtoul(p+1, NULL, 0);
+ /* verify if load address is within [dosmin, dosmax) */
val = (segval << 4) + offval;
- if (val < ADDRMIN || val > ADDRMAX) {
- error("Invalid seg:off:* address specified..\n");
+ if (val < dosmin || val >= dosmax) {
+ error("Invalid seg:off:* address specified.");
goto bail;
}
+ /*
+ * verify if jump address is within [dosmin, dosmax) and offset is 16bit
+ * sane
+ */
val = (segval << 4) + ipval;
- if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
- error("Invalid seg:*:ip address specified.\n");
+ if (ipval > 0xFFFE || val < dosmin || val >= dosmax) {
+ error("Invalid seg:*:ip address specified.");
goto bail;
}
@@ -53,75 +92,82 @@ bail:
static void usage(void)
{
- unsigned int i;
- static const char key[] = "Press any key...\n";
+ size_t i;
static const char *const usage[] = {
-"\
-Usage:\n\
- chain.c32 [options]\n\
- chain.c32 {fd|hd}<disk#>{,| }[<part#>] [options]\n\
- chain.c32 mbr{:|=}<id>{,| }[<part#>] [options]\n\
- chain.c32 guid{:|=}<guid>{,| }[<part#>] [options]\n\
- chain.c32 label{:|=}<label> [<part#>] [options]\n\
- chain.c32 boot{,| }[<part#>] [options]\n\
- chain.c32 fs [options]\n\
-", "\
-\nOptions ('no' prefix specifies default value):\n\
- sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
- - defaults to 0:0x7C00:0x7C00\n\
- - ommited o/i values default to 0\n\
- maps Map loaded sector into real memory\n\
- nosetbpb Fix BPB fields in loaded sector\n\
- nofilebpb Apply 'setbpb' to loaded file\n\
- nosave Write adjusted sector back to disk\n\
- hand Prepare handover area\n\
- nohptr Force ds:si and ds:bp to point to handover area\n\
- noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
- nohide Disable all hide variations (also the default)\n\
- hide Hide primary partitions, unhide selected partition\n\
- hideall Hide *all* partitions, unhide selected partition\n\
- unhide Unhide primary partitions\n\
- unhideall Unhide *all* partitions\n\
- nofixchs Walk *all* partitions and fix E/MBRs' chs values\n\
- nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
- nowarn Wait for a keypress to continue chainloading\n\
- - useful to see emited warnings\n\
- nobreak Actually perform the chainloading\n\
-", "\
-\nOptions continued ...\n\
- file=<file> Load and execute <file>\n\
- seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
- - defaults to 0:0x7C00:0x7C00\n\
- - ommited o/i values default to 0\n\
- isolinux=<loader> Load another version of ISOLINUX\n\
- ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
- reactos=<loader> Load ReactOS's loader\n\
- cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
- freedos=<loader> Load FreeDOS KERNEL.SYS\n\
- msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\
- msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
- pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
- drmk=<loader> Load DRMK DELLBIO.BIN\n\
- grub=<loader> Load GRUB Legacy stage2\n\
- grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
- grldr=<loader> Load GRUB4DOS grldr\n\
- bss=<filename> Emulate syslinux's BSS\n\
- bs=<filename> Emulate syslinux's BS\n\
-\nPlease see doc/chain.txt for the detailed documentation.\n\
-"
- };
+"Usage:",
+"",
+" disk + partition selection:",
+" chain.c32 [options]",
+" chain.c32 hd#[,#] [options]",
+" chain.c32 fd#[,#] [options]",
+" chain.c32 mbr=<id>[,#] [options]",
+" chain.c32 guid=<guid>[,#] [options]",
+" chain.c32 boot[,#] [options]",
+"",
+" direct partition selection:",
+" chain.c32 guid=<guid> [options]",
+" chain.c32 label=<label> [options]",
+" chain.c32 fs [options]",
+"",
+"You can use ':' instead of '=' and ' ' instead of ','.",
+"The default is 'boot,0'.",
+"",
+"Options:",
+" sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>",
+" - defaults to 0:0x7C00:0x7C00",
+" - omitted o/i values default to 0",
+" maps Map loaded sector into real memory",
+" setbpb Fix BPB fields in loaded sector",
+" filebpb Apply 'setbpb' to loaded file",
+" save Write adjusted sector back to disk",
+" hand Prepare handover area",
+" hptr Force ds:si and ds:bp to point to handover area",
+" swap Swap drive numbers, if bootdisk is not fd0/hd0",
+" nohide Disable all hide variations (default)",
+" hide Hide primary partitions, unhide selected partition",
+" hideall Hide *all* partitions, unhide selected partition",
+" unhide Unhide primary partitions",
+" unhideall Unhide *all* partitions",
+" fixchs Walk *all* partitions and fix E/MBRs' CHS values",
+" keeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)",
+" warn Wait for a keypress to continue chainloading",
+" break Don't chainload",
+" relax Relax sanity checks",
+" prefmbr On hybrid MBR/GPT disks, prefer legacy layout",
+"",
+" file=<file> Load and execute <file>",
+" seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>",
+" - defaults to 0:0x7C00:0x7C00",
+" - omitted o/i values default to 0",
+" isolinux=<loader> Load another version of ISOLINUX",
+" ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR",
+" reactos=<loader> Load ReactOS's loader",
+" cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003",
+" freedos=<loader> Load FreeDOS KERNEL.SYS",
+" msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS",
+" msdos7=<loader> Load MS-DOS 7+ IO.SYS",
+" pcdos=<loader> Load PC-DOS IBMBIO.COM",
+" drmk=<loader> Load DRMK DELLBIO.BIN",
+" grub=<loader> Load GRUB Legacy stage2",
+" grubcfg=<config> Set alternative config filename for GRUB Legacy",
+" grldr=<loader> Load GRUB4DOS grldr",
+" bss=<sectimage> Emulate syslinux's BSS",
+" bs=<sectimage> Emulate syslinux's BS",
+"",
+"Please see doc/chain.txt for the detailed documentation."
+};
for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
- if (i) {
- error(key);
+ if (i % 20 == 19) {
+ puts("Press any key...");
wait_key();
}
- error(usage[i]);
+ puts(usage[i]);
}
}
void opt_set_defs(void)
{
- memset(&opt, 0, sizeof(opt));
+ memset(&opt, 0, sizeof opt);
opt.sect = true; /* by def. load sector */
opt.maps = true; /* by def. map sector */
opt.hand = true; /* by def. prepare handover */
@@ -136,7 +182,7 @@ void opt_set_defs(void)
int opt_parse_args(int argc, char *argv[])
{
int i;
- unsigned int v;
+ size_t v;
char *p;
for (i = 1; i < argc; i++) {
@@ -152,7 +198,6 @@ int opt_parse_args(int argc, char *argv[])
opt.bss = true;
opt.maps = false;
opt.setbpb = true;
- /* opt.save = true; */
} else if (!strncmp(argv[i], "bs=", 3)) {
opt.file = argv[i] + 3;
opt.sect = false;
@@ -168,7 +213,6 @@ int opt_parse_args(int argc, char *argv[])
opt.fip = 0;
opt.file = argv[i] + 6;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "reactos=", 8)) {
/*
@@ -182,7 +226,6 @@ int opt_parse_args(int argc, char *argv[])
opt.fip = 0x8100;
opt.file = argv[i] + 8;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "cmldr=", 6)) {
opt.fseg = 0x2000; /* CMLDR wants this address */
@@ -191,7 +234,6 @@ int opt_parse_args(int argc, char *argv[])
opt.file = argv[i] + 6;
opt.cmldr = true;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "freedos=", 8)) {
opt.fseg = 0x60; /* FREEDOS wants this address */
@@ -200,7 +242,6 @@ int opt_parse_args(int argc, char *argv[])
opt.sseg = 0x1FE0;
opt.file = argv[i] + 8;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
!strncmp(argv[i], "pcdos=", v)) ||
@@ -211,7 +252,6 @@ int opt_parse_args(int argc, char *argv[])
opt.sseg = 0x8000;
opt.file = argv[i] + v;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "drmk=", 5)) {
opt.fseg = 0x70; /* DRMK wants this address */
@@ -223,7 +263,6 @@ int opt_parse_args(int argc, char *argv[])
opt.file = argv[i] + 5;
/* opt.drmk = true; */
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "grub=", 5)) {
opt.fseg = 0x800; /* stage2 wants this address */
@@ -261,15 +300,15 @@ int opt_parse_args(int argc, char *argv[])
} else if (!strcmp(argv[i], "noswap")) {
opt.swap = false;
} else if (!strcmp(argv[i], "nohide")) {
- opt.hide = 0;
+ opt.hide = HIDE_OFF;
} else if (!strcmp(argv[i], "hide")) {
- opt.hide = 1; /* 001b */
+ opt.hide = HIDE_ON;
} else if (!strcmp(argv[i], "hideall")) {
- opt.hide = 2; /* 010b */
+ opt.hide = HIDE_ON | HIDE_EXT;
} else if (!strcmp(argv[i], "unhide")) {
- opt.hide = 5; /* 101b */
+ opt.hide = HIDE_ON | HIDE_REV;
} else if (!strcmp(argv[i], "unhideall")) {
- opt.hide = 6; /* 110b */
+ opt.hide = HIDE_ON | HIDE_EXT | HIDE_REV;
} else if (!strcmp(argv[i], "setbpb")) {
opt.setbpb = true;
} else if (!strcmp(argv[i], "nosetbpb")) {
@@ -296,10 +335,18 @@ int opt_parse_args(int argc, char *argv[])
opt.fixchs = true;
} else if (!strcmp(argv[i], "nofixchs")) {
opt.fixchs = false;
+ } else if (!strcmp(argv[i], "relax")) {
+ opt.piflags |= PIF_RELAX;
+ } else if (!strcmp(argv[i], "norelax")) {
+ opt.piflags &= ~PIF_RELAX;
} else if (!strcmp(argv[i], "warn")) {
opt.warn = true;
} else if (!strcmp(argv[i], "nowarn")) {
opt.warn = false;
+ } else if (!strcmp(argv[i], "prefmbr")) {
+ opt.piflags |= PIF_PREFMBR;
+ } else if (!strcmp(argv[i], "noprefmbr")) {
+ opt.piflags &= ~PIF_PREFMBR;
} else if (!strcmp(argv[i], "nobreak")) {
opt.brkchain = false;
} else if (!strcmp(argv[i], "break")) {
@@ -337,34 +384,27 @@ int opt_parse_args(int argc, char *argv[])
}
if (opt.grubcfg && !opt.grub) {
- error("grubcfg=<filename> must be used together with grub=<loader>.\n");
+ error("grubcfg=<filename> must be used together with grub=<loader>.");
goto bail;
}
-#if 0
- if ((!opt.maps || !opt.sect) && !opt.file) {
- error("You have to load something.\n");
- goto bail;
- }
-#endif
-
if (opt.filebpb && !opt.file) {
- error("Option 'filebpb' requires a file.\n");
+ error("Option 'filebpb' requires a file.");
goto bail;
}
if (opt.save && !opt.sect) {
- error("Option 'save' requires a sector.\n");
+ error("Option 'save' requires a sector.");
goto bail;
}
if (opt.setbpb && !opt.sect) {
- error("Option 'setbpb' requires a sector.\n");
+ error("Option 'setbpb' requires a sector.");
goto bail;
}
if (opt.maps && !opt.sect) {
- error("Option 'maps' requires a sector.\n");
+ error("Option 'maps' requires a sector.");
goto bail;
}
diff --git a/com32/chain/options.h b/com32/chain/options.h
index 4493ef1f..df96e2d3 100644
--- a/com32/chain/options.h
+++ b/com32/chain/options.h
@@ -1,20 +1,56 @@
-#ifndef _COM32_CHAIN_OPTIONS_H
-#define _COM32_CHAIN_OPTIONS_H
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010-2012 Michal Soltys
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_OPTIONS_H
+#define COM32_CHAIN_OPTIONS_H
#include <stdint.h>
#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+
+enum {HIDE_OFF = 0, HIDE_ON = 1, HIDE_EXT = 2, HIDE_REV = 4};
struct options {
- unsigned int fseg;
- unsigned int foff;
- unsigned int fip;
- unsigned int sseg;
- unsigned int soff;
- unsigned int sip;
const char *drivename;
const char *partition;
const char *file;
const char *grubcfg;
+ addr_t fseg;
+ addr_t foff;
+ addr_t fip;
+ addr_t sseg;
+ addr_t soff;
+ addr_t sip;
+ int hide;
+ int piflags;
+ uint16_t keeppxe;
bool isolinux;
bool cmldr;
bool drmk;
@@ -24,7 +60,6 @@ struct options {
bool hand;
bool hptr;
bool swap;
- int hide;
bool sect;
bool save;
bool bss;
@@ -33,7 +68,6 @@ struct options {
bool fixchs;
bool warn;
bool brkchain;
- uint16_t keeppxe;
struct syslinux_rm_regs regs;
};
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
index 1acd1958..1eb5350d 100644
--- a/com32/chain/partiter.c
+++ b/com32/chain/partiter.c
@@ -1,8 +1,9 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
* Copyright 2010 Shao Miller
- * Copyright 2010 Michal Soltys
+ * Copyright 2010-2012 Michal Soltys
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -39,7 +40,6 @@
#include <stdarg.h>
#include <zlib.h>
#include <syslinux/disk.h>
-#include "common.h"
#include "partiter.h"
#include "utility.h"
@@ -47,175 +47,110 @@
#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
#define sane(s,l) ((s)+(l) > (s))
-/* forwards */
+/* virtual forwards */
-static int iter_ctor(struct part_iter *, va_list *);
-static int iter_dos_ctor(struct part_iter *, va_list *);
-static int iter_gpt_ctor(struct part_iter *, va_list *);
-static void iter_dtor(struct part_iter *);
-static struct part_iter *pi_dos_next(struct part_iter *);
-static struct part_iter *pi_gpt_next(struct part_iter *);
-static struct part_iter *pi_raw_next(struct part_iter *);
+static void pi_dtor_(struct part_iter *);
+static int pi_next_(struct part_iter *);
+static int pi_dos_next(struct part_iter *);
+static int pi_gpt_next(struct part_iter *);
+
+/* vtab and types */
static struct itertype types[] = {
[0] = {
- .ctor = &iter_dos_ctor,
- .dtor = &iter_dtor,
+ .dtor = &pi_dtor_,
.next = &pi_dos_next,
}, [1] = {
- .ctor = &iter_gpt_ctor,
- .dtor = &iter_dtor,
+ .dtor = &pi_dtor_,
.next = &pi_gpt_next,
}, [2] = {
- .ctor = &iter_ctor,
- .dtor = &iter_dtor,
- .next = &pi_raw_next,
+ .dtor = &pi_dtor_,
+ .next = &pi_next_,
}};
const struct itertype * const typedos = types;
const struct itertype * const typegpt = types+1;
const struct itertype * const typeraw = types+2;
-#ifdef DEBUG
-static int inv_type(const void *type)
+/* pi_dtor_() - common/raw iterator cleanup */
+static void pi_dtor_(struct part_iter *iter)
{
- int i, cnt = sizeof(types)/sizeof(types[0]);
- for (i = 0; i < cnt; i++) {
- if (type == types + i)
- return 0;
- }
- return -1;
+ /* syslinux's free is null resilient */
+ free(iter->data);
}
-#endif
-/**
- * iter_ctor() - common iterator initialization
- * @iter: iterator pointer
- * @args(0): disk_info structure used for disk functions
- * @args(1): stepall modifier
- *
- * Second and further arguments are passed as a pointer to va_list
- **/
-static int iter_ctor(struct part_iter *iter, va_list *args)
+/* pi_ctor() - common/raw iterator initialization */
+static int pi_ctor(struct part_iter *iter,
+ const struct disk_info *di, int flags
+)
{
- const struct disk_info *di = va_arg(*args, const struct disk_info *);
- int stepall = va_arg(*args, int);
-
-#ifdef DEBUG
- if (!di)
- return -1;
-#endif
-
- memcpy(&iter->di, di, sizeof(struct disk_info));
- iter->stepall = stepall;
+ memcpy(&iter->di, di, sizeof *di);
+ iter->flags = flags;
iter->index0 = -1;
iter->length = di->lbacnt;
+ iter->type = typeraw;
return 0;
}
-/**
- * iter_dtor() - common iterator cleanup
- * @iter: iterator pointer
- *
- **/
-static void iter_dtor(struct part_iter *iter)
+/* pi_dos_ctor() - MBR/EBR iterator specific initialization */
+static int pi_dos_ctor(struct part_iter *iter,
+ const struct disk_info *di, int flags,
+ const struct disk_dos_mbr *mbr
+)
{
- free(iter->data);
-}
-
-/**
- * iter_dos_ctor() - MBR/EBR iterator specific initialization
- * @iter: iterator pointer
- * @args(0): disk_info structure used for disk functions
- * @args(1): pointer to buffer with loaded valid MBR
- *
- * Second and further arguments are passed as a pointer to va_list.
- * This function only makes rudimentary checks. If user uses
- * pi_new(), he/she is responsible for doing proper sanity checks.
- **/
-static int iter_dos_ctor(struct part_iter *iter, va_list *args)
-{
- const struct disk_dos_mbr *mbr;
-
- /* uses args(0) */
- if (iter_ctor(iter, args))
+ if (pi_ctor(iter, di, flags))
return -1;
- mbr = va_arg(*args, const struct disk_dos_mbr *);
-
-#ifdef DEBUG
- if (!mbr)
- goto bail;
-#endif
-
- if (!(iter->data = malloc(sizeof(struct disk_dos_mbr))))
+ if (!(iter->data = malloc(sizeof *mbr))) {
+ critm();
goto bail;
+ }
- memcpy(iter->data, mbr, sizeof(struct disk_dos_mbr));
+ memcpy(iter->data, mbr, sizeof *mbr);
- iter->sub.dos.bebr_index0 = -1;
- iter->sub.dos.disk_sig = mbr->disk_sig;
+ iter->dos.bebr_index0 = -1;
+ iter->dos.disk_sig = mbr->disk_sig;
+ iter->type = typedos;
return 0;
bail:
- iter->type->dtor(iter);
+ pi_dtor_(iter);
return -1;
}
-/**
- * iter_gpt_ctor() - GPT iterator specific initialization
- * @iter: iterator pointer
- * @args(0): ptr to disk_info structure
- * @args(1): ptr to buffer with GPT header
- * @args(2): ptr to buffer with GPT partition list
- *
- * Second and further arguments are passed as a pointer to va_list.
- * This function only makes rudimentary checks. If user uses
- * pi_new(), he/she is responsible for doing proper sanity checks.
- **/
-static int iter_gpt_ctor(struct part_iter *iter, va_list *args)
+/* pi_gpt_ctor() - GPT iterator specific initialization */
+static int pi_gpt_ctor(struct part_iter *iter,
+ const struct disk_info *di, int flags,
+ const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl
+)
{
uint64_t siz;
- const struct disk_gpt_header *gpth;
- const struct disk_gpt_part_entry *gptl;
- /* uses args(0) */
- if (iter_ctor(iter, args))
+ if (pi_ctor(iter, di, flags))
return -1;
- gpth = va_arg(*args, const struct disk_gpt_header *);
- gptl = va_arg(*args, const struct disk_gpt_part_entry *);
-
-#ifdef DEBUG
- if (!gpth || !gptl)
- goto bail;
-#endif
-
siz = (uint64_t)gpth->part_count * gpth->part_size;
-#ifdef DEBUG
- if (!siz || (siz + iter->di.bps - 1) / iter->di.bps > 255u ||
- gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
+ if (!(iter->data = malloc((size_t)siz))) {
+ critm();
goto bail;
}
-#endif
-
- if (!(iter->data = malloc((size_t)siz)))
- goto bail;
memcpy(iter->data, gptl, (size_t)siz);
- iter->sub.gpt.pe_count = (int)gpth->part_count;
- iter->sub.gpt.pe_size = (int)gpth->part_size;
- iter->sub.gpt.ufirst = gpth->lba_first_usable;
- iter->sub.gpt.ulast = gpth->lba_last_usable;
+ iter->gpt.pe_count = (int)gpth->part_count;
+ iter->gpt.pe_size = (int)gpth->part_size;
+ iter->gpt.ufirst = gpth->lba_first_usable;
+ iter->gpt.ulast = gpth->lba_last_usable;
- memcpy(&iter->sub.gpt.disk_guid, &gpth->disk_guid, sizeof(struct guid));
+ memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
+ memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
+ iter->type = typegpt;
return 0;
bail:
- iter->type->dtor(iter);
+ pi_dtor_(iter);
return -1;
}
@@ -237,18 +172,21 @@ static int notsane_logical(const struct part_iter *iter)
return 0;
if (ost_is_ext(dp[0].ostype)) {
- error("1st EBR entry must be data or empty.\n");
+ error("The 1st EBR entry must be data or empty.");
return -1;
}
+ if (iter->flags & PIF_RELAX)
+ return 0;
+
end_log = dp[0].start_lba + dp[0].length;
if (!dp[0].start_lba ||
!dp[0].length ||
!sane(dp[0].start_lba, dp[0].length) ||
- end_log > iter->sub.dos.ebr_size) {
+ end_log > iter->dos.nebr_siz) {
- error("Insane logical partition.\n");
+ error("Logical partition (in EBR) with invalid offset and/or length.");
return -1;
}
@@ -273,18 +211,21 @@ static int notsane_extended(const struct part_iter *iter)
return 0;
if (!ost_is_nondata(dp[1].ostype)) {
- error("2nd EBR entry must be extended or empty.\n");
+ error("The 2nd EBR entry must be extended or empty.");
return -1;
}
+ if (iter->flags & PIF_RELAX)
+ return 0;
+
end_ebr = dp[1].start_lba + dp[1].length;
if (!dp[1].start_lba ||
!dp[1].length ||
!sane(dp[1].start_lba, dp[1].length) ||
- end_ebr > iter->sub.dos.bebr_size) {
+ end_ebr > iter->dos.bebr_siz) {
- error("Insane extended partition.\n");
+ error("Extended partition (EBR) with invalid offset and/or length.");
return -1;
}
@@ -304,11 +245,14 @@ static int notsane_primary(const struct part_iter *iter)
if (!dp->ostype)
return 0;
+ if (iter->flags & PIF_RELAX)
+ return 0;
+
if (!dp->start_lba ||
!dp->length ||
!sane(dp->start_lba, dp->length) ||
dp->start_lba + dp->length > iter->di.lbacnt) {
- error("Insane primary (MBR) partition.\n");
+ error("Primary partition (in MBR) with invalid offset and/or length.");
return -1;
}
@@ -319,21 +263,24 @@ static int notsane_gpt(const struct part_iter *iter)
{
const struct disk_gpt_part_entry *gp;
gp = (const struct disk_gpt_part_entry *)
- (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+ (iter->data + iter->index0 * iter->gpt.pe_size);
if (guid_is0(&gp->type))
return 0;
- if (gp->lba_first < iter->sub.gpt.ufirst ||
- gp->lba_last > iter->sub.gpt.ulast) {
- error("Insane GPT partition.\n");
+ if (iter->flags & PIF_RELAX)
+ return 0;
+
+ if (gp->lba_first < iter->gpt.ufirst ||
+ gp->lba_last > iter->gpt.ulast) {
+ error("LBA sectors of GPT partition are beyond the range allowed in GPT header.");
return -1;
}
return 0;
}
-static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
+static int dos_next_mbr(struct part_iter *iter, uint32_t *lba,
struct disk_dos_part_entry **_dp)
{
struct disk_dos_part_entry *dp;
@@ -343,19 +290,19 @@ static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
if (notsane_primary(iter)) {
iter->status = PI_INSANE;
- goto bail;
+ return -1;
}
if (ost_is_ext(dp->ostype)) {
- if (iter->sub.dos.bebr_index0 >= 0) {
- error("You have more than 1 extended partition.\n");
+ if (iter->dos.bebr_index0 >= 0) {
+ error("More than 1 extended partition.");
iter->status = PI_INSANE;
- goto bail;
+ return -1;
}
/* record base EBR index */
- iter->sub.dos.bebr_index0 = iter->index0;
+ iter->dos.bebr_index0 = iter->index0;
}
- if (!ost_is_nondata(dp->ostype) || iter->stepall) {
+ if (!ost_is_nondata(dp->ostype) || (iter->flags & PIF_STEPALL)) {
*lba = dp->start_lba;
*_dp = dp;
break;
@@ -363,52 +310,48 @@ static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
}
return 0;
-bail:
- return -1;
}
static int prep_base_ebr(struct part_iter *iter)
{
struct disk_dos_part_entry *dp;
- if (iter->sub.dos.bebr_index0 < 0) /* if we don't have base extended partition at all */
+ if (iter->dos.bebr_index0 < 0) /* if we don't have base extended partition at all */
return -1;
- else if (!iter->sub.dos.bebr_start) { /* if not initialized yet */
- dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.bebr_index0;
-
- iter->sub.dos.bebr_start = dp->start_lba;
- iter->sub.dos.bebr_size = dp->length;
+ else if (!iter->dos.bebr_lba) { /* if not initialized yet */
+ dp = ((struct disk_dos_mbr *)iter->data)->table + iter->dos.bebr_index0;
- iter->sub.dos.ebr_start = 0;
- iter->sub.dos.ebr_size = iter->sub.dos.bebr_size;
+ iter->dos.bebr_lba = dp->start_lba;
+ iter->dos.bebr_siz = dp->length;
- iter->sub.dos.cebr_lba = 0;
- iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start;
+ iter->dos.nebr_lba = dp->start_lba;
+ iter->dos.nebr_siz = dp->length;
iter->index0--;
}
return 0;
}
-static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
+static int dos_next_ebr(struct part_iter *iter, uint32_t *lba,
struct disk_dos_part_entry **_dp)
{
struct disk_dos_part_entry *dp;
- if (prep_base_ebr(iter)) {
+ if (prep_base_ebr(iter) < 0) {
iter->status = PI_DONE;
return -1;
}
- while (++iter->index0 < 1024 && iter->sub.dos.nebr_lba) {
+ while (++iter->index0 < 1024 && iter->dos.nebr_lba) {
free(iter->data);
if (!(iter->data =
- disk_read_sectors(&iter->di, iter->sub.dos.nebr_lba, 1))) {
- error("Couldn't load EBR.\n");
+ disk_read_sectors(&iter->di, iter->dos.nebr_lba, 1))) {
+ error("Couldn't load EBR.");
iter->status = PI_ERRLOAD;
return -1;
}
+ /* check sanity of loaded data */
if (notsane_logical(iter) || notsane_extended(iter)) {
iter->status = PI_INSANE;
return -1;
@@ -416,24 +359,23 @@ static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
dp = ((struct disk_dos_mbr *)iter->data)->table;
- iter->sub.dos.cebr_lba = iter->sub.dos.nebr_lba;
+ iter->dos.cebr_lba = iter->dos.nebr_lba;
+ iter->dos.cebr_siz = iter->dos.nebr_siz;
/* setup next frame values */
if (dp[1].ostype) {
- iter->sub.dos.ebr_start = dp[1].start_lba;
- iter->sub.dos.ebr_size = dp[1].length;
- iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start + dp[1].start_lba;
+ iter->dos.nebr_lba = iter->dos.bebr_lba + dp[1].start_lba;
+ iter->dos.nebr_siz = dp[1].length;
} else {
- iter->sub.dos.ebr_start = 0;
- iter->sub.dos.ebr_size = 0;
- iter->sub.dos.nebr_lba = 0;
+ iter->dos.nebr_lba = 0;
+ iter->dos.nebr_siz = 0;
}
if (!dp[0].ostype)
- iter->sub.dos.skipcnt++;
+ iter->dos.logskipcnt++;
- if (dp[0].ostype || iter->stepall) {
- *lba = iter->sub.dos.cebr_lba + dp[0].start_lba;
+ if (dp[0].ostype || (iter->flags & PIF_STEPALL)) {
+ *lba = dp[0].start_lba ? iter->dos.cebr_lba + dp[0].start_lba : 0;
*_dp = dp;
return 0;
}
@@ -441,128 +383,33 @@ static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
* This way it's possible to continue, if some crazy soft left a "hole"
* - EBR with a valid extended partition without a logical one. In
* such case, linux will not reserve a number for such hole - so we
- * don't increase index0. If stepall flag is set, we will never reach
- * this place.
+ * don't increase index0. If PIF_STEPALL flag is set, we will never
+ * reach this place.
*/
}
iter->status = PI_DONE;
return -1;
}
-static struct part_iter *pi_dos_next(struct part_iter *iter)
-{
- uint32_t start_lba = 0;
- struct disk_dos_part_entry *dos_part = NULL;
-
- if (iter->status)
- goto bail;
-
- /* look for primary partitions */
- if (iter->index0 < 4 &&
- pi_dos_next_mbr(iter, &start_lba, &dos_part))
- goto bail;
-
- /* look for logical partitions */
- if (iter->index0 >= 4 &&
- pi_dos_next_ebr(iter, &start_lba, &dos_part))
- goto bail;
-
- /*
- * note special index handling, if we have stepall set -
- * this is made to keep index consistent with non-stepall
- * iterators
- */
-
- if (iter->index0 >= 4 && !dos_part->ostype)
- iter->index = -1;
- else
- iter->index = iter->index0 - iter->sub.dos.skipcnt + 1;
- iter->rawindex = iter->index0 + 1;
- iter->start_lba = start_lba;
- iter->length = dos_part->length;
- iter->record = (char *)dos_part;
-
-#ifdef DEBUG
- disk_dos_part_dump(dos_part);
-#endif
-
- return iter;
-bail:
- return NULL;
-}
-
static void gpt_conv_label(struct part_iter *iter)
{
const struct disk_gpt_part_entry *gp;
const int16_t *orig_lab;
gp = (const struct disk_gpt_part_entry *)
- (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+ (iter->data + iter->index0 * iter->gpt.pe_size);
orig_lab = (const int16_t *)gp->name;
/* caveat: this is very crude conversion */
for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
- iter->sub.gpt.part_label[i] = (char)orig_lab[i];
- }
- iter->sub.gpt.part_label[PI_GPTLABSIZE/2] = 0;
-}
-
-static struct part_iter *pi_gpt_next(struct part_iter *iter)
-{
- const struct disk_gpt_part_entry *gpt_part = NULL;
-
- if (iter->status)
- goto bail;
-
- while (++iter->index0 < iter->sub.gpt.pe_count) {
- gpt_part = (const struct disk_gpt_part_entry *)
- (iter->data + iter->index0 * iter->sub.gpt.pe_size);
-
- if (notsane_gpt(iter)) {
- iter->status = PI_INSANE;
- goto bail;
- }
-
- if (!guid_is0(&gpt_part->type) || iter->stepall)
- break;
- }
- /* no more partitions ? */
- if (iter->index0 == iter->sub.gpt.pe_count) {
- iter->status = PI_DONE;
- goto bail;
+ iter->gpt.part_label[i] = (char)orig_lab[i];
}
- /* gpt_part is guaranteed to be valid here */
- iter->index = iter->index0 + 1;
- iter->rawindex = iter->index0 + 1;
- iter->start_lba = gpt_part->lba_first;
- iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
- iter->record = (char *)gpt_part;
- memcpy(&iter->sub.gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
- gpt_conv_label(iter);
-
-#ifdef DEBUG
- disk_gpt_part_dump(gpt_part);
-#endif
-
- return iter;
-bail:
- return NULL;
-}
-
-static struct part_iter *pi_raw_next(struct part_iter *iter)
-{
- iter->status = PI_DONE;
- return NULL;
+ iter->gpt.part_label[PI_GPTLABSIZE/2] = 0;
}
-static int check_crc(uint32_t crc_match, const uint8_t *buf, unsigned int siz)
+static inline int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz)
{
- uint32_t crc;
-
- crc = crc32(0, NULL, 0);
- crc = crc32(crc, buf, siz);
-
- return crc_match != crc;
+ return crc == crc32(crc32(0, NULL, 0), buf, siz);
}
static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh)
@@ -573,19 +420,19 @@ static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct dis
hold_crc32 = gh->chksum;
gh->chksum = 0;
- if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
- error("WARNING: Primary GPT header checksum invalid.\n");
+ if (!valid_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+ warn("Primary GPT header checksum invalid.");
/* retry with backup */
lba_alt = gh->lba_alt;
free(gh);
if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) {
- error("Couldn't read backup GPT header.\n");
+ error("Couldn't read backup GPT header.");
return -1;
}
hold_crc32 = gh->chksum;
gh->chksum = 0;
- if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
- error("Secondary GPT header checksum invalid.\n");
+ if (!valid_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+ error("Secondary GPT header checksum invalid.");
return -1;
}
}
@@ -595,149 +442,156 @@ static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct dis
return 0;
}
-/*
- * ----------------------------------------------------------------------------
- * Following functions are for users to call.
- * ----------------------------------------------------------------------------
- */
-
+static int pi_next_(struct part_iter *iter)
+{
+ iter->status = PI_DONE;
+ return iter->status;
+}
-int pi_next(struct part_iter **_iter)
+static int pi_dos_next(struct part_iter *iter)
{
- struct part_iter *iter;
+ uint32_t abs_lba = 0;
+ struct disk_dos_part_entry *dos_part = NULL;
+
+ if (iter->status)
+ return iter->status;
+
+ /* look for primary partitions */
+ if (iter->index0 < 4 &&
+ dos_next_mbr(iter, &abs_lba, &dos_part) < 0)
+ return iter->status;
+
+ /* look for logical partitions */
+ if (iter->index0 >= 4 &&
+ dos_next_ebr(iter, &abs_lba, &dos_part) < 0)
+ return iter->status;
+
+ /*
+ * note special index handling:
+ * in case PIF_STEPALL is set - this makes the index consistent with
+ * non-PIF_STEPALL iterators
+ */
+
+ if (!dos_part->ostype)
+ iter->index = -1;
+ else
+ iter->index = iter->index0 + 1 - iter->dos.logskipcnt;
+ iter->abs_lba = abs_lba;
+ iter->length = dos_part->length;
+ iter->record = (char *)dos_part;
- if(!_iter || !*_iter)
- return 0;
- iter = *_iter;
#ifdef DEBUG
- if (inv_type(iter->type)) {
- error("This is not a valid iterator.\n");
- return 0;
- }
+ disk_dos_part_dump(dos_part);
#endif
- if ((iter = iter->type->next(iter))) {
- *_iter = iter;
- }
- return (*_iter)->status;
+
+ return iter->status;
}
-/**
- * pi_new() - get new iterator
- * @itertype: iterator type
- * @...: variable arguments passed to ctors
- *
- * Variable arguments depend on the type. Please see functions:
- * iter_gpt_ctor() and iter_dos_ctor() for details.
- **/
-struct part_iter *pi_new(const struct itertype *type, ...)
+static int pi_gpt_next(struct part_iter *iter)
{
- int badctor = 0;
- struct part_iter *iter = NULL;
- va_list ap;
+ const struct disk_gpt_part_entry *gpt_part = NULL;
- va_start(ap, type);
+ if (iter->status)
+ return iter->status;
-#ifdef DEBUG
- if (inv_type(type)) {
- error("Unknown iterator requested.\n");
- goto bail;
- }
-#endif
+ while (++iter->index0 < iter->gpt.pe_count) {
+ gpt_part = (const struct disk_gpt_part_entry *)
+ (iter->data + iter->index0 * iter->gpt.pe_size);
- if (!(iter = malloc(sizeof(struct part_iter)))) {
- error("Couldn't allocate memory for the iterator.\n");
- goto bail;
+ if (notsane_gpt(iter)) {
+ iter->status = PI_INSANE;
+ return iter->status;
+ }
+
+ if (!guid_is0(&gpt_part->type) || (iter->flags & PIF_STEPALL))
+ break;
}
+ /* no more partitions ? */
+ if (iter->index0 == iter->gpt.pe_count) {
+ iter->status = PI_DONE;
+ return iter->status;
+ }
+ /* gpt_part is guaranteed to be valid here */
+ iter->index = iter->index0 + 1;
+ iter->abs_lba = gpt_part->lba_first;
+ iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
+ iter->record = (char *)gpt_part;
+ memcpy(&iter->gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
+ gpt_conv_label(iter);
- memset(iter, 0, sizeof(struct part_iter));
- iter->type = type;
+#ifdef DEBUG
+ disk_gpt_part_dump(gpt_part);
+#endif
- if (type->ctor(iter, &ap)) {
- badctor = -1;
- error("Cannot initialize the iterator.\n");
- goto bail;
- }
+ return iter->status;
+}
-bail:
- va_end(ap);
- if (badctor) {
- free(iter);
- iter = NULL;
- }
+static struct part_iter *pi_alloc(void)
+{
+ struct part_iter *iter;
+ if (!(iter = malloc(sizeof *iter)))
+ critm();
+ else
+ memset(iter, 0, sizeof *iter);
return iter;
}
-/**
- * pi_del() - delete iterator
- * @iter: iterator double pointer
- *
- **/
-
+/* pi_del() - delete iterator */
void pi_del(struct part_iter **_iter)
{
- struct part_iter *iter;
-
if(!_iter || !*_iter)
return;
- iter = *_iter;
-
-#ifdef DEBUG
- if (inv_type(iter->type)) {
- error("This is not a valid iterator.\n");
- return;
- }
-#endif
-
- iter->type->dtor(iter);
- free(iter);
+ pi_dtor(*_iter);
+ free(*_iter);
*_iter = NULL;
}
-/**
- * pi_begin() - check disk, validate, and get proper iterator
- * @di: diskinfo struct pointer
- *
- * This function checks the disk for GPT or legacy partition table and allocates
- * an appropriate iterator.
- **/
-struct part_iter *pi_begin(const struct disk_info *di, int stepall)
+/* pi_begin() - validate and and get proper iterator for a disk described by di */
+struct part_iter *pi_begin(const struct disk_info *di, int flags)
{
- int setraw = 0;
- struct part_iter *iter = NULL;
+ int gptprot, ret = -1;
+ struct part_iter *iter;
struct disk_dos_mbr *mbr = NULL;
struct disk_gpt_header *gpth = NULL;
struct disk_gpt_part_entry *gptl = NULL;
+ /* Preallocate iterator */
+ if (!(iter = pi_alloc()))
+ goto bail;
+
/* Read MBR */
if (!(mbr = disk_read_sectors(di, 0, 1))) {
- error("Couldn't read first disk sector.\n");
+ error("Couldn't read the first disk sector.");
goto bail;
}
- setraw = -1;
-
- /* Check for MBR magic*/
+ /* Check for MBR magic */
if (mbr->sig != disk_mbr_sig_magic) {
- error("No MBR magic.\n");
+ warn("No MBR magic, treating disk as raw.");
+ /* looks like RAW */
+ ret = pi_ctor(iter, di, flags);
goto bail;
}
/* Check for GPT protective MBR */
- if (mbr->table[0].ostype == 0xEE) {
+ gptprot = 0;
+ for (size_t i = 0; i < 4; i++)
+ gptprot |= (mbr->table[i].ostype == 0xEE);
+ if (gptprot && !(flags & PIF_PREFMBR)) {
if (!(gpth = disk_read_sectors(di, 1, 1))) {
- error("Couldn't read potential GPT header.\n");
+ error("Couldn't read potential GPT header.");
goto bail;
}
}
if (gpth && gpth->rev.uint32 == 0x00010000 &&
- !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) {
+ !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) {
/* looks like GPT v1.0 */
uint64_t gpt_loff; /* offset to GPT partition list in sectors */
uint64_t gpt_lsiz; /* size of GPT partition list in bytes */
uint64_t gpt_lcnt; /* size of GPT partition in sectors */
#ifdef DEBUG
- puts("Looks like a GPT v1.0 disk.");
+ dprintf("Looks like a GPT v1.0 disk.\n");
disk_gpt_header_dump(gpth);
#endif
/* Verify checksum, fallback to backup, then bail if invalid */
@@ -753,48 +607,45 @@ struct part_iter *pi_begin(const struct disk_info *di, int stepall)
* it as a sanity check base. EFI doesn't specify max (AFAIK).
* Apart from that, some extensive sanity checks.
*/
- if (!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u ||
+ if (!(flags & PIF_RELAX) && (
+ !gpt_loff || !gpt_lsiz || gpt_lcnt > 255u ||
gpth->lba_first_usable > gpth->lba_last_usable ||
!sane(gpt_loff, gpt_lcnt) ||
gpt_loff + gpt_lcnt > gpth->lba_first_usable ||
!sane(gpth->lba_last_usable, gpt_lcnt) ||
gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt ||
gpth->lba_alt >= di->lbacnt ||
- gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
- error("Invalid GPT header's values.\n");
+ gpth->part_size < sizeof *gptl)) {
+ error("Invalid GPT header's values.");
goto bail;
}
- if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)gpt_lcnt))) {
- error("Couldn't read GPT partition list.\n");
+ if (!(gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt))) {
+ error("Couldn't read GPT partition list.");
goto bail;
}
/* Check array checksum(s). */
- if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
- error("WARNING: GPT partition list checksum invalid, trying backup.\n");
+ if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+ warn("Checksum of the main GPT partition list is invalid, trying backup.");
free(gptl);
/* secondary array directly precedes secondary header */
- if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, (uint8_t)gpt_lcnt))) {
- error("Couldn't read backup GPT partition list.\n");
+ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, gpt_lcnt))) {
+ error("Couldn't read backup GPT partition list.");
goto bail;
}
- if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
- error("Backup GPT partition list checksum invalid.\n");
+ if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) {
+ error("Checksum of the backup GPT partition list is invalid, giving up.");
goto bail;
}
}
- /* allocate iterator and exit */
- iter = pi_new(typegpt, di, stepall, gpth, gptl);
+ /* looks like GPT */
+ ret = pi_gpt_ctor(iter, di, flags, gpth, gptl);
} else {
/* looks like MBR */
- iter = pi_new(typedos, di, stepall, mbr);
+ ret = pi_dos_ctor(iter, di, flags, mbr);
}
-
- setraw = 0;
bail:
- if (setraw) {
- error("WARNING: treating disk as raw.\n");
- iter = pi_new(typeraw, di, stepall);
- }
+ if (ret < 0)
+ free(iter);
free(mbr);
free(gpth);
free(gptl);
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
index 7deeb534..13dec848 100644
--- a/com32/chain/partiter.h
+++ b/com32/chain/partiter.h
@@ -1,8 +1,9 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
- * Copyright 2010 Michal Soltys
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
* Copyright 2010 Shao Miller
+ * Copyright 2010-2012 Michal Soltys
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -33,24 +34,26 @@
* Provides disk / partition iteration.
*/
-#ifndef _COM32_CHAIN_PARTITER_H
-#define _COM32_CHAIN_PARTITER_H
+#ifndef COM32_CHAIN_PARTITER_H
+#define COM32_CHAIN_PARTITER_H
#include <stdint.h>
#include <syslinux/disk.h>
-#define PI_ERRLOAD 3
-#define PI_INSANE 2
-#define PI_DONE 1
-#define PI_OK 0
+/* status */
+
+enum {PI_OK, PI_DONE, PI_INSANE, PI_ERRLOAD};
+
+/* flags */
+
+enum {PIF_STEPALL = 1, PIF_RELAX = 2, PIF_PREFMBR = 4};
struct itertype;
struct part_iter;
struct itertype {
- int (*ctor)(struct part_iter *, va_list *);
void (*dtor)(struct part_iter *);
- struct part_iter *(*next) (struct part_iter *);
+ int (*next)(struct part_iter *);
};
#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name))
@@ -59,29 +62,29 @@ struct part_iter {
const struct itertype *type;
char *data;
char *record;
- uint64_t start_lba;
+ uint64_t abs_lba;
uint64_t length;
- int index;
- int rawindex;
+ int index0; /* including holes, from -1 (disk, then parts from 0) */
+ int index; /* excluding holes, from 0 (disk, then parts from 1), -1 means hole, if PIF_STEPALL is set */
+ int flags; /* flags, see #defines above */
+ int status; /* current status, see enums above */
struct disk_info di;
- int stepall;
- int status;
- /* internal */
- int index0;
- union _sub {
- struct _dos {
- uint32_t disk_sig;
- uint32_t nebr_lba;
- uint32_t cebr_lba;
- /* internal */
- uint32_t ebr_start;
- uint32_t ebr_size;
- uint32_t bebr_start;
- uint32_t bebr_size;
- int bebr_index0;
- int skipcnt;
+ union {
+ struct {
+ uint32_t disk_sig; /* 32bit disk signature as stored in MBR */
+
+ uint32_t bebr_lba; /* absolute lba of base extended partition */
+ uint32_t bebr_siz; /* size of base extended partition */
+
+ uint32_t cebr_lba; /* absolute lba of curr ext. partition */
+ uint32_t cebr_siz; /* size of curr ext. partition */
+ uint32_t nebr_lba; /* absolute lba of next ext. partition */
+ uint32_t nebr_siz; /* size of next ext. partition */
+
+ int bebr_index0; /* index of (0-3) of base ext. part., -1 if not present in MBR */
+ int logskipcnt; /* how many logical holes were skipped */
} dos;
- struct _gpt {
+ struct {
struct guid disk_guid;
struct guid part_guid;
char part_label[PI_GPTLABSIZE/2+1];
@@ -90,17 +93,31 @@ struct part_iter {
uint64_t ufirst;
uint64_t ulast;
} gpt;
- } sub;
+ };
};
extern const struct itertype * const typedos;
extern const struct itertype * const typegpt;
extern const struct itertype * const typeraw;
-struct part_iter *pi_begin(const struct disk_info *, int stepall);
-struct part_iter *pi_new(const struct itertype *, ...);
+struct part_iter *pi_begin(const struct disk_info *, int flags);
void pi_del(struct part_iter **);
-int pi_next(struct part_iter **);
+
+static inline int pi_errored(struct part_iter *iter)
+{
+ return iter->status > PI_DONE;
+}
+
+/* inline virtuals */
+static inline int pi_next(struct part_iter *iter)
+{
+ return iter->type->next(iter);
+}
+
+static inline void pi_dtor(struct part_iter *iter)
+{
+ iter->type->dtor(iter);
+}
#endif
diff --git a/com32/chain/utility.c b/com32/chain/utility.c
index cb882722..b17997f7 100644
--- a/com32/chain/utility.c
+++ b/com32/chain/utility.c
@@ -1,4 +1,35 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010-2012 Michal Soltys
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
#include <com32.h>
+#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
@@ -18,18 +49,9 @@ static const char *bpbtypes[] = {
[5] = "4.0",
[6] = "8.0 (NT+)",
[7] = "7.0",
+ [8] = "exFAT",
};
-void error(const char *msg)
-{
- fputs(msg, stderr);
-}
-
-int guid_is0(const struct guid *guid)
-{
- return !*(const uint64_t *)guid && !*((const uint64_t *)guid + 1);
-}
-
void wait_key(void)
{
int cnt;
@@ -48,7 +70,29 @@ void wait_key(void)
} while (!cnt || (cnt < 0 && errno == EAGAIN));
}
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode)
+int guid_is0(const struct guid *guid)
+{
+ return
+ !(guid->data1 ||
+ guid->data2 ||
+ guid->data3 ||
+ guid->data4);
+}
+
+/*
+ * mode explanation:
+ *
+ * cnul - "strict" mode, never returning higher value than obtained from cbios
+ * cadd - if the disk is larger than reported geometry /and/ if the geometry has
+ * less cylinders than 1024 - it means that the total size is somewhere
+ * between cs and cs+1; in this particular case, we bump the cs to be able
+ * to return matching chs triplet
+ * cmax - assume we can use any cylinder value
+ *
+ * by default cadd seems most reasonable, giving consistent results with e.g.
+ * sfdisk's behavior
+ */
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode)
{
uint32_t c, h, s, t;
uint32_t cs, hs, ss;
@@ -61,9 +105,10 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
cs = di->cyl;
hs = di->head;
ss = di->spt;
- if (mode == l2c_cadd && cs < 1024 && di->lbacnt > cs*hs*ss)
- cs++;
- else if (mode == l2c_cmax)
+ if (mode == L2C_CADD) {
+ if (cs < 1024 && di->lbacnt > cs*hs*ss)
+ cs++;
+ } else if (mode == L2C_CMAX)
cs = 1024;
} else {
if (di->disk & 0x80) {
@@ -82,8 +127,8 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
h = hs - 1;
c = cs - 1;
} else {
- s = ((uint32_t)lba % ss) + 1;
- t = (uint32_t)lba / ss;
+ s = (lba % ss) + 1;
+ t = lba / ss;
h = t % hs;
c = t / hs;
}
@@ -107,7 +152,7 @@ uint32_t get_file_lba(const char *filename)
/* Put the filename in the bounce buffer */
strlcpy(buf, filename, size);
- if (open_file(buf, &fd) <= 0) {
+ if (open_file(buf, O_RDONLY, &fd) <= 0) {
goto fail; /* Filename not found */
}
@@ -123,14 +168,15 @@ fail:
}
/* drive offset detection */
-int drvoff_detect(int type, unsigned int *off)
+int drvoff_detect(int type)
{
if (bpbV40 <= type && type <= bpbVNT) {
- *off = 0x24;
+ return 0x24;
} else if (type == bpbV70) {
- *off = 0x40;
- } else
- return 0;
+ return 0x40;
+ } else if (type == bpbEXF) {
+ return 0x6F;
+ }
return -1;
}
@@ -142,6 +188,12 @@ int bpb_detect(const uint8_t *sec, const char *tag)
{
int a, b, c, jmp = -1, rev = 0;
+ /* exFAT mess first (media descriptor is 0 here) */
+ if (!memcmp(sec + 0x03, "EXFAT ", 8)) {
+ rev = bpbEXF;
+ goto out;
+ }
+
/* media descriptor check */
if ((sec[0x15] & 0xF0) != 0xF0)
goto out;
diff --git a/com32/chain/utility.h b/com32/chain/utility.h
index 8a08be71..596017bb 100644
--- a/com32/chain/utility.h
+++ b/com32/chain/utility.h
@@ -1,29 +1,74 @@
-#ifndef _COM32_CHAIN_UTILITY_H
-#define _COM32_CHAIN_UTILITY_H
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010-2012 Michal Soltys
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_UTILITY_H
+#define COM32_CHAIN_UTILITY_H
#include <stdint.h>
+#include <stdio.h>
#include <syslinux/disk.h>
+#include <syslinux/movebits.h>
-#define bpbUNK 0
-#define bpbV20 1
-#define bpbV30 2
-#define bpbV32 3
-#define bpbV34 4
-#define bpbV40 5
-#define bpbVNT 6
-#define bpbV70 7
+/* most (all ?) bpb "types" known to humankind as of 2012 */
+enum {bpbUNK, bpbV20, bpbV30, bpbV32, bpbV34, bpbV40, bpbVNT, bpbV70, bpbEXF};
-#define l2c_cnul 0
-#define l2c_cadd 1
-#define l2c_cmax 2
+/* see utility.c for details */
+enum {L2C_CNUL, L2C_CADD, L2C_CMAX};
+
+/* first usable and first unusable offsets */
+#define dosmin ((addr_t)0x500u)
+#define dosmax ((addr_t)(*(uint16_t *) 0x413 << 10))
-void error(const char *msg);
-int guid_is0(const struct guid *guid);
void wait_key(void);
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode);
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode);
uint32_t get_file_lba(const char *filename);
-int drvoff_detect(int type, unsigned int *off);
+int drvoff_detect(int type);
int bpb_detect(const uint8_t *bpb, const char *tag);
+int guid_is0(const struct guid *guid);
+
+static inline int warn(const char *x)
+{
+ return fprintf(stderr, "WARN: %s\n", x);
+}
+
+static inline int error(const char *x)
+{
+ return fprintf(stderr, "ERR: %s\n", x);
+}
+
+static inline int crit(const char *x)
+{
+ return fprintf(stderr, "CRIT: %s @%s:%d\n", x, __FILE__, __LINE__);
+}
+
+#define critm() crit("Malloc failure.")
#endif
diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c
index ff19c530..27d4618c 100644
--- a/com32/elflink/ldlinux/chainboot.c
+++ b/com32/elflink/ldlinux/chainboot.c
@@ -15,6 +15,7 @@
* is BIOS-specific.
*/
+#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -53,7 +54,7 @@ void chainboot_file(const char *file, uint32_t type)
if (!buf)
goto bail;
- rv = open_file(file, &fd);
+ rv = open_file(file, O_RDONLY, &fd);
if (rv == -1)
goto bail;
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 5c53b995..bf0bd8ce 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -46,16 +46,21 @@ const struct image_types image_boot_types[] = {
extern int create_args_and_load(char *);
-__export void execute(const char *cmdline, uint32_t type)
+__export void execute(const char *cmdline, uint32_t type, bool sysappend)
{
const char *kernel, *args;
const char *p;
com32sys_t ireg;
- char *q;
+ char *q, ch;
memset(&ireg, 0, sizeof ireg);
- q = malloc(strlen(cmdline) + 2);
+ if (strlen(cmdline) >= MAX_CMDLINE_LEN) {
+ printf("cmdline too long\n");
+ return;
+ }
+
+ q = malloc(MAX_CMDLINE_LEN);
if (!q) {
printf("%s(): Fail to malloc a buffer to exec %s\n",
__func__, cmdline);
@@ -72,7 +77,17 @@ __export void execute(const char *cmdline, uint32_t type)
while (*p && my_isspace(*p))
p++;
- strcpy(q, p);
+ do {
+ *q++ = ch = *p++;
+ } while (ch);
+
+ if (sysappend) {
+ /* If we've seen some args, insert a space */
+ if (--q != args)
+ *q++ = ' ';
+
+ do_sysappend(q);
+ }
dprintf("kernel is %s, args = %s type = %d \n", kernel, args, type);
@@ -86,13 +101,14 @@ __export void execute(const char *cmdline, uint32_t type)
* filename extension if COM32 and
* retry.
*/
+ p = args;
if (t->type == IMAGE_TYPE_COM32) {
p = apply_extension(p, ".c32");
if (!p)
return;
}
- execute(p, t->type);
+ execute(p, t->type, sysappend);
return;
}
}
@@ -122,17 +138,23 @@ __export void execute(const char *cmdline, uint32_t type)
ldlinux_enter_command();
} else if (type == IMAGE_TYPE_CONFIG) {
- char *argv[] = { "ldlinux.c32", NULL };
+ char *argv[] = { "ldlinux.c32", NULL, NULL };
+ char *config;
int rv;
/* kernel contains the config file name */
- realpath(ConfigName, kernel, FILENAME_MAX);
+ config = malloc(FILENAME_MAX);
+ if (!config)
+ goto out;
+
+ realpath(config, kernel, FILENAME_MAX);
/* If we got anything on the command line, do a chdir */
if (*args)
mangle_name(config_cwd, args);
- rv = start_ldlinux(argv);
+ argv[1] = config;
+ rv = start_ldlinux(2, argv);
printf("Failed to exec ldlinux.c32: %s\n", strerror(rv));
} else if (type == IMAGE_TYPE_LOCALBOOT) {
local_boot(strtoul(kernel, NULL, 0));
@@ -142,9 +164,10 @@ __export void execute(const char *cmdline, uint32_t type)
} else {
/* Need add one item for kernel load, as we don't use
* the assembly runkernel.inc any more */
- new_linux_kernel((char *)kernel, (char *)cmdline);
+ new_linux_kernel((char *)kernel, (char *)args);
}
+out:
free((void *)kernel);
/* If this returns, something went bad; return to menu */
diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c
index 920246fc..f3ba37fa 100644
--- a/com32/elflink/ldlinux/kernel.c
+++ b/com32/elflink/ldlinux/kernel.c
@@ -35,14 +35,10 @@ int new_linux_kernel(char *okernel, char *ocmdline)
else if (append)
args = append;
- cmdline_len = strlen(kernel_name);
- if (args) {
- /* +1 for the space (' ') between kernel and args */
- cmdline_len += strlen(args) + 1;
- }
-
- /* +1 for NUL termination */
- cmdline_len++;
+ cmdline_len = strlen("BOOT_IMAGE=") + strlen(kernel_name);
+ cmdline_len += 1; /* space between BOOT_IMAGE and args */
+ cmdline_len += strlen(args);
+ cmdline_len += 1; /* NUL-termination */
cmdline = malloc(cmdline_len);
if (!cmdline) {
@@ -50,10 +46,7 @@ int new_linux_kernel(char *okernel, char *ocmdline)
return 1;
}
- if (args)
- snprintf(cmdline, cmdline_len, "%s %s", kernel_name, args);
- else
- snprintf(cmdline, cmdline_len, "%s", kernel_name);
+ sprintf(cmdline, "BOOT_IMAGE=%s %s", kernel_name, args);
/* "keeppxe" handling */
#if IS_PXELINUX
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index a8b1b386..76d117c7 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -154,9 +154,29 @@ __export void load_kernel(const char *command_line)
/* Virtual kernel? */
me = find_label(kernel);
if (me) {
- type = parse_image_type(me->cmdline);
+ const char *args;
+ char *cmd;
+ size_t len = strlen(me->cmdline) + 1;
- execute(me->cmdline, type);
+ /* Find the end of the command */
+ args = find_command(kernel);
+ while(*args && my_isspace(*args))
+ args++;
+
+ if (strlen(args))
+ len += strlen(args) + 1; /* +1 for space (' ') */
+
+ cmd = malloc(len);
+ if (!cmd)
+ goto bad_kernel;
+
+ if (strlen(args))
+ snprintf(cmd, len, "%s %s", me->cmdline, args);
+ else
+ strncpy(cmd, me->cmdline, len);
+
+ type = parse_image_type(cmd);
+ execute(cmd, type, false);
/* We shouldn't return */
goto bad_kernel;
}
@@ -193,7 +213,7 @@ __export void load_kernel(const char *command_line)
}
}
- execute(kernel, type);
+ execute(kernel, type, true);
free((void *)kernel);
bad_implicit:
@@ -210,7 +230,7 @@ bad_kernel:
rsprintf(&cmdline, "%s %s", onerror, default_cmd);
type = parse_image_type(cmdline);
- execute(cmdline, type);
+ execute(cmdline, type, true);
}
}
@@ -277,19 +297,15 @@ void ldlinux_console_init(void)
openconsole(&dev_stdcon_r, &dev_ansiserial_w);
}
-__export int main(int argc __unused, char **argv __unused)
+__export int main(int argc __unused, char **argv)
{
const void *adv;
const char *cmdline;
size_t count = 0;
- char *config_argv[2] = { NULL, NULL };
ldlinux_console_init();
- if (ConfigName[0])
- config_argv[0] = ConfigName;
-
- parse_configs(config_argv);
+ parse_configs(&argv[1]);
__syslinux_set_serial_console_info();
diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
index a2421e95..9d50c2f3 100644
--- a/com32/elflink/ldlinux/readconfig.c
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -29,6 +29,7 @@
#include <bios.h>
#include <core.h>
#include <fs.h>
+#include <syslinux/pxe_api.h>
#include "menu.h"
#include "config.h"
@@ -318,6 +319,31 @@ static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
}
}
+/*
+ * Copy a string, converting whitespace characters to underscores
+ * and compacting them. Return a pointer to the final null.
+ */
+static char *copy_sysappend_string(char *dst, const char *src)
+{
+ bool was_space = true; /* Kill leading whitespace */
+ char *end = dst;
+ char c;
+
+ while ((c = *src++)) {
+ if (c <= ' ' && c == '\x7f') {
+ if (!was_space)
+ *dst++ = '_';
+ was_space = true;
+ } else {
+ *dst++ = c;
+ end = dst;
+ was_space = false;
+ }
+ }
+ *end = '\0';
+ return end;
+}
+
static void record(struct menu *m, struct labeldata *ld, const char *append)
{
int i;
@@ -381,8 +407,11 @@ static void record(struct menu *m, struct labeldata *ld, const char *append)
if (ld->ipappend) {
ipappend = syslinux_ipappend_strings();
for (i = 0; i < ipappend->count; i++) {
- if ((ld->ipappend & (1U << i)) && ipappend->ptr[i])
- ipp += sprintf(ipp, " %s", ipappend->ptr[i]);
+ if ((ld->ipappend & (1U << i)) &&
+ ipappend->ptr[i] && ipappend->ptr[i][0]) {
+ *ipp++ = ' ';
+ ipp = copy_sysappend_string(ipp, ipappend->ptr[i]);
+ }
}
}
@@ -444,6 +473,9 @@ void print_labels(const char *prefix, size_t len)
printf("\n");
for (me = all_entries; me; me = me->next ) {
+ if (!me->label)
+ continue;
+
if (!strncmp(prefix, me->label, len))
printf(" %s", me->label);
}
@@ -605,8 +637,6 @@ uint32_t parse_argb(char **p)
*/
//static const char *append = NULL;
extern const char *append;
-//static unsigned int ipappend = 0;
-__export unsigned int ipappend = 0;
extern uint16_t PXERetry;
static struct labeldata ld;
@@ -1074,7 +1104,7 @@ do_include:
ld.initrd = NULL;
ld.menulabel = NULL;
ld.helptext = NULL;
- ld.ipappend = ipappend;
+ ld.ipappend = SysAppends;
ld.menudefault = ld.menuhide = ld.menuseparator =
ld.menudisabled = ld.menuindent = 0;
} else if ((ep = is_kernel_type(p, &type))) {
@@ -1093,11 +1123,13 @@ do_include:
ontimeoutlen = strlen(ontimeout);
} else if (looking_at(p, "allowoptions")) {
allowoptions = !!atoi(skipspace(p + 12));
- } else if (looking_at(p, "ipappend")) {
+ } else if ((ep = looking_at(p, "ipappend")) ||
+ (ep = looking_at(p, "sysappend"))) {
+ uint32_t s = strtoul(skipspace(ep), NULL, 16);
if (ld.label)
- ld.ipappend = atoi(skipspace(p + 8));
+ ld.ipappend = s;
else
- ipappend = atoi(skipspace(p + 8));
+ SysAppends = s;
} else if (looking_at(p, "default")) {
/* default could be a kernel image or another label */
refstr_put(globaldefault);
@@ -1333,6 +1365,16 @@ do_include:
PATH = _p;
} else
printf("Failed to realloc PATH\n");
+ } else if (looking_at(p, "sendcookies")) {
+ const union syslinux_derivative_info *sdi;
+
+ p += strlen("sendcookies");
+ sdi = syslinux_derivative_info();
+
+ if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
+ SendCookies = strtoul(skipspace(p), NULL, 10);
+ http_bake_cookies();
+ }
}
}
}
@@ -1360,6 +1402,15 @@ static int parse_one_config(const char *filename)
f = fdopen(fd, mode);
parse_config_file(f);
+ /*
+ * Update ConfigName so that syslinux_config_file() returns
+ * the filename we just opened. filesystem-specific
+ * open_config() implementations are expected to update
+ * ConfigName themselves.
+ */
+ if (filename)
+ strcpy(ConfigName, filename);
+
return 0;
}
diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c
index aa05caf8..9c07d263 100644
--- a/com32/gfxboot/gfxboot.c
+++ b/com32/gfxboot/gfxboot.c
@@ -393,7 +393,7 @@ int read_config_file(const char *filename)
continue;
}
- if(!strcasecmp(s, "ipappend")) {
+ if(!strcasecmp(s, "ipappend") || !strcasecmp(s, "sysappend")) {
(menu_ptr ?: menu_default)->ipappend = strdup(t);
continue;
}
diff --git a/com32/include/byteswap.h b/com32/include/byteswap.h
new file mode 100644
index 00000000..d1a4d543
--- /dev/null
+++ b/com32/include/byteswap.h
@@ -0,0 +1,58 @@
+#ifndef _BYTESWAP_H
+#define _BYTESWAP_H
+
+/* COM32 will be running on an i386 platform */
+
+#include <stdint.h>
+#include <klibc/compiler.h>
+
+#define __bswap_16_macro(v) ((uint16_t) \
+ (((uint16_t)(v) << 8) | \
+ ((uint16_t)(v) >> 8)))
+
+static inline __constfunc uint16_t __bswap_16(uint16_t v)
+{
+ return __bswap_16_macro(v);
+}
+
+#define bswap_16(x) (__builtin_constant_p(x) ? \
+ __bswap_16_macro(x) : __bswap_16(x))
+
+#define __bswap_32_macro(v) ((uint32_t) \
+ ((((uint32_t)(v) & 0x000000ff) << 24) | \
+ (((uint32_t)(v) & 0x0000ff00) << 8) | \
+ (((uint32_t)(v) & 0x00ff0000) >> 8) | \
+ (((uint32_t)(v) & 0xff000000) >> 24)))
+
+static inline __constfunc uint32_t __bswap_32(uint32_t v)
+{
+#if __SIZEOF_POINTER__ == 4
+ asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
+ : "+q" (v));
+#elif __SIZEOF_POINTER__ == 8
+ asm("bswap %0"
+ : "=r" (v)
+ : "0" (v));
+#else
+#error "unable to build for architecture"
+#endif
+ return v;
+}
+
+#define bswap_32(x) (__builtin_constant_p(x) ? \
+ __bswap_32_macro(x) : __bswap_32(x))
+
+
+#define __bswap_64_macro(v) ((uint64_t) \
+ (((uint64_t)__bswap_32_macro((uint32_t)(v)) << 32) | \
+ (__bswap_32__macro((uint32_t)((uint64_t)(v) >> 32)))))
+
+static inline __constfunc uint64_t __bswap_64(uint64_t v)
+{
+ return ((uint64_t)__bswap_32(v) << 32) | __bswap_32(v >> 32);
+}
+
+#define bswap_64(x) (__builtin_constant_p(x) ? \
+ __bswap_64_macro(x) : __bswap_64(x))
+
+#endif /* byteswap.h */
diff --git a/com32/include/com32.h b/com32/include/com32.h
index c5d60176..adef7126 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -206,4 +206,6 @@ static inline far_ptr_t FAR_PTR(void *__ptr)
return __fptr;
}
+extern const char *com32_cmdline(void);
+
#endif /* _COM32_H */
diff --git a/com32/include/errno.h b/com32/include/errno.h
index 36690bf6..40bf2ecc 100644
--- a/com32/include/errno.h
+++ b/com32/include/errno.h
@@ -131,4 +131,25 @@ extern int errno;
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
+/* lwIP nameserver query return codes */
+#define ENSROK 0 /* DNS server returned answer with no data */
+#define ENSRNODATA 160 /* DNS server returned answer with no data */
+#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
+#define ENSRSERVFAIL 162 /* DNS server returned general failure */
+#define ENSRNOTFOUND 163 /* Domain name not found */
+#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
+#define ENSRREFUSED 165 /* DNS server refused query */
+#define ENSRBADQUERY 166 /* Misformatted DNS query */
+#define ENSRBADNAME 167 /* Misformatted domain name */
+#define ENSRBADFAMILY 168 /* Unsupported address family */
+#define ENSRBADRESP 169 /* Misformatted DNS reply */
+#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
+#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
+#define ENSROF 172 /* End of file */
+#define ENSRFILE 173 /* Error reading file */
+#define ENSRNOMEM 174 /* Out of memory */
+#define ENSRDESTRUCTION 175 /* Application terminated lookup */
+#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
+#define ENSRCNAMELOOP 177 /* Domain name is too long */
+
#endif /* _ERRNO_H */
diff --git a/com32/include/fcntl.h b/com32/include/fcntl.h
index b691b5cd..c8a9cb52 100644
--- a/com32/include/fcntl.h
+++ b/com32/include/fcntl.h
@@ -14,6 +14,7 @@
#define O_RDONLY 1
#define O_WRONLY 2
#define O_RDWR 3
+#define O_DIRECTORY 010
#define O_CREAT 0100
#define O_EXCL 0200
#define O_TRUNC 01000
diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h
index afe89808..157ded10 100644
--- a/com32/include/linux/list.h
+++ b/com32/include/linux/list.h
@@ -35,18 +35,6 @@ static inline void INIT_LIST_HEAD(struct list_head *list)
list->prev = list;
}
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-
/*
* Insert a new entry between two known consecutive entries.
*
diff --git a/com32/include/netinet/in.h b/com32/include/netinet/in.h
index d3fba17f..b24f8046 100644
--- a/com32/include/netinet/in.h
+++ b/com32/include/netinet/in.h
@@ -3,57 +3,17 @@
/* COM32 will be running on an i386 platform */
-#include <stdint.h>
#include <klibc/compiler.h>
#include <klibc/extern.h>
-
-#define __htons_macro(v) ((uint16_t) \
- (((uint16_t)(v) << 8) | \
- ((uint16_t)(v) >> 8)))
-
-static inline __constfunc uint16_t __htons(uint16_t v)
-{
- return __htons_macro(v);
-}
-
-#define htons(x) (__builtin_constant_p(x) ? __htons_macro(x) : __htons(x))
-#define ntohs(x) htons(x)
-
-#define __htonl_macro(v) ((uint32_t) \
- ((((uint32_t)(v) & 0x000000ff) << 24) | \
- (((uint32_t)(v) & 0x0000ff00) << 8) | \
- (((uint32_t)(v) & 0x00ff0000) >> 8) | \
- (((uint32_t)(v) & 0xff000000) >> 24)))
-
-static inline __constfunc uint32_t __htonl(uint32_t v)
-{
-#if __SIZEOF_POINTER__ == 4
- asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
- : "+q" (v));
-#elif __SIZEOF_POINTER__ == 8
- asm("bswap %0"
- : "=r" (v)
- : "0" (v));
-#else
-#error "unable to build for architecture"
-#endif
- return v;
-}
-
-#define htonl(x) (__builtin_constant_p(x) ? __htonl_macro(x) : __htonl(x))
-#define ntohl(x) htonl(x)
-
-#define __htonq_macro(v) ((uint64_t) \
- (((uint64_t)__htonl_macro((uint32_t)(v)) << 32) | \
- (__htonl_macro((uint32_t)((uint64_t)(v) >> 32)))))
-
-static inline __constfunc uint64_t __htonq(uint64_t v)
-{
- return ((uint64_t)__htonl(v) << 32) | __htonl(v >> 32);
-}
-
-#define htonq(x) (__builtin_constant_p(x) ? __htonq_macro(x) : __htonq(x))
-#define ntohq(x) htonq(x)
+#include <stdint.h>
+#include <byteswap.h>
+
+#define htons(x) bswap_16(x)
+#define ntohs(x) bswap_16(x)
+#define htonl(x) bswap_32(x)
+#define ntohl(x) bswap_32(x)
+#define htonq(x) bswap_64(x)
+#define ntohq(x) bswap_64(x)
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;
diff --git a/com32/include/stddef.h b/com32/include/stddef.h
index 125d2352..f52d62f3 100644
--- a/com32/include/stddef.h
+++ b/com32/include/stddef.h
@@ -21,4 +21,12 @@
#undef offsetof
#define offsetof(t,m) ((size_t)&((t *)0)->m)
+#undef container_of
+/*
+ * The container_of construct: if p is a pointer to member m of
+ * container class c, then return a pointer to the container of which
+ * *p is a member.
+ */
+#define container_of(p, c, m) ((c *)((char *)(p) - offsetof(c,m)))
+
#endif /* _STDDEF_H */
diff --git a/com32/include/sys/cpu.h b/com32/include/sys/cpu.h
index 05c98843..76c45da0 100644
--- a/com32/include/sys/cpu.h
+++ b/com32/include/sys/cpu.h
@@ -13,4 +13,45 @@
#error "unsupported architecture"
#endif
+typedef unsigned long irq_state_t;
+
+static inline irq_state_t irq_state(void)
+{
+ irq_state_t __st;
+
+ asm volatile("pushf ; pop %0" : "=rm" (__st) : : "memory");
+ return __st;
+}
+
+static inline irq_state_t irq_save(void)
+{
+ irq_state_t __st = irq_state();
+ cli();
+ return __st;
+}
+
+static inline void irq_restore(irq_state_t __st)
+{
+ asm volatile("push %0 ; popf" : : "rm" (__st) : "memory");
+}
+
+/* Standard macro to see if a specific flag is changeable */
+static inline __constfunc bool cpu_has_eflag(unsigned long flag)
+{
+ unsigned long f0, f1;
+ asm("pushf ; "
+ "pushf ; "
+ "pop %0 ; "
+ "mov %0,%1 ; "
+ "xor %2,%1 ; "
+ "push %1 ; "
+ "popf ; "
+ "pushf ; "
+ "pop %1 ; "
+ "popf"
+ : "=&r" (f0), "=&r" (f1)
+ : "ri" (flag));
+ return !!((f0^f1) & flag);
+}
+
#endif
diff --git a/com32/include/sys/i386/cpu.h b/com32/include/sys/i386/cpu.h
index 63d0f5ed..a0cedf20 100644
--- a/com32/include/sys/i386/cpu.h
+++ b/com32/include/sys/i386/cpu.h
@@ -80,27 +80,6 @@ static inline __constfunc uint32_t cpuid_edx(uint32_t level)
return v;
}
-/* Standard macro to see if a specific flag is changeable */
-static inline __constfunc bool cpu_has_eflag(uint32_t flag)
-{
- uint32_t f0, f1;
-
- asm("pushfl ; "
- "pushfl ; "
- "popl %0 ; "
- "movl %0,%1 ; "
- "xorl %2,%1 ; "
- "pushl %1 ; "
- "popfl ; "
- "pushfl ; "
- "popl %1 ; "
- "popfl"
- : "=&r" (f0), "=&r" (f1)
- : "ri" (flag));
-
- return !!((f0^f1) & flag);
-}
-
static inline uint64_t rdmsr(uint32_t msr)
{
uint64_t v;
@@ -116,20 +95,20 @@ static inline void wrmsr(uint64_t v, uint32_t msr)
static inline void cpu_relax(void)
{
- asm volatile("rep ; nop");
+ asm volatile("rep ; nop" : : : "memory");
}
static inline void hlt(void)
{
- asm volatile("hlt");
+ asm volatile("hlt" : : : "memory");
}
static inline void cli(void)
{
- asm volatile("cli");
+ asm volatile("cli" : : : "memory");
}
static inline void sti(void)
{
- asm volatile("sti");
+ asm volatile("sti" : : : "memory");
}
diff --git a/com32/include/sys/x86_64/cpu.h b/com32/include/sys/x86_64/cpu.h
index 89d79154..cbe968f5 100644
--- a/com32/include/sys/x86_64/cpu.h
+++ b/com32/include/sys/x86_64/cpu.h
@@ -93,26 +93,6 @@ static inline void cpuid_count(uint32_t op, uint32_t cnt,
: "a"(op), "c"(cnt));
}
-/* Standard macro to see if a specific flag is changeable */
-static inline __constfunc bool cpu_has_eflag(uint32_t flag)
-{
- /* x86_64 */
- uint64_t f0, f1;
- asm("pushf ; "
- "pushf ; "
- "pop %0 ; "
- "mov %0,%1 ; "
- "xor %2,%1 ; "
- "push %1 ; "
- "popf ; "
- "pushf ; "
- "pop %1 ; "
- "popf"
- : "=&r" (f0), "=&r" (f1)
- : "ri" (flag));
- return !!((f0^f1) & flag);
-}
-
static inline uint64_t rdmsr(uint32_t msr)
{
uint64_t v;
@@ -128,21 +108,21 @@ static inline void wrmsr(uint64_t v, uint32_t msr)
static inline void cpu_relax(void)
{
- asm volatile("rep ; nop");
+ asm volatile("rep ; nop" : : : "memory");
}
static inline void hlt(void)
{
- asm volatile("hlt");
+ asm volatile("hlt" : : : "memory");
}
static inline void cli(void)
{
- asm volatile("cli");
+ asm volatile("cli" : : : "memory");
}
static inline void sti(void)
{
- asm volatile("sti");
+ asm volatile("sti" : : : "memory");
}
#endif
diff --git a/com32/include/syslinux/config.h b/com32/include/syslinux/config.h
index 8f4124ce..235f288d 100644
--- a/com32/include/syslinux/config.h
+++ b/com32/include/syslinux/config.h
@@ -39,7 +39,7 @@
#include <com32.h>
enum syslinux_filesystem {
- SYSLINUX_FS_UNKNOWN = 0x30,
+ SYSLINUX_FS_UNKNOWN = 0x30,
SYSLINUX_FS_SYSLINUX = 0x31,
SYSLINUX_FS_PXELINUX = 0x32,
SYSLINUX_FS_ISOLINUX = 0x33,
diff --git a/com32/include/syslinux/pmapi.h b/com32/include/syslinux/pmapi.h
index fa390185..14a2c326 100644
--- a/com32/include/syslinux/pmapi.h
+++ b/com32/include/syslinux/pmapi.h
@@ -57,7 +57,7 @@ struct com32_pmapi {
void *(*lmalloc)(size_t);
void (*lfree)(void *);
- int (*open_file)(const char *, struct com32_filedata *);
+ int (*open_file)(const char *, int, struct com32_filedata *);
size_t (*read_file)(uint16_t *, void *, size_t);
void (*close_file)(uint16_t);
@@ -74,6 +74,9 @@ struct com32_pmapi {
/* Should be "const volatile", but gcc miscompiles that sometimes */
volatile uint32_t *jiffies;
volatile uint32_t *ms_timer;
+
+ const int sysappend_count;
+ const char * const *sysappend_strings;
};
#endif /* _SYSLINUX_PMAPI_H */
diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h
index 203ab38f..e9baa48c 100644
--- a/com32/include/syslinux/pxe_api.h
+++ b/com32/include/syslinux/pxe_api.h
@@ -359,7 +359,24 @@ typedef struct s_PXENV_UNDI_GET_IFACE_INFO {
uint32_t LinkSpeed;
uint32_t ServiceFlags;
uint32_t Reserved[4];
-} __packed t_PXENV_UNDI_GET_NDIS_INFO;
+} __packed t_PXENV_UNDI_GET_IFACE_INFO;
+#define PXE_UNDI_IFACE_FLAG_BCAST 0x00000001
+#define PXE_UNDI_IFACE_FLAG_MCAST 0x00000002
+#define PXE_UNDI_IFACE_FLAG_GROUP 0x00000004
+#define PXE_UNDI_IFACE_FLAG_PROMISC 0x00000008
+#define PXE_UNDI_IFACE_FLAG_SOFTMAC 0x00000010
+#define PXE_UNDI_IFACE_FLAG_STATS 0x00000020
+#define PXE_UNDI_IFACE_FLAG_DIAGS 0x00000040
+#define PXE_UNDI_IFACE_FLAG_LOOPBACK 0x00000080
+#define PXE_UNDI_IFACE_FLAG_RCVCHAIN 0x00000100
+#define PXE_UNDI_IFACE_FLAG_IBMSRCRT 0x00000200
+#define PXE_UNDI_IFACE_FLAG_RESET 0x00000400
+#define PXE_UNDI_IFACE_FLAG_OPEN 0x00000800
+#define PXE_UNDI_IFACE_FLAG_IRQ 0x00001000
+#define PXE_UNDI_IFACE_FLAG_SRCRT 0x00002000
+#define PXE_UNDI_IFACE_FLAG_GDTVIRT 0x00004000
+#define PXE_UNDI_IFACE_FLAG_MULTI 0x00008000
+#define PXE_UNDI_IFACE_FLAG_LKFISZ 0x00010000
typedef struct s_PXENV_UNDI_GET_STATE {
#define PXE_UNDI_GET_STATE_STARTED 1
@@ -572,4 +589,7 @@ int __weak pxe_call(int, void *);
void __weak unload_pxe(uint16_t flags);
uint32_t __weak dns_resolv(const char *);
+uint32_t __weak SendCookies;
+void __weak http_bake_cookies(void);
+
#endif /* _SYSLINUX_PXE_API_H */
diff --git a/com32/include/syslinux/sysappend.h b/com32/include/syslinux/sysappend.h
new file mode 100644
index 00000000..f243eabc
--- /dev/null
+++ b/com32/include/syslinux/sysappend.h
@@ -0,0 +1,59 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/sysappend.h
+ *
+ * List of the Syslinux sysappend strings
+ */
+
+#ifndef _SYSLINUX_SYSAPPEND_H
+#define _SYSLINUX_SYSAPPEND_H
+
+enum syslinux_sysappend {
+ SYSAPPEND_IP, /* PXELINUX: ip= address */
+ SYSAPPEND_BOOTIF, /* PXELINUX: BOOTIF= address */
+ SYSAPPEND_SYSUUID, /* System UUID from PXE or DMI */
+ SYSAPPEND_CPU, /* CPU features */
+ SYSAPPEND_SYSVENDOR, /* System or MB vendor from DMI */
+ SYSAPPEND_SYSPRODUCT, /* System or MB product from DMI */
+ SYSAPPEND_SYSVERSION, /* System or MB version from DMI */
+ SYSAPPEND_SYSSERIAL, /* System or MB serial from DMI */
+ SYSAPPEND_SYSSKU, /* System SKU from DMI */
+ SYSAPPEND_SYSFAMILY, /* System family from DMI */
+ SYSAPPEND_MBVENDOR, /* System or MB vendor from DMI */
+ SYSAPPEND_MBPRODUCT, /* System or MB product from DMI */
+ SYSAPPEND_MBVERSION, /* System or MB version from DMI */
+ SYSAPPEND_MBSERIAL, /* System or MB serial from DMI */
+ SYSAPPEND_MBASSET, /* MB asset tag from DMI */
+ SYSAPPEND_BIOSVENDOR, /* BIOS vendor */
+ SYSAPPEND_BIOSVERSION, /* BIOS version string */
+ SYSAPPEND_SYSFF, /* System form factor */
+ SYSAPPEND_MAX /* Total number of strings */
+};
+
+#endif
diff --git a/com32/lib/errno.c b/com32/lib/errno.c
deleted file mode 100644
index f280e309..00000000
--- a/com32/lib/errno.c
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * errno.c
- *
- */
-#include <errno.h>
-
-int errno;
diff --git a/com32/lib/sys/file.h b/com32/lib/sys/file.h
index 4cd19464..f79b4f19 100644
--- a/com32/lib/sys/file.h
+++ b/com32/lib/sys/file.h
@@ -74,7 +74,7 @@ struct output_dev {
/* File structure */
-#define NFILES 32 /* Number of files to support */
+#define NFILES 128 /* Number of files to support */
#define MAXBLOCK 16384 /* Defined by ABI */
struct file_info {
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
index 3221bb60..1ed5bb4c 100644
--- a/com32/lib/sys/open.c
+++ b/com32/lib/sys/open.c
@@ -65,7 +65,7 @@ int open(const char *pathname, int flags, ...)
fp = &__file_info[fd];
- handle = open_file(pathname, &fp->i.fd);
+ handle = open_file(pathname, flags, &fp->i.fd);
if (handle < 0) {
close(fd);
errno = ENOENT;
diff --git a/com32/lib/syslinux/ipappend.c b/com32/lib/syslinux/ipappend.c
index 3eda48cf..11eb1bf5 100644
--- a/com32/lib/syslinux/ipappend.c
+++ b/com32/lib/syslinux/ipappend.c
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2011 Intel Corporation; author: H. Peter Anvin
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -31,20 +32,16 @@
* Get ipappend strings
*/
+#include <syslinux/sysappend.h>
#include <syslinux/config.h>
+#include <syslinux/pmapi.h>
#include <klibc/compiler.h>
#include <core.h>
struct syslinux_ipappend_strings __syslinux_ipappend_strings;
-static const char *syslinux_ipappend_string_list[32];
void __constructor __syslinux_get_ipappend_strings(void)
{
- unsigned int i;
-
- __syslinux_ipappend_strings.count = (size_t)numIPAppends;
- __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list;
-
- for (i = 0; i < (size_t)numIPAppends; i++)
- syslinux_ipappend_string_list[i] = (const char *)(size_t)IPAppends[i];
+ __syslinux_ipappend_strings.count = SYSAPPEND_MAX,
+ __syslinux_ipappend_strings.ptr = sysappend_strings;
}
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index 4a8a1fd3..ea5033e1 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-2013 Intel Corporation; author: H. Peter Anvin
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -232,7 +232,10 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024)
goto bail; /* Kernel cannot be loaded low */
- if (initramfs && hdr.version < 0x0200)
+ /* Get the size of the initramfs, if there is one */
+ irf_size = initramfs_size(initramfs);
+
+ if (irf_size && hdr.version < 0x0200)
goto bail; /* initrd/initramfs not supported */
if (hdr.version >= 0x0200) {
@@ -241,14 +244,6 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
whdr->heap_end_ptr = cmdline_offset - 0x0200;
whdr->loadflags |= CAN_USE_HEAP;
}
- if (hdr.version >= 0x0202) {
- whdr->cmd_line_ptr = real_mode_base + cmdline_offset;
- } else {
- whdr->old_cmd_line_magic = OLD_CMDLINE_MAGIC;
- whdr->old_cmd_line_offset = cmdline_offset;
- /* Be paranoid and round up to a multiple of 16 */
- whdr->setup_move_size = (cmdline_offset + cmdline_size + 15) & ~15;
- }
}
/* Get the memory map */
@@ -337,6 +332,9 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
break;
}
}
+
+ if (!ok)
+ goto bail;
}
if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t) kernel_buf,
@@ -355,6 +353,16 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
if (syslinux_add_movelist(&fraglist, real_mode_base + cmdline_offset,
(addr_t) cmdline, cmdline_size))
goto bail;
+ if (hdr.version >= 0x0202) {
+ whdr->cmd_line_ptr = real_mode_base + cmdline_offset;
+ } else {
+ whdr->old_cmd_line_magic = OLD_CMDLINE_MAGIC;
+ whdr->old_cmd_line_offset = cmdline_offset;
+ if (hdr.version >= 0x0200) {
+ /* Be paranoid and round up to a multiple of 16 */
+ whdr->setup_move_size = (cmdline_offset + cmdline_size + 15) & ~15;
+ }
+ }
/* Protected-mode code */
if (syslinux_add_movelist(&fraglist, prot_mode_base,
@@ -368,8 +376,6 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
We should put it at the highest possible address which is
<= hdr.initrd_addr_max, which fits the entire initramfs. */
- irf_size = initramfs_size(initramfs); /* Handles initramfs == NULL */
-
if (irf_size) {
addr_t best_addr = 0;
struct syslinux_memmap *ml;
diff --git a/com32/lib/syslinux/run_command.c b/com32/lib/syslinux/run_command.c
index 0efb61f2..7e4dc41b 100644
--- a/com32/lib/syslinux/run_command.c
+++ b/com32/lib/syslinux/run_command.c
@@ -37,7 +37,7 @@ int syslinux_run_command(const char *command)
if (!lm_command)
return -1;
- create_args_and_load(lm_command);
+ load_kernel(lm_command);
/* Should not return even on failure, but in case... */
lfree(lm_command);
diff --git a/com32/lib/syslinux/runimage.c b/com32/lib/syslinux/runimage.c
index d3db75f3..4dcd029d 100644
--- a/com32/lib/syslinux/runimage.c
+++ b/com32/lib/syslinux/runimage.c
@@ -37,8 +37,6 @@
#include <syslinux/config.h>
#include <core.h>
-extern unsigned int ipappend;
-
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type)
{
@@ -56,8 +54,6 @@ void syslinux_run_kernel_image(const char *filename, const char *cmdline,
if (rv == -1 || (size_t)rv >= len)
return;
- if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
- ipappend = ipappend_flags;
-
- execute(bbcmdline, type);
+ SysAppends = ipappend_flags;
+ execute(bbcmdline, type, true);
}
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index d014340c..ce85a5c4 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -135,7 +135,7 @@ int syslinux_do_shuffle(struct syslinux_movelist *fraglist,
goto bail;
#if DEBUG > 1
- syslinux_dump_movelist(stdout, fraglist);
+ syslinux_dump_movelist(fraglist);
#endif
if (syslinux_compute_movelist(&moves, fraglist, rxmap))
@@ -155,7 +155,7 @@ int syslinux_do_shuffle(struct syslinux_movelist *fraglist,
#if DEBUG > 1
dprintf("Final movelist:\n");
- syslinux_dump_movelist(stdout, moves);
+ syslinux_dump_movelist(moves);
#endif
syslinux_free_memmap(rxmap);
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index dc99da6e..a3061ede 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -1161,10 +1161,10 @@ int main(int argc, char *argv[])
if (cmdline) {
uint32_t type = parse_image_type(cmdline);
- execute(cmdline, type);
+ execute(cmdline, type, false);
if (cm->onerror) {
type = parse_image_type(cm->onerror);
- execute(cm->onerror, type);
+ execute(cm->onerror, type, true);
}
} else {
return 0; /* Exit */
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index dd6d5f91..7eaea280 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -288,6 +288,31 @@ static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
}
}
+/*
+ * Copy a string, converting whitespace characters to underscores
+ * and compacting them. Return a pointer to the final null.
+ */
+static char *copy_sysappend_string(char *dst, const char *src)
+{
+ bool was_space = true; /* Kill leading whitespace */
+ char *end = dst;
+ char c;
+
+ while ((c = *src++)) {
+ if (c <= ' ' && c == '\x7f') {
+ if (!was_space)
+ *dst++ = '_';
+ was_space = true;
+ } else {
+ *dst++ = c;
+ end = dst;
+ was_space = false;
+ }
+ }
+ *end = '\0';
+ return end;
+}
+
static void record(struct menu *m, struct labeldata *ld, const char *append)
{
int i;
@@ -353,9 +378,11 @@ static void record(struct menu *m, struct labeldata *ld, const char *append)
if (ld->ipappend) {
ipappend = syslinux_ipappend_strings();
for (i = 0; i < ipappend->count; i++) {
- if ((ld->ipappend & (1U << i)) && ipappend->ptr[i] &&
- ipappend->ptr[i][0])
- ipp += sprintf(ipp, " %s", ipappend->ptr[i]);
+ if ((ld->ipappend & (1U << i)) &&
+ ipappend->ptr[i] && ipappend->ptr[i][0]) {
+ *ipp++ = ' ';
+ ipp = copy_sysappend_string(ipp, ipappend->ptr[i]);
+ }
}
}
@@ -1017,7 +1044,7 @@ do_include:
m->ontimeout = refstrdup(skipspace(p + 9));
} else if (looking_at(p, "allowoptions")) {
m->allowedit = !!atoi(skipspace(p + 12));
- } else if (looking_at(p, "ipappend")) {
+ } else if (looking_at(p, "ipappend") || looking_at(p, "sysappend")) {
if (ld.label)
ld.ipappend = atoi(skipspace(p + 8));
else
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 8965f5f0..6e562b8c 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -24,7 +24,7 @@ MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \
ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \
whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32 \
- hexdump.c32
+ hexdump.c32 poweroff.c32 cptime.c32
TESTFILES =
diff --git a/com32/modules/cmd.c b/com32/modules/cmd.c
index 5d3f8918..233c7cac 100644
--- a/com32/modules/cmd.c
+++ b/com32/modules/cmd.c
@@ -21,6 +21,6 @@
int main(void)
{
- syslinux_run_command(__com32.cs_cmdline);
+ syslinux_run_command(com32_cmdline());
return -1;
}
diff --git a/com32/modules/cptime.c b/com32/modules/cptime.c
new file mode 100644
index 00000000..0f5ffe61
--- /dev/null
+++ b/com32/modules/cptime.c
@@ -0,0 +1,284 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010-2011 Gene Cumm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * cptime.c Version 1.4
+ *
+ * Timed copy; read entire file then output total time, bytes transferred,
+ * and compute transfer rate.
+ *
+ * cptime [-s|-l] [-v|-q] [-b _SIZE_] [-n _LEN_] _FILE_...
+ * -s Change to simple output mode without computing transfer rate
+ * -l Change to long output mode (to allow for overriding previous -s)
+ * -v Verbose output
+ * -q Quiet output
+ * -b _SIZE_ use _SIZE_ for transfer size
+ * -n _LEN_ maximum length to fetch
+ * _FILE_... Space delimited list of files to dump
+ * Note: The last instance of -s or -l wins, along with the last use of -b and -n and the winning option will be applied to all operations
+ *
+ * Hisory:
+ * 1.4 Use fread() rather than read(); use CLK_TCK when available.
+ * 1.3 Added -v/-q; rework some argument processing.
+ * 1.2 Added -n
+ * 1.1 Added -l and -b switches; more flexible command line processing
+ * 1.0 First release
+ */
+
+/*
+ * ToDos:
+ * - Refine timing to be more precise. Low priority.
+ * - Add -o for offset. Wishlist.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/times.h>
+#include <consoles.h>
+#include <minmax.h>
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+#include <console.h>
+
+#ifdef __COM32__
+# define BUFSZ_DEF (size_t)2048
+/* What's optimal? Under 4k?
+ * layout.inc: xfer_buf_seg equ 1000h
+ * com32.inc: push dword (1 << 16) ; 64K bounce buffer
+ */
+/* typedef size_t off_t */
+
+# define TPS_T float
+# ifdef CLK_TCK
+static inline TPS_T get_tps(void) { return CLK_TCK; }
+# else
+static inline TPS_T get_tps(void) { return 18.2; }
+# endif
+
+#else /* __COM32__ */
+
+# define BUFSZ_DEF (size_t)16384
+/* Need to check what might be a "best" buffer/fetch block size here */
+
+# define TPS_T long
+static inline TPS_T get_tps(void) { return sysconf(_SC_CLK_TCK); }
+
+#endif /* __COM32__ */
+
+#ifndef SSIZE_MAX
+# define SSIZE_MAX PTRDIFF_MAX
+#endif
+/* typedef ptrdiff_t ssize_t; */
+#define BUFSZ_MAX (size_t)SSIZE_MAX
+/* ssize_t max */
+#define BUFSZ_MIN (size_t)1
+
+
+/* Please note: I don't know the origin of these two macros nor their license */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+#define TYPE_MAX(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) -1 \
+ : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
+
+#ifndef OFF_T_MAX
+# define OFF_T_MAX TYPE_MAX(off_t)
+#endif
+/* Can't be SIZE_MAX or SSIZE_MAX as Syslinux/COM32 is unsigned while Linux
+ * is signed.
+ */
+
+#define LEN_MAX OFF_T_MAX
+/* off_t max */
+#define LEN_MIN (off_t)0
+
+void print_cp_result_tick(size_t bcnt, clock_t et, TPS_T tps, int offs)
+{
+ size_t dr;
+ /* prevent divide by 0 */
+ dr = max(bcnt, (bcnt * tps)) / max((clock_t)1, (et + offs));
+ printf(" %+d %zu B/s; %zu KiB/s; %zu MiB/s\n", offs, dr, dr/1024, dr/1048576);
+} /* void print_cp_result_tick(size_t bcnt, clock_t et, TPS_T tps, int offs) */
+
+void print_cp_result_long(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz, char do_verbose)
+{
+ TPS_T tps;
+ if (do_verbose > 2)
+ printf("Enter print_cp_result_long()\n");
+ tps = get_tps();
+ printf(" %zu B in %d ticks from '%s'\n", bcnt, (int)(ec - bc), fn);
+ printf(" ~%d ticks per second; %zu B block/transfer size\n", (int)tps, bufsz);
+ print_cp_result_tick(bcnt, (ec - bc), tps, 0);
+ print_cp_result_tick(bcnt, (ec - bc), tps, 1);
+ print_cp_result_tick(bcnt, (ec - bc), tps, -1);
+} /* void print_cp_result_long(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz) */
+
+void print_cp_result_simple(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz, char do_verbose)
+{
+ if (do_verbose) {}
+ printf(" %zuB %dt %zux '%s'\n", bcnt, (int)(ec - bc), bufsz, fn);
+} /* void print_cp_result_simple(char *fn, int bcnt, clock_t bc, clock_t ec, char do_verbose) */
+
+size_t time_copy_bufsz(size_t bufsz, size_t bcnt, off_t maxlen)
+{
+ return min(bufsz, (maxlen - bcnt));
+} /* size_t time_copy_bufsz(size_t bufsz, size_t bcnt, off_t maxlen) */
+
+int time_copy(char *fn, char do_simple, char do_verbose, size_t ibufsz, off_t maxlen)
+{
+// int fd;
+ int rv = 0;
+ int i = 0;
+ FILE *f;
+ size_t bufsz, bcnt = 0;
+ int numrd;
+ struct tms tm;
+ clock_t bc, ec;
+ char buf[ibufsz + 1];
+
+ buf[0] = 0;
+ if (do_verbose)
+ printf("Trying file '%s'\n", fn);
+ errno = 0;
+// fd = open(fn, O_RDONLY);
+ f = fopen(fn, "r");
+// if (fd == -1) {
+ if (!f) {
+ switch (errno) {
+ case ENOENT :
+ printf("File '%s' does not exist\n", fn);
+ break;
+ case EBADF:
+ printf("File '%s': Bad File Descriptor\n", fn);
+ break;
+ default :
+ printf("Error '%d' opening file '%s'\n", errno, fn);
+ }
+ rv = 1;
+ } else {
+ if (do_verbose)
+ printf("File '%s' opened\n", fn);
+ bufsz = time_copy_bufsz(ibufsz, bcnt, maxlen);
+ bc = times(&tm);
+// numrd = read(fd, buf, bufsz);
+// numrd = fread(buf, bufsz, 1, f);
+ numrd = fread(buf, 1, bufsz, f);
+ i++;
+ if (numrd > 0)
+ bcnt = numrd;
+ while ((numrd > 0) && (bufsz > 0)) {
+ bufsz = time_copy_bufsz(bufsz, bcnt, maxlen);
+// numrd = read(fd, buf, bufsz);
+// numrd = fread(buf, bufsz, 1, f);
+ numrd = fread(buf, 1, bufsz, f);
+ i++;
+ if (numrd >= 0)
+// bcnt = bcnt + numrd;
+ bcnt += numrd;
+ }
+ ec = times(&tm);
+// close(fd);
+ fclose(f);
+ if (do_verbose)
+ printf("File '%s' closed\n", fn);
+ if (numrd < 0) {
+ switch (errno) {
+ case EIO :
+ printf("IO Error at %zu B reading file '%s'\n", bcnt, fn);
+ break;
+ case EINVAL :
+ printf("Invalid Mode at %zu B reading file '%s'\n", bcnt, fn);
+ break;
+ default :
+ printf("Error '%d' at %zu B reading file '%s'\n", errno, bcnt, fn);
+ }
+ rv = 2;
+ }
+ if (bcnt > 0) {
+ if (bufsz == 0)
+ printf("maxed out on maxln\n");
+ if (do_simple)
+ print_cp_result_simple(fn, bcnt, bc, ec, ibufsz, do_verbose);
+ else
+ print_cp_result_long(fn, bcnt, bc, ec, ibufsz, do_verbose);
+ }
+ if (do_verbose)
+ printf(" numrd %d bcnt %d bufsz %d i %d\n", numrd, bcnt, bufsz, i);
+ }
+ return rv;
+} /* int time_copy(char *fn, char do_simple, int bufsz, off_t maxlen) */
+
+int main(int argc, char *argv[])
+{
+ int i;
+ char do_simple = 0, do_pbuf = 0, do_plen = 0, do_verbose = 0;
+ char *arg;
+ size_t tbufsz, bufsz = min((BUFSZ_DEF), (BUFSZ_MAX));
+ off_t tmaxlen, maxlen = LEN_MAX;
+ int numfl = 0;
+ console_ansi_std();
+// openconsole(&dev_stdcon_r, &dev_stdcon_w);
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ arg = argv[i] + 1;
+ if (strcmp(arg, "b") == 0) {
+ i++;
+ if (i < argc) {
+ tbufsz = atoi(argv[i]);
+ if (tbufsz > 0)
+ bufsz = min(max((BUFSZ_MIN), tbufsz), (BUFSZ_MAX));
+ do_pbuf = 1;
+ }
+ } else if (strcmp(arg, "n") == 0) {
+ i++;
+ if (i < argc) {
+ tmaxlen = atoi(argv[i]);
+ if (tmaxlen > 0)
+ maxlen = min(max((LEN_MIN), tmaxlen), (LEN_MAX));
+ do_plen = 1;
+ }
+ } else if (strcmp(arg, "s") == 0)
+ do_simple = 1;
+ else if (strcmp(arg, "l") == 0)
+ do_simple = 0;
+ else if (strcmp(arg, "v") == 0)
+ do_verbose = 1;
+ else if (strcmp(arg, "q") == 0)
+ do_verbose = 0;
+ }
+ }
+ if (do_pbuf || do_verbose)
+ printf("Using bufsz %zu\n", bufsz);
+ if (do_plen || do_verbose)
+ printf("Using maxlen %zu\n", maxlen);
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ arg = argv[i] + 1;
+ if ((strcmp(arg, "b") == 0) || (strcmp(arg, "n") == 0))
+ i++; /* Skip next arg */
+ else if (!((strcmp(arg, "s") == 0) || (strcmp(arg, "l") == 0) || (strcmp(arg, "v") == 0) || (strcmp(arg, "q") == 0))) {
+ time_copy(argv[i], do_simple, do_verbose, bufsz, maxlen);
+ numfl++;
+ }
+ } else {
+ time_copy(argv[i], do_simple, do_verbose, bufsz, maxlen);
+ numfl++;
+ }
+ }
+ if (numfl == 0)
+ fprintf(stderr, "%s: Please specify a file\n", argv[0]);
+ return 0;
+} /* int main(int argc, char *argv[]) */
diff --git a/com32/modules/poweroff.c b/com32/modules/poweroff.c
new file mode 100644
index 00000000..8b656ad4
--- /dev/null
+++ b/com32/modules/poweroff.c
@@ -0,0 +1,88 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2013 Sebastian Herbszt - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * poweroff.c
+ *
+ * APM poweroff module
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <com32.h>
+
+int main()
+{
+ com32sys_t inregs, outregs;
+
+ memset(&inregs, 0, sizeof inregs);
+
+ inregs.eax.l = 0x5300; /* APM Installation Check (00h) */
+ inregs.ebx.l = 0; /* APM BIOS (0000h) */
+ __intcall(0x15, &inregs, &outregs);
+
+ if (outregs.eflags.l & EFLAGS_CF) {
+ printf("APM not present.\n");
+ return 1;
+ }
+
+ if ((outregs.ebx.l & 0xffff) != 0x504d) { /* signature 'PM' */
+ printf("APM not present.\n");
+ return 1;
+ }
+
+ if ((outregs.eax.l & 0xffff) < 0x101) { /* Need version 1.1+ */
+ printf("APM 1.1+ not supported.\n");
+ return 1;
+ }
+
+ if ((outregs.ecx.l & 0x8) == 0x8) { /* bit 3 APM BIOS Power Management disabled */
+ printf("Power management disabled.\n");
+ return 1;
+ }
+
+ inregs.eax.l = 0x5301; /* APM Real Mode Interface Connect (01h) */
+ inregs.ebx.l = 0; /* APM BIOS (0000h) */
+ __intcall(0x15, &inregs, &outregs);
+
+ if (outregs.eflags.l & EFLAGS_CF) {
+ printf("APM RM interface connect failed.\n");
+ return 1;
+ }
+
+ inregs.eax.l = 0x530e; /* APM Driver Version (0Eh) */
+ inregs.ebx.l = 0; /* APM BIOS (0000h) */
+ inregs.ecx.l = 0x101; /* APM Driver version 1.1 */
+ __intcall(0x15, &inregs, &outregs);
+
+ if (outregs.eflags.l & EFLAGS_CF) {
+ printf("APM 1.1+ not supported.\n");
+ return 1;
+ }
+
+ if ((outregs.ecx.l & 0xffff) < 0x101) { /* APM Connection version */
+ printf("APM 1.1+ not supported.\n");
+ return 1;
+ }
+
+ inregs.eax.l = 0x5307; /* Set Power State (07h) */
+ inregs.ebx.l = 1; /* All devices power managed by the APM BIOS */
+ inregs.ecx.l = 3; /* Power state off */
+ __intcall(0x15, &inregs, &outregs);
+
+ if (outregs.eflags.l & EFLAGS_CF) {
+ printf("Power off failed.\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/core/Makefile b/core/Makefile
index 14590eb6..562e49f5 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -25,7 +25,8 @@ include $(MAKEDIR)/embedded.mk
-include $(objdir)/version.mk
OPTFLAGS =
-INCLUDES = -I$(SRC)/include -I$(com32)/include -I$(com32)/include/sys -I$(com32)/lib
+INCLUDES = -I$(SRC)/include -I$(com32)/include -I$(com32)/include/sys -I$(com32)/lib \
+ -I$(SRC)/lwip/src/include -I$(SRC)/lwip/src/include/ipv4 -I$(SRC)/fs/pxe
# This is very similar to cp437; technically it's for Norway and Denmark,
# but it's unlikely the characters that are different will be used in
@@ -35,27 +36,56 @@ CODEPAGE = cp865
# The targets to build in this directory...
BTARGET = kwdhash.gen \
ldlinux.bss ldlinux.sys ldlinux.bin \
- isolinux.bin isolinux-debug.bin pxelinux.0
+ isolinux.bin isolinux-debug.bin pxelinux.0 lpxelinux.0
# All primary source files for the main syslinux files
NASMSRC := $(wildcard $(SRC)/*.asm)
NASMHDR := $(wildcard $(SRC)/*.inc)
-CSRC := $(wildcard $(SRC)/*.c $(SRC)/*/*.c $(SRC)/*/*/*.c)
-SSRC := $(wildcard $(SRC)/*.S $(SRC)/*/*.S $(SRC)/*/*/*.S)
-CHDR := $(wildcard $(SRC)/*.h $(SRC)/*/*.h $(SRC)/*/*/*.h)
+CSRC := $(shell find $(SRC) -name '*.c' -print)
+SSRC := $(shell find $(SRC) -name '*.S' -print)
+CHDR := $(shell find $(SRC) -name '*.h' -print)
OTHERSRC := keywords
ALLSRC = $(NASMSRC) $(NASMHDR) $(CSRC) $(SSRC) $(CHDR) $(OTHERSRC)
COBJ := $(subst $(SRC)/,,$(patsubst %.c,%.o,$(CSRC)))
SOBJ := $(subst $(SRC)/,,$(patsubst %.S,%.o,$(SSRC)))
-# Don't include derivative-specific objects
-COBJS = $(filter-out %rawcon.o %plaincon.o %pxelinux-c.o %ldlinux-c.o %isolinux-c.o,$(COBJ))
+# To make this compatible with the following $(filter-out), make sure
+# we prefix everything with $(SRC)
+CORE_PXE_CSRC = \
+ $(addprefix $(SRC)/fs/pxe/, dhcp_option.c pxe.c tftp.c urlparse.c)
+
+LPXELINUX_CSRC = $(CORE_PXE_CSRC) \
+ $(shell find $(SRC)/lwip -name '*.c' -print) \
+ $(addprefix $(SRC)/fs/pxe/, \
+ core.c dnsresolv.c ftp.c ftp_readdir.c gpxeurl.c http.c \
+ http_readdir.c idle.c isr.c tcp.c)
+
+PXELINUX_CSRC = $(CORE_PXE_CSRC) \
+ $(shell find $(SRC)/legacynet -name '*.c' -print)
+
+LPXELINUX_OBJS = $(subst $(SRC)/,,$(LPXELINUX_CSRC:%.c=%.o))
+PXELINUX_OBJS = $(subst $(SRC)/,,$(PXELINUX_CSRC:%.c=%.o))
+
+# Don't include console and network stack specific objects
+FILTER_OBJS = %rawcon.o %plaincon.o %pxelinux-c.o %ldlinux-c.o %isolinux-c.o \
+ $(subst $(OBJ)/,,$(LPXELINUX_OBJS)) \
+ $(subst $(OBJ)/,,$(PXELINUX_OBJS))
+
+ifdef EFI_BUILD
+# EFI is single-threaded.
+FILTER_OBJS += $(subst $(SRC)/,, \
+ $(patsubst %.c,%.o, $(wildcard $(SRC)/thread/*.c)) \
+ $(patsubst %.S,%.o, $(wildcard $(SRC)/thread/*.S)))
+endif
+
+COBJS = $(filter-out $(FILTER_OBJS),$(COBJ))
+SOBJS = $(filter-out $(FILTER_OBJS),$(SOBJ))
LIB = libcom32.a
LIBS = $(LIB) --whole-archive $(objdir)/com32/lib/libcom32core.a
LIBDEP = $(filter-out -% %start%,$(LIBS))
-LIBOBJS = $(COBJS) $(SOBJ)
+LIBOBJS = $(COBJS) $(SOBJS)
NASMDEBUG = -g -F dwarf
NASMOPT += $(NASMDEBUG)
@@ -88,7 +118,7 @@ ifeq ($(ARCH),x86_64)
endif
ifdef EFI_BUILD
-all: makeoutputdirs $(filter-out %bios.o,$(COBJS)) codepage.o
+all: makeoutputdirs $(filter-out %bios.o,$(COBJS) $(SOBJS)) codepage.o
else
all: makeoutputdirs $(BTARGET)
endif
@@ -117,7 +147,8 @@ kwdhash.gen: keywords genhash.pl
-I$(SRC)/ \
-l $(@:.o=.lsr) -o $@ -MP -MD $(dir $@).$(notdir $@).d $<
-AUXLIBS = libisolinux.a libisolinux-debug.a libldlinux.a libpxelinux.a
+AUXLIBS = libisolinux.a libisolinux-debug.a libldlinux.a \
+ libpxelinux.a liblpxelinux.a
LDSCRIPT = $(SRC)/$(ARCH)/syslinux.ld
%.elf: %.o $(LIBDEP) $(LDSCRIPT) $(AUXLIBS)
@@ -135,11 +166,21 @@ libisolinux.a: rawcon.o isolinux-c.o
libisolinux-debug.a: libisolinux.a
cp $^ $@
-libpxelinux.a: rawcon.o pxelinux-c.o
+# Legacy network stack
+libpxelinux.a: rawcon.o pxelinux-c.o $(PXELINUX_OBJS)
rm -f $@
$(AR) cq $@ $^
$(RANLIB) $@
+# LwIP network stack
+liblpxelinux.a: rawcon.o pxelinux-c.o
+ $(MAKE) OBJ="$(OBJ)" SRC="$(SRC)" -f $(SRC)/Makefile \
+ CFLAGS="$(CFLAGS) -I$(objdir) -DIS_LPXELINUX" $(LPXELINUX_OBJS)
+ rm -f $@
+ $(AR) cq $@ $^ $(LPXELINUX_OBJS)
+ $(RANLIB) $@
+ rm $(LPXELINUX_OBJS)
+
libldlinux.a: plaincon.o ldlinux-c.o
rm -f $@
$(AR) cq $@ $^
@@ -150,9 +191,28 @@ $(LIB): $(LIBOBJS)
$(AR) cq $@ $^
$(RANLIB) $@
+pxelinux.o: pxelinux.asm kwdhash.gen ../version.gen
+ $(NASM) -f $(NASM_ELF) $(NASMOPT) -DDATE_STR="'$(DATE)'" \
+ -DHEXDATE="$(HEXDATE)" \
+ -D$(ARCH) \
+ -I$(SRC)/ \
+ -DIS_LPXELINUX=0 \
+ -l $(@:.o=.lsr) -o $@ -MP -MD $(dir $@).$(notdir $@).d $<
+
pxelinux.0: pxelinux.bin
cp -f $< $@
+lpxelinux.o: pxelinux.asm kwdhash.gen ../version.gen
+ $(NASM) -f $(NASM_ELF) $(NASMOPT) -DDATE_STR="'$(DATE)'" \
+ -DHEXDATE="$(HEXDATE)" \
+ -D$(ARCH) \
+ -I$(SRC)/ \
+ -DIS_LPXELINUX=1 \
+ -l $(@:.o=.lsr) -o $@ -MP -MD $(dir $@).$(notdir $@).d $<
+
+lpxelinux.0: lpxelinux.bin
+ cp -f $< $@
+
ldlinux.bss: ldlinux.bin
dd if=$< of=$@ bs=512 count=1
@@ -173,10 +233,11 @@ install-all: install install-lib
netinstall: installer
tidy dist:
- rm -f codepage.cp *.o *.elf *.a stupid.* patch.offset .depend .*.d
+ find . -type f \( -name '*.o' -o -name '*.a' -o -name '.*.d' \
+ -o -name '*.lst' \) -print | xargs -rt rm -f
+ rm -f codepage.cp *.elf stupid.* patch.offset .depend
rm -f *.elf.tmp *.sym
- rm -f *.lsr *.lst *.map *.sec *.raw
- rm -f */*.o */*/*.o */*.lst */*/*.lst */.*.d */*/.*.d
+ rm -f *.lsr *.map *.sec *.raw
rm -f $(OBSOLETE) $(LIB)
clean: tidy
@@ -185,4 +246,4 @@ spotless: clean
rm -f $(BTARGET) *.bin *_bin.c
# Include dependencies file
--include .*.d */.*.d */*/.*.d
+-include $(shell find . -name '.*.d' -print)
diff --git a/core/bios.c b/core/bios.c
index bd8b4d87..aca764b1 100644
--- a/core/bios.c
+++ b/core/bios.c
@@ -537,9 +537,15 @@ void bios_init(void)
/* Init the memory subsystem */
bios_free_mem = (uint16_t *)0x413;
+ mem_init();
/* CPU-dependent initialization and related checks. */
check_escapes();
+
+ /*
+ * Scan the DMI tables for interesting information.
+ */
+ dmi_init();
}
extern void *bios_malloc(size_t, enum heap, size_t);
diff --git a/core/callback.inc b/core/callback.inc
index 454b4522..f1332e8e 100644
--- a/core/callback.inc
+++ b/core/callback.inc
@@ -49,6 +49,7 @@ core_intcall:
core_syscall:
pushfd ; Save IF among other things...
+ inc dword [CallbackCtr]
push ebx
push ebp
push esi
@@ -130,6 +131,10 @@ core_syscall:
; Remove from stack
pop dword [CallbackSP]
+ dec dword [CallbackCtr]
+ jnz .skip
+ call [core_pm_hook]
+.skip:
pop edi
pop esi
pop ebp
@@ -145,6 +150,7 @@ core_syscall:
global core_cfarcall:function hidden
core_cfarcall:
pushfd ; Save IF among other things...
+ inc dword [CallbackCtr]
push ebx
push ebp
push esi
@@ -199,6 +205,10 @@ core_cfarcall:
mov eax,esi
; EDX already set up to be the RM return value
pop dword [CallbackSP]
+ dec dword [CallbackCtr]
+ jnz .skip
+ call [core_pm_hook]
+.skip:
pop ebx
pop ebp
pop esi
@@ -206,10 +216,11 @@ core_cfarcall:
popfd
ret
- bits 16
section .bss16
alignb 4
+ global core_pm_hook
CallbackSP resd 1 ; SP saved during callback
+CallbackCtr resd 1
bits 16
section .text16
diff --git a/core/debug.c b/core/debug.c
new file mode 100644
index 00000000..9bf8b3a6
--- /dev/null
+++ b/core/debug.c
@@ -0,0 +1,9 @@
+#include "core.h"
+#include <dprintf.h>
+
+void pm_debug_msg(com32sys_t *regs)
+{
+ (void)regs; /* For the non-DEBUG configuration */
+
+ dprintf("%s\n", MK_PTR(0, regs->eax.w[0]));
+}
diff --git a/core/diskfs.inc b/core/diskfs.inc
index 827f5003..d0f2804c 100644
--- a/core/diskfs.inc
+++ b/core/diskfs.inc
@@ -33,25 +33,6 @@ BS_MAGIC_VER equ 0x1b << 9
MIN_SECTOR_SHIFT equ 9
MIN_SECTOR_SIZE equ (1 << MIN_SECTOR_SHIFT)
-;
-; The following structure is used for "virtual kernels"; i.e. LILO-style
-; option labels. The options we permit here are `kernel' and `append
-; Since there is no room in the bottom 64K for all of these, we
-; stick them in high memory and copy them down before we need them.
-;
- struc vkernel
-vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
-vk_rname: resb FILENAME_MAX ; Real name
-vk_appendlen: resw 1
-vk_type: resb 1 ; Type of file
- alignb 4
-vk_append: resb max_cmd_len+1 ; Command line
- alignb 4
-vk_end: equ $ ; Should be <= vk_size
- endstruc
-
-
-
; ---------------------------------------------------------------------------
; BEGIN CODE
; ---------------------------------------------------------------------------
@@ -99,17 +80,6 @@ FuncFlag resb 1 ; Escape sequences received from keyboard
KernelType resb 1 ; Kernel type, from vkernel, if known
global KernelName
KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .data16
- global IPAppends, numIPAppends
-%if IS_PXELINUX
- extern IPOption
- alignz 2
-IPAppends dw IPOption
-numIPAppends equ ($-IPAppends)/2
-%else
-IPAppends equ 0
-numIPAppends equ 0
-%endif
section .text16
;
diff --git a/core/dmi.c b/core/dmi.c
new file mode 100644
index 00000000..9cbe2832
--- /dev/null
+++ b/core/dmi.c
@@ -0,0 +1,383 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Search DMI information for specific data or strings
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/bitops.h>
+#include <sys/cpu.h>
+#include <syslinux/sysappend.h>
+#include "core.h"
+
+struct dmi_table {
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+};
+
+struct dmi_header {
+ char signature[5];
+ uint8_t csum;
+ uint16_t tbllen;
+ uint32_t tbladdr;
+ uint16_t nstruc;
+ uint8_t revision;
+ uint8_t reserved;
+};
+
+struct smbios_header {
+ char signature[4];
+ uint8_t csum;
+ uint8_t len;
+ uint8_t major;
+ uint8_t minor;
+ uint16_t maxsize;
+ uint8_t revision;
+ uint8_t fmt[5];
+
+ struct dmi_header dmi;
+};
+
+static const struct dmi_header *dmi;
+
+static uint8_t checksum(const void *buf, size_t len)
+{
+ const uint8_t *p = buf;
+ uint8_t csum = 0;
+
+ while (len--)
+ csum += *p++;
+
+ return csum;
+}
+
+static bool is_old_dmi(size_t dptr)
+{
+ const struct dmi_header *dmi = (void *)dptr;
+
+ return !memcmp(dmi->signature, "_DMI_", 5) &&
+ !checksum(dmi, 0x0f);
+ return false;
+}
+
+static bool is_smbios(size_t dptr)
+{
+ const struct smbios_header *smb = (void *)dptr;
+
+ return !memcmp(smb->signature, "_SM_", 4) &&
+ !checksum(smb, smb->len) &&
+ is_old_dmi(dptr+16);
+}
+
+/*
+ * Find the root structure
+ */
+static void dmi_find_header(void)
+{
+ size_t dptr;
+
+ /* Search for _SM_ or _DMI_ structure */
+ for (dptr = 0xf0000 ; dptr < 0x100000 ; dptr += 16) {
+ if (is_smbios(dptr)) {
+ dmi = (const struct dmi_header *)(dptr + 16);
+ break;
+ } else if (is_old_dmi(dptr)) {
+ dmi = (const struct dmi_header *)dptr;
+ break;
+ }
+ }
+}
+
+/*
+ * Return a specific data element in a specific table, and verify
+ * that it is within the bounds of the table.
+ */
+static const void *dmi_find_data(uint8_t type, uint8_t base, uint8_t length)
+{
+ const struct dmi_table *table;
+ size_t offset, end;
+ unsigned int tblcount;
+
+ if (!dmi)
+ return NULL;
+
+ if (base < 2)
+ return NULL;
+
+ end = base+length;
+
+ offset = 0;
+ tblcount = dmi->nstruc;
+
+ while (offset+6 <= dmi->tbllen && tblcount--) {
+ table = (const struct dmi_table *)(dmi->tbladdr + offset);
+
+ if (table->type == 127) /* End of table */
+ break;
+
+ if (table->length < sizeof *table)
+ break; /* Invalid length */
+
+ offset += table->length;
+
+ if (table->type == type && end <= table->length)
+ return (const char *)table + base;
+
+ /* Search for a double NUL terminating the string table */
+ while (offset+2 <= dmi->tbllen &&
+ *(const uint16_t *)(dmi->tbladdr + offset) != 0)
+ offset++;
+
+ offset += 2;
+ }
+
+ return NULL;
+}
+
+/*
+ * Return a specific string in a specific table.
+ */
+static const char *dmi_find_string(uint8_t type, uint8_t base)
+{
+ const struct dmi_table *table;
+ size_t offset;
+ unsigned int tblcount;
+
+ if (!dmi)
+ return NULL;
+
+ if (base < 2)
+ return NULL;
+
+ offset = 0;
+ tblcount = dmi->nstruc;
+
+ while (offset+6 <= dmi->tbllen && tblcount--) {
+ table = (const struct dmi_table *)(dmi->tbladdr + offset);
+
+ if (table->type == 127) /* End of table */
+ break;
+
+ if (table->length < sizeof *table)
+ break; /* Invalid length */
+
+ offset += table->length;
+
+ if (table->type == type && base < table->length) {
+ uint8_t index = ((const uint8_t *)table)[base];
+ const char *p = (const char *)table + table->length;
+ const char *str;
+ char c;
+
+ if (!index)
+ return NULL; /* String not present */
+
+ while (--index) {
+ if (!*p)
+ return NULL;
+
+ do {
+ if (offset++ >= dmi->tbllen)
+ return NULL;
+ c = *p++;
+ } while (c);
+ }
+
+ /* Make sure the string is null-terminated */
+ str = p;
+ do {
+ if (offset++ >= dmi->tbllen)
+ return NULL;
+ c = *p++;
+ } while (c);
+ return str;
+ }
+
+ /* Search for a double NUL terminating the string table */
+ while (offset+2 <= dmi->tbllen &&
+ *(const uint16_t *)(dmi->tbladdr + offset) != 0)
+ offset++;
+
+ offset += 2;
+ }
+
+ return NULL;
+}
+
+struct sysappend_dmi_strings {
+ const char *prefix;
+ enum syslinux_sysappend sa;
+ uint8_t index;
+ uint8_t offset;
+};
+
+static const struct sysappend_dmi_strings dmi_strings[] = {
+ { "SYSVENDOR=", SYSAPPEND_SYSVENDOR, 1, 0x04 },
+ { "SYSPRODUCT=", SYSAPPEND_SYSPRODUCT, 1, 0x05 },
+ { "SYSVERSION=", SYSAPPEND_SYSVERSION, 1, 0x06 },
+ { "SYSSERIAL=", SYSAPPEND_SYSSERIAL, 1, 0x07 },
+ { "SYSSKU=", SYSAPPEND_SYSSKU, 1, 0x19 },
+ { "SYSFAMILY=", SYSAPPEND_SYSFAMILY, 1, 0x1a },
+ { "MBVENDOR=", SYSAPPEND_MBVENDOR, 2, 0x04 },
+ { "MBPRODUCT=", SYSAPPEND_MBPRODUCT, 2, 0x05 },
+ { "MBVERSION=", SYSAPPEND_MBVERSION, 2, 0x06 },
+ { "MBSERIAL=", SYSAPPEND_MBSERIAL, 2, 0x07 },
+ { "MBASSET=", SYSAPPEND_MBASSET, 2, 0x08 },
+ { "BIOSVENDOR=", SYSAPPEND_BIOSVENDOR, 0, 0x04 },
+ { "BIOSVERSION=", SYSAPPEND_BIOSVERSION, 0, 0x05 },
+ { NULL, 0, 0, 0 }
+};
+
+/*
+ * Install the string in the string table, if nonempty, after
+ * removing leading and trailing whitespace.
+ */
+static bool is_ctl_or_whitespace(char c)
+{
+ return (c <= ' ' || c == '\x7f');
+}
+
+static const char *dmi_install_string(const char *pfx, const char *str)
+{
+ const char *p, *ep;
+ size_t pfxlen;
+ char *nstr, *q;
+
+ if (!str)
+ return NULL;
+
+ while (*str && is_ctl_or_whitespace(*str))
+ str++;
+
+ if (!*str)
+ return NULL;
+
+ ep = p = str;
+ while (*p) {
+ if (!is_ctl_or_whitespace(*p))
+ ep = p+1;
+ p++;
+ }
+
+ pfxlen = strlen(pfx);
+ q = nstr = malloc(pfxlen + (ep-str) + 1);
+ if (!nstr)
+ return NULL;
+ memcpy(q, pfx, pfxlen);
+ q += pfxlen;
+ memcpy(q, str, ep-str);
+ q += (ep-str);
+ *q = '\0';
+
+ return nstr;
+}
+
+static void sysappend_set_sysff(const uint8_t *type)
+{
+ static char sysff_str[] = "SYSFF=000";
+
+ if (!type || !*type)
+ return;
+
+ sprintf(sysff_str+6, "%u", *type & 0x7f);
+ sysappend_strings[SYSAPPEND_SYSFF] = sysff_str;
+}
+
+struct cpuflag {
+ uint8_t bit;
+ char flag;
+};
+
+static void sysappend_set_cpu(void)
+{
+ static char cpu_str[6+6] = "CPU=";
+ char *p = cpu_str + 4;
+ static const struct cpuflag cpuflags[] = {
+ { 0*32+ 6, 'P' }, /* PAE */
+ { 1*32+ 5, 'V' }, /* VMX */
+ { 1*32+ 6, 'T' }, /* SMX (TXT) */
+ { 2*32+20, 'X' }, /* XD/NX */
+ { 2*32+29, 'L' }, /* Long mode (x86-64) */
+ { 3*32+ 2, 'S' }, /* SVM */
+ { 0, 0 }
+ };
+ const struct cpuflag *cf;
+
+ /* Not technically from DMI, but it fit here... */
+
+ if (!cpu_has_eflag(EFLAGS_ID)) {
+ /* No CPUID */
+ *p++ = cpu_has_eflag(EFLAGS_AC) ? '4' : '3';
+ } else {
+ uint32_t flags[4], eax, ebx, family;
+ uint32_t ext_level;
+
+ cpuid(1, &eax, &ebx, &flags[1], &flags[0]);
+ family = (eax & 0x0ff00f00) >> 8;
+ *p++ = family >= 6 ? '6' : family + '0';
+
+ ext_level = cpuid_eax(0x80000000);
+ if (ext_level >= 0x80000001 && ext_level <= 0x8000ffff) {
+ cpuid(0x80000001, &eax, &ebx, &flags[3], &flags[2]);
+ } else {
+ flags[2] = flags[3] = 0;
+ }
+
+ for (cf = cpuflags; cf->flag; cf++) {
+ if (test_bit(cf->bit, flags))
+ *p++ = cf->flag;
+ }
+ }
+
+ *p = '\0';
+
+ sysappend_strings[SYSAPPEND_CPU] = cpu_str;
+}
+
+void dmi_init(void)
+{
+ const struct sysappend_dmi_strings *ds;
+
+ sysappend_set_cpu();
+
+ dmi_find_header();
+ if (!dmi)
+ return;
+
+ sysappend_set_uuid(dmi_find_data(1, 0x08, 16));
+ sysappend_set_sysff(dmi_find_data(3, 0x05, 1));
+
+ for (ds = dmi_strings; ds->prefix; ds++) {
+ if (!sysappend_strings[ds->sa]) {
+ const char *str = dmi_find_string(ds->index, ds->offset);
+ sysappend_strings[ds->sa] = dmi_install_string(ds->prefix, str);
+ }
+ }
+}
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index b277877a..5f797d67 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -57,12 +57,12 @@ void init_module_subsystem(struct elf_module *module)
list_add(&module->list, &modules_head);
}
-__export int start_ldlinux(char **argv)
+__export int start_ldlinux(int argc, char **argv)
{
int rv;
again:
- rv = spawn_load(LDLINUX, 1, argv);
+ rv = spawn_load(LDLINUX, argc, argv);
if (rv == EEXIST) {
/*
* If a COM32 module calls execute() we may need to
@@ -139,7 +139,7 @@ void load_env32(com32sys_t * regs __unused)
init_module_subsystem(&core_module);
- start_ldlinux(argv);
+ start_ldlinux(1, argv);
/*
* If we failed to load LDLINUX it could be because our
@@ -147,10 +147,9 @@ void load_env32(com32sys_t * regs __unused)
* a bit harder to find LDLINUX. If search_dirs() succeeds
* in finding LDLINUX it will set the cwd.
*/
- free(PATH);
fd = opendev(&__file_dev, NULL, O_RDONLY);
if (fd < 0)
- return;
+ goto out;
fp = &__file_info[fd];
@@ -159,27 +158,45 @@ void load_env32(com32sys_t * regs __unused)
/*
* search_dirs() sets the current working directory if
- * it successfully opens the file. Set PATH to the
- * directory in which we found ldlinux.c32.
+ * it successfully opens the file. Add the directory
+ * in which we found ldlinux.c32 to PATH.
*/
if (!core_getcwd(path, sizeof(path)))
goto out;
- PATH = malloc(strlen(path) + 1);
- if (!PATH) {
- printf("Couldn't allocate memory for PATH\n");
- goto out;
+ if (!strlen(PATH)) {
+ PATH = realloc(PATH, strlen(path) + 1);
+ if (!PATH) {
+ printf("Couldn't allocate memory for PATH\n");
+ goto out;
+ }
+
+ strcpy(PATH, path);
+ } else {
+ PATH = realloc(PATH, strlen(path) + strlen(PATH) + 2);
+ if (!PATH) {
+ printf("Couldn't allocate memory for PATH\n");
+ goto out;
+ }
+
+ strcat(PATH, ":");
+ strcat(PATH, path);
}
- strcpy(PATH, path);
-
- start_ldlinux(argv);
+ start_ldlinux(1, argv);
}
out:
+ free(PATH);
writestr("\nFailed to load ldlinux.c32");
}
+static const char *__cmdline;
+__export const char *com32_cmdline(void)
+{
+ return __cmdline;
+}
+
__export int create_args_and_load(char *cmdline)
{
char *p, **argv;
@@ -231,6 +248,12 @@ __export int create_args_and_load(char *cmdline)
*/
while (*p && isspace(*p))
p++;
+
+ /*
+ * Point __cmdline at "argv[1] ... argv[argc-1]"
+ */
+ if (i == 0)
+ __cmdline = p;
}
/* NUL-terminate */
diff --git a/core/errno.c b/core/errno.c
new file mode 100644
index 00000000..adfd92f8
--- /dev/null
+++ b/core/errno.c
@@ -0,0 +1,4 @@
+#include <klibc/compiler.h>
+#include <errno.h>
+
+__export int errno;
diff --git a/core/extern.inc b/core/extern.inc
index a159000b..673191cf 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -44,9 +44,27 @@
; newconfig.c
extern pm_is_config_file
+%ifdef DEBUG
+ ; debug.c
+ extern pm_debug_msg
+
+ %macro dprint 1+
+ push ax
+ call %%fwd
+ db %1
+ db 0
+%%fwd: pop ax
+ pm_call pm_debug_msg
+ pop ax
+ %endmacro
+%else
+ %macro dprint 1+
+ %endmacro
+%endif
+
%if IS_PXELINUX
; pxe.c
- extern unload_pxe, reset_pxe
+ extern unload_pxe, reset_pxe, http_bake_cookies
%endif
; plaincon.c
diff --git a/core/fs/chdir.c b/core/fs/chdir.c
index 5d3a545f..276ea11c 100644
--- a/core/fs/chdir.c
+++ b/core/fs/chdir.c
@@ -2,6 +2,7 @@
#include <stdbool.h>
#include <string.h>
#include <dprintf.h>
+#include <fcntl.h>
#include "fs.h"
#include "cache.h"
@@ -65,7 +66,7 @@ __export size_t realpath(char *dst, const char *src, size_t bufsize)
if (this_fs->fs_ops->realpath) {
s = this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
} else {
- rv = searchdir(src);
+ rv = searchdir(src, O_RDONLY);
if (rv < 0) {
dprintf("realpath: searchpath failure\n");
return -1;
@@ -97,7 +98,7 @@ __export int chdir(const char *src)
return this_fs->fs_ops->chdir(this_fs, src);
/* Otherwise it is a "conventional filesystem" */
- rv = searchdir(src);
+ rv = searchdir(src, O_RDONLY|O_DIRECTORY);
if (rv < 0)
return rv;
diff --git a/core/fs/diskio.c b/core/fs/diskio.c
index afe4e58c..7d95d674 100644
--- a/core/fs/diskio.c
+++ b/core/fs/diskio.c
@@ -7,6 +7,7 @@
#include <fs.h>
#include <disk.h>
#include <ilog2.h>
+#include <minmax.h>
#include <syslinux/firmware.h>
@@ -19,17 +20,14 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size)
/*
* Initialize the device structure.
- *
- * NOTE: the disk cache needs to be revamped to support multiple devices...
*/
struct device * device_init(void *args)
{
static struct device dev;
- static __hugebss char diskcache[128*1024];
dev.disk = firmware->disk_init(args);
- dev.cache_data = diskcache;
- dev.cache_size = sizeof diskcache;
+ dev.cache_size = 128*1024;
+ dev.cache_data = malloc(dev.cache_size);
return &dev;
}
diff --git a/core/fs/fs.c b/core/fs/fs.c
index adcee916..2c1bdbee 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
#include <dprintf.h>
#include "core.h"
#include "dev.h"
@@ -138,7 +139,7 @@ size_t pmapi_read_file(uint16_t *handle, void *buf, size_t sectors)
return bytes_read;
}
-int searchdir(const char *name)
+int searchdir(const char *name, int flags)
{
static char root_name[] = "/";
struct file *file;
@@ -155,7 +156,7 @@ int searchdir(const char *name)
/* if we have ->searchdir method, call it */
if (file->fs->fs_ops->searchdir) {
- file->fs->fs_ops->searchdir(name, file);
+ file->fs->fs_ops->searchdir(name, flags, file);
if (file->inode)
return file_to_handle(file);
@@ -337,7 +338,7 @@ err_no_close:
return -1;
}
-__export int open_file(const char *name, struct com32_filedata *filedata)
+__export int open_file(const char *name, int flags, struct com32_filedata *filedata)
{
int rv;
struct file *file;
@@ -346,7 +347,7 @@ __export int open_file(const char *name, struct com32_filedata *filedata)
dprintf("open_file %s\n", name);
mangle_name(mangled_name, name);
- rv = searchdir(mangled_name);
+ rv = searchdir(mangled_name, flags);
if (rv < 0)
return rv;
@@ -394,9 +395,6 @@ void fs_init(const struct fs_ops **ops, void *priv)
int blk_shift = -1;
struct device *dev = NULL;
- /* Initialize malloc() */
- mem_init();
-
/* Default name for the root directory */
fs.cwd_name[0] = '/';
diff --git a/core/fs/lib/searchconfig.c b/core/fs/lib/searchconfig.c
index b2a964e8..bb1dabf9 100644
--- a/core/fs/lib/searchconfig.c
+++ b/core/fs/lib/searchconfig.c
@@ -1,4 +1,5 @@
#include <dprintf.h>
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <core.h>
@@ -30,7 +31,7 @@ int search_dirs(struct com32_filedata *filedata,
if (realpath(realname, namebuf, FILENAME_MAX) == (size_t)-1)
continue;
dprintf("Config search: %s\n", realname);
- if (open_file(realname, filedata) >= 0) {
+ if (open_file(realname, O_RDONLY, filedata) >= 0) {
chdir(sd);
return 0; /* Got it */
}
diff --git a/core/fs/pxe/core.c b/core/fs/pxe/core.c
new file mode 100644
index 00000000..9246f669
--- /dev/null
+++ b/core/fs/pxe/core.c
@@ -0,0 +1,207 @@
+#include <syslinux/pxe_api.h>
+#include <lwip/api.h>
+#include <lwip/tcpip.h>
+#include <lwip/dns.h>
+#include <core.h>
+#include <net.h>
+#include "pxe.h"
+
+/**
+ * Open a socket
+ *
+ * @param:socket, the socket to open
+ * @param:proto, the protocol of the new connection
+ *
+ * @out: error code, 0 on success, -1 on failure
+ */
+int net_core_open(struct pxe_pvt_inode *socket, enum net_core_proto proto)
+{
+ struct net_private *priv = &socket->private;
+ enum netconn_type type;
+ int err;
+
+ switch (proto) {
+ case NET_CORE_TCP:
+ type = NETCONN_TCP;
+ break;
+ case NET_CORE_UDP:
+ type = NETCONN_UDP;
+ break;
+ default:
+ type = NETCONN_INVALID;
+ break;
+ }
+
+ priv->conn = netconn_new(type);
+ if (!priv->conn)
+ return -1;
+
+ priv->conn->recv_timeout = 15; /* A 15 ms recv timeout... */
+ err = netconn_bind(priv->conn, NULL, 0);
+ if (err) {
+ printf("netconn_bind error %d\n", err);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Close a socket
+ *
+ * @param:socket, the socket to open
+ */
+void net_core_close(struct pxe_pvt_inode *socket)
+{
+ struct net_private *priv = &socket->private;
+
+ if (priv->conn) {
+ netconn_delete(priv->conn);
+ priv->conn = NULL;
+ }
+}
+
+/**
+ * Establish a connection on an open socket
+ *
+ * @param:socket, the open socket
+ * @param:ip, the ip address
+ * @param:port, the port number, host-byte order
+ */
+void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip,
+ uint16_t port)
+{
+ struct net_private *priv = &socket->private;
+ struct ip_addr addr;
+
+ addr.addr = ip;
+ netconn_connect(priv->conn, &addr, port);
+}
+
+/**
+ * Tear down a connection on an open socket
+ *
+ * @param:socket, the open socket
+ */
+void net_core_disconnect(struct pxe_pvt_inode *socket)
+{
+ struct net_private *priv = &socket->private;
+ netconn_disconnect(priv->conn);
+}
+
+/**
+ * Read data from the network stack
+ *
+ * @param:socket, the open socket
+ * @param:buf, location of buffer to store data
+ * @param:buf_len, size of buffer
+
+ * @out: src_ip, ip address of the data source
+ * @out: src_port, port number of the data source, host-byte order
+ */
+int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
+ uint32_t *src_ip, uint16_t *src_port)
+{
+ struct net_private *priv = &socket->private;
+ struct netbuf *nbuf;
+ u16_t nbuf_len;
+ int err;
+
+ err = netconn_recv(priv->conn, &nbuf);
+ if (err)
+ return err;
+
+ if (!nbuf)
+ return -1;
+
+ *src_ip = netbuf_fromaddr(nbuf)->addr;
+ *src_port = netbuf_fromport(nbuf);
+
+ netbuf_first(nbuf); /* XXX needed? */
+ nbuf_len = netbuf_len(nbuf);
+ if (nbuf_len <= *buf_len)
+ netbuf_copy(nbuf, buf, nbuf_len);
+ else
+ nbuf_len = 0; /* impossible mtu < PKTBUF_SIZE */
+ netbuf_delete(nbuf);
+
+ *buf_len = nbuf_len;
+ return 0;
+}
+
+/**
+ * Send a UDP packet.
+ *
+ * @param:socket, the open socket
+ * @param:data, data buffer to send
+ * @param:len, size of data bufer
+ */
+void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
+{
+ struct netconn *conn = socket->private.conn;
+ struct netbuf *nbuf;
+ void *pbuf;
+ int err;
+
+ nbuf = netbuf_new();
+ if (!nbuf) {
+ printf("netbuf allocation error\n");
+ return;
+ }
+
+ pbuf = netbuf_alloc(nbuf, len);
+ if (!pbuf) {
+ printf("pbuf allocation error\n");
+ goto out;
+ }
+
+ memcpy(pbuf, data, len);
+
+ err = netconn_send(conn, nbuf);
+ if (err) {
+ printf("netconn_send error %d\n", err);
+ goto out;
+ }
+
+out:
+ netbuf_delete(nbuf);
+}
+
+/**
+ * Network stack-specific initialization
+ */
+void net_core_init(void)
+{
+ int err;
+ int i;
+
+ http_bake_cookies();
+
+ /* Initialize lwip */
+ tcpip_init(NULL, NULL);
+
+ /* Start up the undi driver for lwip */
+ err = undiif_start(IPInfo.myip, IPInfo.netmask, IPInfo.gateway);
+ if (err) {
+ printf("undiif driver failed to start: %d\n", err);
+ kaboom();
+ }
+
+ for (i = 0; i < DNS_MAX_SERVERS; i++) {
+ /* Transfer the DNS information to lwip */
+ dns_setserver(i, (struct ip_addr *)&dns_server[i]);
+ }
+}
+
+void probe_undi(void)
+{
+ /* Probe UNDI information */
+ pxe_call(PXENV_UNDI_GET_INFORMATION, &pxe_undi_info);
+ pxe_call(PXENV_UNDI_GET_IFACE_INFO, &pxe_undi_iface);
+
+ printf("UNDI: baseio %04x int %d MTU %d type %d \"%s\" flags 0x%x\n",
+ pxe_undi_info.BaseIo, pxe_undi_info.IntNumber,
+ pxe_undi_info.MaxTranUnit, pxe_undi_info.HwType,
+ pxe_undi_iface.IfaceType, pxe_undi_iface.ServiceFlags);
+}
+
diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
index f2a96129..3517161a 100644
--- a/core/fs/pxe/dhcp_option.c
+++ b/core/fs/pxe/dhcp_option.c
@@ -2,6 +2,7 @@
#include <string.h>
#include <core.h>
#include <sys/cpu.h>
+#include <lwip/opt.h> /* DNS_MAX_SERVERS */
#include "pxe.h"
char LocalDomain[256];
@@ -48,13 +49,8 @@ static void dns_servers(const void *data, int opt_len)
static void local_domain(const void *data, int opt_len)
{
- char buffer[256];
- char *ld = LocalDomain;
-
- memcpy(buffer, data, opt_len);
- buffer[opt_len] = 0;
-
- dns_mangle(&ld, buffer);
+ memcpy(LocalDomain, data, opt_len);
+ LocalDomain[opt_len] = 0;
}
static void vendor_encaps(const void *data, int opt_len)
diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c
index 184bacbd..afb9e219 100644
--- a/core/fs/pxe/dnsresolv.c
+++ b/core/fs/pxe/dnsresolv.c
@@ -2,6 +2,8 @@
#include <string.h>
#include <core.h>
#include "pxe.h"
+#include "lwip/api.h"
+#include "lwip/dns.h"
/* DNS CLASS values we care about */
#define CLASS_IN 1
@@ -48,295 +50,82 @@ struct dnsrr {
uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
-
-/*
- * 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)
-{
- char *q = *dst;
- char *count_ptr;
- char c;
- int dots = 0;
-
- count_ptr = q;
- *q++ = 0;
-
- while (1) {
- c = *p++;
- if (c == 0 || c == ':' || c == '/')
- break;
- if (c == '.') {
- dots++;
- count_ptr = q;
- *q++ = 0;
- continue;
- }
-
- *count_ptr += 1;
- *q++ = c;
- }
-
- if (*count_ptr)
- *q++ = 0;
-
- /* update the strings */
- *dst = q;
- return dots;
-}
-
-
/*
- * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_
- * is allowed pointers relative to a packet in buf.
+ * parse the ip_str and return the ip address with *res.
+ * return true if the whole string was consumed and the result
+ * was valid.
*
*/
-static bool dns_compare(const void *s1, const void *s2, const void *buf)
+static bool parse_dotquad(const char *ip_str, uint32_t *res)
{
- const uint8_t *q = s1;
- const uint8_t *p = s2;
- unsigned int c0, c1;
-
- while (1) {
- c0 = p[0];
- if (c0 >= 0xc0) {
- /* Follow pointer */
- c1 = p[1];
- p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
- } else if (c0) {
- c0++; /* Include the length byte */
- if (memcmp(q, p, c0))
- return false;
- q += c0;
- p += c0;
- } else {
- return *q == 0;
- }
- }
-}
-
-/*
- * Copy a DNS label into a buffer, considering the possibility that we might
- * have to follow pointers relative to "buf".
- * Returns a pointer to the first free byte *after* the terminal null.
- */
-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;
+ const char *p = ip_str;
+ uint8_t part = 0;
+ uint32_t ip = 0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ while (is_digit(*p)) {
+ part = part * 10 + *p - '0';
+ p++;
+ }
+ if (i != 3 && *p != '.')
+ return false;
- while (1) {
- c0 = p[0];
- if (c0 >= 0xc0) {
- /* Follow pointer */
- c1 = p[1];
- p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
- } else if (c0) {
- c0++; /* Include the length byte */
- memcpy(q, p, c0);
- p += c0;
- q += c0;
- } else {
- *q++ = 0;
- return q;
- }
+ ip = (ip << 8) | part;
+ part = 0;
+ p++;
}
-}
-
-/*
- * Skip past a DNS label set in DS:SI
- */
-static char *dns_skiplabel(char *label)
-{
- uint8_t c;
+ p--;
- while (1) {
- c = *label++;
- if (c >= 0xc0)
- return ++label; /* pointer is two bytes */
- if (c == 0)
- return label;
- label += c;
- }
+ *res = htonl(ip);
+ return *p == '\0';
}
/*
- * Actual resolver function
- * Points to a null-terminated or :-terminated string in _name_
- * and returns the ip addr in _ip_ if it exists and can be found.
- * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
+ * Actual resolver function.
*
- * XXX: probably need some caching here.
+ * Points to a null-terminated in _name_ and returns the ip addr in
+ * _ip_ if it exists and can be found. If _ip_ = 0 on exit, the
+ * lookup failed. _name_ will be updated
*/
__export uint32_t dns_resolv(const char *name)
{
- static char __lowmem DNSSendBuf[PKTBUF_SIZE];
- static char __lowmem DNSRecvBuf[PKTBUF_SIZE];
- char *p;
- int err;
- int dots;
- int same;
- int rd_len;
- int ques, reps; /* number of questions and replies */
- uint8_t timeout;
- const uint8_t *timeout_ptr = TimeoutTable;
- uint32_t oldtime;
- uint32_t srv;
- uint32_t *srv_ptr;
- struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf;
- 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;
- uint16_t local_port;
- uint32_t result = 0;
-
- /* Make sure we have at least one valid DNS server */
- if (!dns_server[0])
+ err_t err;
+ struct ip_addr ip;
+ char fullname[512];
+
+ /*
+ * Return failure on an empty input... this can happen during
+ * some types of URL parsing, and this is the easiest place to
+ * check for it.
+ */
+ if (!name || !*name)
return 0;
- /* Get a local port number */
- local_port = get_port();
-
- /* First, fill the DNS header struct */
- hd1->id++; /* New query ID */
- hd1->flags = htons(0x0100); /* Recursion requested */
- hd1->qdcount = htons(1); /* One question */
- 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 */
- p = stpcpy(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++;
- 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 = 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)
- continue;
-
- oldtime = jiffies();
- do {
- if (jiffies() - oldtime >= timeout)
- goto again;
-
- udp_read.status = 0;
- udp_read.src_ip = srv;
- udp_read.dest_ip = IPInfo.myip;
- udp_read.s_port = DNS_PORT;
- udp_read.d_port = local_port;
- udp_read.buffer_size = PKTBUF_SIZE;
- udp_read.buffer = FAR_PTR(DNSRecvBuf);
- err = pxe_call(PXENV_UDP_READ, &udp_read);
- } while (err || udp_read.status || hd2->id != hd1->id);
+ /* If it is a valid dot quad, just return that value */
+ if (parse_dotquad(name, &ip.addr))
+ return ip.addr;
- if ((hd2->flags ^ 0x80) & htons(0xf80f))
- goto badness;
-
- ques = htons(hd2->qdcount); /* Questions */
- reps = htons(hd2->ancount); /* Replies */
- p = DNSRecvBuf + sizeof(struct dnshdr);
- while (ques--) {
- p = dns_skiplabel(p); /* Skip name */
- p += 4; /* Skip question trailer */
- }
-
- /* Parse the replies */
- while (reps--) {
- same = dns_compare(DNSSendBuf + sizeof(struct dnshdr),
- p, DNSRecvBuf);
- p = dns_skiplabel(p);
- rr = (struct dnsrr *)p;
- rd_len = ntohs(rr->rdlength);
- if (same && ntohs(rr->class) == CLASS_IN) {
- switch (ntohs(rr->type)) {
- case TYPE_A:
- if (rd_len == 4) {
- result = *(uint32_t *)rr->rdata;
- goto done;
- }
- break;
- case TYPE_CNAME:
- dns_copylabel(DNSSendBuf + sizeof(struct dnshdr),
- rr->rdata, DNSRecvBuf);
- /*
- * We should probably rescan the packet from the top
- * here, and technically we might have to send a whole
- * new request here...
- */
- break;
- default:
- break;
- }
- }
-
- /* not the one we want, try next */
- p += sizeof(struct dnsrr) + rd_len;
- }
-
- badness:
- /*
- *
- ; We got back no data from this server.
- ; Unfortunately, for a recursive, non-authoritative
- ; query there is no such thing as an NXDOMAIN reply,
- ; which technically means we can't draw any
- ; conclusions. However, in practice that means the
- ; 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))
- continue;
-
- break; /* failed */
+ /* Make sure we have at least one valid DNS server */
+ if (!dns_getserver(0).addr)
+ return 0;
- again:
- continue;
+ /* Is it a local (unqualified) domain name? */
+ if (!strchr(name, '.') && LocalDomain[0]) {
+ snprintf(fullname, sizeof fullname, "%s.%s", name, LocalDomain);
+ name = fullname;
}
-done:
- free_port(local_port); /* Return port number to the free pool */
+ err = netconn_gethostbyname(name, &ip);
+ if (err)
+ return 0;
- return result;
+ return ip.addr;
}
+/*
+ * the one should be called from ASM file
+ */
void pm_pxe_dns_resolv(com32sys_t *regs)
{
const char *name = MK_PTR(regs->ds, regs->esi.w[0]);
diff --git a/core/fs/pxe/ftp.c b/core/fs/pxe/ftp.c
new file mode 100644
index 00000000..5d5a6f03
--- /dev/null
+++ b/core/fs/pxe/ftp.c
@@ -0,0 +1,280 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * ftp.c
+ */
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <minmax.h>
+#include <sys/cpu.h>
+#include <netinet/in.h>
+#include <lwip/api.h>
+#include "core.h"
+#include "fs.h"
+#include "pxe.h"
+#include "thread.h"
+#include "url.h"
+
+static int ftp_cmd_response(struct inode *inode, const char *cmd,
+ const char *cmd_arg,
+ uint8_t *pasv_data, int *pn_ptr)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ int c;
+ int pos, code;
+ int pb, pn;
+ bool ps;
+ bool first_line, done;
+ err_t err;
+ char cmd_buf[4096];
+ int cmd_len;
+ const char *p;
+ char *q;
+
+ if (cmd) {
+ cmd_len = strlcpy(cmd_buf, cmd, sizeof cmd_buf);
+ if (cmd_len >= sizeof cmd_buf - 3)
+ return -1;
+ q = cmd_buf + cmd_len;
+
+ if (cmd_arg) {
+ p = cmd_arg;
+
+ *q++ = ' ';
+ cmd_len++;
+ while (*p) {
+ if (++cmd_len < sizeof cmd_buf) *q++ = *p;
+ if (*p == '\r')
+ if (++cmd_len < sizeof cmd_buf) *q++ = '\0';
+ p++;
+ }
+
+ if (cmd_len >= sizeof cmd_buf - 2)
+ return -1;
+ }
+
+ *q++ = '\r';
+ *q++ = '\n';
+ cmd_len += 2;
+
+ err = netconn_write(socket->private.conn, cmd_buf, cmd_len, NETCONN_COPY);
+ if (err)
+ return -1;
+ }
+
+ pos = code = pn = pb = 0;
+ ps = false;
+ first_line = true;
+ done = false;
+
+ while ((c = pxe_getc(inode)) >= 0) {
+ if (c == '\n') {
+ if (done) {
+ if (pn) {
+ pn += ps;
+ if (pn_ptr)
+ *pn_ptr = pn;
+ }
+ return code;
+ }
+ pos = code = 0;
+ first_line = false;
+ continue;
+ }
+
+ switch (pos++) {
+ case 0:
+ case 1:
+ case 2:
+ if (c < '0' || c > '9') {
+ if (first_line)
+ return -1;
+ else
+ pos = 4; /* Skip this line */
+ } else {
+ code = (code*10) + (c - '0');
+ }
+ break;
+
+ case 3:
+ pn = pb = 0;
+ ps = false;
+ if (c == ' ')
+ done = true;
+ else if (c == '-')
+ done = false;
+ else if (first_line)
+ return -1;
+ else
+ done = false;
+ break;
+
+ default:
+ if (pasv_data) {
+ if (c >= '0' && c <= '9') {
+ pb = (pb*10) + (c-'0');
+ if (pn < 6)
+ pasv_data[pn] = pb;
+ ps = true;
+ } else if (c == ',') {
+ pn++;
+ pb = 0;
+ ps = false;
+ } else if (pn) {
+ pn += ps;
+ if (pn_ptr)
+ *pn_ptr = pn;
+ pn = pb = 0;
+ ps = false;
+ }
+ }
+ break;
+ }
+ }
+
+ return -1;
+}
+
+static void ftp_free(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ if (socket->ctl) {
+ tcp_close_file(socket->ctl);
+ free_socket(socket->ctl);
+ socket->ctl = NULL;
+ }
+ tcp_close_file(inode);
+}
+
+static void ftp_close_file(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ struct pxe_pvt_inode *ctlsock;
+ int resp;
+
+ ctlsock = socket->ctl ? PVT(socket->ctl) : NULL;
+ if (ctlsock->private.conn) {
+ resp = ftp_cmd_response(socket->ctl, "QUIT", NULL, NULL, NULL);
+ while (resp == 226) {
+ resp = ftp_cmd_response(socket->ctl, NULL, NULL, NULL, NULL);
+ }
+ }
+ ftp_free(inode);
+}
+
+static const struct pxe_conn_ops ftp_conn_ops = {
+ .fill_buffer = tcp_fill_buffer,
+ .close = ftp_close_file,
+ .readdir = ftp_readdir,
+};
+
+void ftp_open(struct url_info *url, int flags, struct inode *inode,
+ const char **redir)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ struct pxe_pvt_inode *ctlsock;
+ struct ip_addr addr;
+ uint8_t pasv_data[6];
+ int pasv_bytes;
+ int resp;
+ err_t err;
+
+ (void)redir; /* FTP does not redirect */
+
+ inode->size = 0;
+
+ if (!url->port)
+ url->port = 21;
+
+ url_unescape(url->path, 0);
+
+ socket->ops = &ftp_conn_ops;
+
+ /* Set up the control connection */
+ socket->ctl = alloc_inode(inode->fs, 0, sizeof(struct pxe_pvt_inode));
+ if (!socket->ctl)
+ return;
+ ctlsock = PVT(socket->ctl);
+ ctlsock->ops = &tcp_conn_ops; /* The control connection is just TCP */
+ ctlsock->private.conn = netconn_new(NETCONN_TCP);
+ if (!ctlsock->private.conn)
+ goto err_free;
+ addr.addr = url->ip;
+ err = netconn_connect(ctlsock->private.conn, &addr, url->port);
+ if (err)
+ goto err_delete;
+
+ do {
+ resp = ftp_cmd_response(socket->ctl, NULL, NULL, NULL, NULL);
+ } while (resp == 120);
+ if (resp != 220)
+ goto err_disconnect;
+
+ if (!url->user)
+ url->user = "anonymous";
+ if (!url->passwd)
+ url->passwd = "syslinux@";
+
+ resp = ftp_cmd_response(socket->ctl, "USER", url->user, NULL, NULL);
+ if (resp != 202 && resp != 230) {
+ if (resp != 331)
+ goto err_disconnect;
+
+ resp = ftp_cmd_response(socket->ctl, "PASS", url->passwd, NULL, NULL);
+ if (resp != 230)
+ goto err_disconnect;
+ }
+
+ if (!(flags & O_DIRECTORY)) {
+ resp = ftp_cmd_response(socket->ctl, "TYPE", "I", NULL, NULL);
+ if (resp != 200)
+ goto err_disconnect;
+ }
+
+ resp = ftp_cmd_response(socket->ctl, "PASV", NULL, pasv_data, &pasv_bytes);
+ if (resp != 227 || pasv_bytes != 6)
+ goto err_disconnect;
+
+ socket->private.conn = netconn_new(NETCONN_TCP);
+ if (!socket->private.conn)
+ goto err_disconnect;
+ err = netconn_connect(socket->private.conn, (struct ip_addr *)&pasv_data[0],
+ ntohs(*(uint16_t *)&pasv_data[4]));
+ if (err)
+ goto err_disconnect;
+
+ resp = ftp_cmd_response(socket->ctl,
+ (flags & O_DIRECTORY) ? "LIST" : "RETR",
+ url->path, NULL, NULL);
+ if (resp != 125 && resp != 150)
+ goto err_disconnect;
+
+ inode->size = -1;
+ return; /* Sucess! */
+
+err_disconnect:
+ if (ctlsock->private.conn)
+ netconn_write(ctlsock->private.conn, "QUIT\r\n", 6, NETCONN_NOCOPY);
+ if (socket->private.conn)
+ netconn_delete(socket->private.conn);
+ if (ctlsock->private.buf)
+ netbuf_delete(ctlsock->private.buf);
+err_delete:
+ if (ctlsock->private.conn)
+ netconn_delete(ctlsock->private.conn);
+err_free:
+ free_socket(socket->ctl);
+}
diff --git a/core/fs/pxe/ftp_readdir.c b/core/fs/pxe/ftp_readdir.c
new file mode 100644
index 00000000..6b87f77e
--- /dev/null
+++ b/core/fs/pxe/ftp_readdir.c
@@ -0,0 +1,141 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * ftp_readdir.c
+ */
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <dprintf.h>
+#include "pxe.h"
+
+static int dirtype(char type)
+{
+ switch (type) {
+ case 'f':
+ return DT_FIFO;
+ case 'c':
+ return DT_CHR;
+ case 'd':
+ return DT_DIR;
+ case 'b':
+ return DT_BLK;
+ case '-':
+ case '0' ... '9': /* Some DOS FTP stacks */
+ return DT_REG;
+ case 'l':
+ return DT_LNK;
+ case 's':
+ return DT_SOCK;
+ default:
+ return DT_UNKNOWN;
+ }
+}
+
+int ftp_readdir(struct inode *inode, struct dirent *dirent)
+{
+ char bufs[2][FILENAME_MAX + 1];
+ int nbuf = 0;
+ char *buf = bufs[nbuf];
+ char *p = buf;
+ char *name = NULL;
+ char type;
+ int c;
+ int dt;
+ bool was_cr = false;
+ bool first = true;
+
+ for (;;) {
+ type = 0;
+
+ for (;;) {
+ c = pxe_getc(inode);
+ if (c == -1)
+ return -1; /* Nothing else there */
+
+ if (c == '\r') {
+ was_cr = true;
+ continue;
+ }
+ if (was_cr) {
+ if (c == '\n') {
+ if (!name) {
+ *p = '\0';
+ name = buf;
+ }
+ break; /* End of line */
+ }
+ else if (c == '\0')
+ c = '\r';
+ }
+ was_cr = false;
+
+ if (c == ' ' || c == '\t') {
+ if (!name) {
+ *p = '\0';
+ if (first) {
+ if (p == buf) {
+ /* Name started with whitespace - skip line */
+ name = buf;
+ } else if ((p = strchr(buf, ';'))) {
+ /* VMS/Multinet format */
+ if (p > buf+4 && !memcmp(p-4, ".DIR", 4)) {
+ type = 'd';
+ p -= 4;
+ } else {
+ type = 'f';
+ }
+ *p = '\0';
+ name = buf;
+ } else {
+ type = buf[0];
+ }
+ first = false;
+ } else {
+ /* Not the first word */
+ if ((type >= '0' && type <= '9') &&
+ !strcmp(buf, "<DIR>")) {
+ /* Some DOS FTP servers */
+ type = 'd';
+ } else if (type == 'l' && !strcmp(buf, "->")) {
+ /* The name was the previous word */
+ name = bufs[nbuf ^ 1];
+ }
+ }
+ nbuf ^= 1;
+ p = buf = bufs[nbuf];
+ }
+ } else {
+ if (!name && p < buf + FILENAME_MAX)
+ *p++ = c;
+ }
+ }
+
+ dt = dirtype(type);
+ if (dt != DT_UNKNOWN) {
+ size_t len = strlen(name);
+
+ if (len <= NAME_MAX) {
+ dirent->d_type = dt;
+ dirent->d_ino = 0; /* Not applicable */
+ dirent->d_off = 0; /* Not applicable */
+ dirent->d_reclen = offsetof(struct dirent, d_name) + len+1;
+ memcpy(dirent->d_name, name, len+1);
+ return 0;
+ }
+ }
+
+ /* Otherwise try the next line... */
+ }
+}
diff --git a/core/fs/pxe/gpxeurl.c b/core/fs/pxe/gpxeurl.c
new file mode 100644
index 00000000..6bbae3c2
--- /dev/null
+++ b/core/fs/pxe/gpxeurl.c
@@ -0,0 +1,88 @@
+#include "pxe.h"
+#if GPXE
+
+static void gpxe_close_file(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ static __lowmem struct s_PXENV_FILE_CLOSE file_close;
+
+ file_close.FileHandle = socket->tftp_remoteport;
+ pxe_call(PXENV_FILE_CLOSE, &file_close);
+}
+
+/**
+ * Get a fresh packet from a gPXE socket
+ * @param: inode -> Inode pointer
+ *
+ */
+static void gpxe_get_packet(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ static __lowmem struct s_PXENV_FILE_READ file_read;
+ int err;
+
+ while (1) {
+ file_read.FileHandle = socket->tftp_remoteport;
+ file_read.Buffer = FAR_PTR(packet_buf);
+ file_read.BufferSize = PKTBUF_SIZE;
+ err = pxe_call(PXENV_FILE_READ, &file_read);
+ if (!err) /* successed */
+ break;
+
+ if (file_read.Status != PXENV_STATUS_TFTP_OPEN)
+ kaboom();
+ }
+
+ memcpy(socket->tftp_pktbuf, packet_buf, file_read.BufferSize);
+
+ socket->tftp_dataptr = socket->tftp_pktbuf;
+ socket->tftp_bytesleft = file_read.BufferSize;
+ socket->tftp_filepos += file_read.BufferSize;
+
+ if (socket->tftp_bytesleft == 0)
+ inode->size = socket->tftp_filepos;
+
+ /* if we're done here, close the file */
+ if (inode->size > socket->tftp_filepos)
+ return;
+
+ /* Got EOF, close it */
+ socket->tftp_goteof = 1;
+ gpxe_close_file(inode);
+}
+
+/**
+ * Open a url using gpxe
+ *
+ * @param:inode, the inode to store our state in
+ * @param:url, the url we want to open
+ *
+ * @out: open_file_t structure, stores in file->open_file
+ * @out: the lenght of this file, stores in file->file_len
+ *
+ */
+void gpxe_open(struct inode *inode, const char *url)
+{
+ static __lowmem struct s_PXENV_FILE_OPEN file_open;
+ static char lowurl[2*FILENAME_MAX];
+ struct pxe_pvt_inode *socket = PVT(inode);
+ int err;
+
+ socket->tftp_pktbuf = malloc(PKTBUF_SIZE);
+ if (!socket->tftp_pktbuf)
+ return;
+
+ snprintf(lowurl, sizeof lowurl, "%s", url);
+ file_open.Status = PXENV_STATUS_BAD_FUNC;
+ file_open.FileName = FAR_PTR(lowurl);
+ err = pxe_call(PXENV_FILE_OPEN, &file_open);
+ if (err)
+ return;
+
+ socket->fill_buffer = gpxe_get_packet;
+ socket->close = gpxe_close_file;
+ socket->tftp_remoteport = file_open.FileHandle;
+ inode->size = -1; /* This is not an error */
+}
+
+#endif /* GPXE */
diff --git a/core/fs/pxe/http.c b/core/fs/pxe/http.c
new file mode 100644
index 00000000..cc139b68
--- /dev/null
+++ b/core/fs/pxe/http.c
@@ -0,0 +1,400 @@
+#include <syslinux/sysappend.h>
+#include <ctype.h>
+#include <lwip/api.h>
+#include "pxe.h"
+#include "version.h"
+#include "url.h"
+
+#define HTTP_PORT 80
+
+static bool is_tspecial(int ch)
+{
+ bool tspecial = false;
+ switch(ch) {
+ case '(': case ')': case '<': case '>': case '@':
+ case ',': case ';': case ':': case '\\': case '"':
+ case '/': case '[': case ']': case '?': case '=':
+ case '{': case '}': case ' ': case '\t':
+ tspecial = true;
+ break;
+ }
+ return tspecial;
+}
+
+static bool is_ctl(int ch)
+{
+ return ch < 0x20;
+}
+
+static bool is_token(int ch)
+{
+ /* Can by antying except a ctl character or a tspecial */
+ return !is_ctl(ch) && !is_tspecial(ch);
+}
+
+static bool append_ch(char *str, size_t size, size_t *pos, int ch)
+{
+ bool success = true;
+ if ((*pos + 1) >= size) {
+ *pos = 0;
+ success = false;
+ } else {
+ str[*pos] = ch;
+ str[*pos + 1] = '\0';
+ *pos += 1;
+ }
+ return success;
+}
+
+static size_t cookie_len, header_len;
+static char *cookie_buf, *header_buf;
+
+__export uint32_t SendCookies = -1UL; /* Send all cookies */
+
+static size_t http_do_bake_cookies(char *q)
+{
+ static const char uchexchar[16] = "0123456789ABCDEF";
+ int i;
+ size_t n = 0;
+ const char *p;
+ char c;
+ bool first = true;
+ uint32_t mask = SendCookies;
+
+ for (i = 0; i < SYSAPPEND_MAX; i++) {
+ if ((mask & 1) && (p = sysappend_strings[i])) {
+ if (first) {
+ if (q) {
+ strcpy(q, "Cookie: ");
+ q += 8;
+ }
+ n += 8;
+ first = false;
+ }
+ if (q) {
+ strcpy(q, "_Syslinux_");
+ q += 10;
+ }
+ n += 10;
+ /* Copy string up to and including '=' */
+ do {
+ c = *p++;
+ if (q)
+ *q++ = c;
+ n++;
+ } while (c != '=');
+ while ((c = *p++)) {
+ if (c == ' ') {
+ if (q)
+ *q++ = '+';
+ n++;
+ } else if (is_token(c)) {
+ if (q)
+ *q++ = c;
+ n++;
+ } else {
+ if (q) {
+ *q++ = '%';
+ *q++ = uchexchar[c >> 4];
+ *q++ = uchexchar[c & 15];
+ }
+ n += 3;
+ }
+ }
+ if (q)
+ *q++ = ';';
+ n++;
+ }
+ mask >>= 1;
+ }
+ if (!first) {
+ if (q) {
+ *q++ = '\r';
+ *q++ = '\n';
+ }
+ n += 2;
+ }
+ if (q)
+ *q = '\0';
+
+ return n;
+}
+
+void http_bake_cookies(void)
+{
+ if (cookie_buf)
+ free(cookie_buf);
+
+ cookie_len = http_do_bake_cookies(NULL);
+ cookie_buf = malloc(cookie_len+1);
+ if (!cookie_buf) {
+ cookie_len = 0;
+ return;
+ }
+
+ if (header_buf)
+ free(header_buf);
+
+ header_len = cookie_len + 6*FILENAME_MAX + 256;
+ header_buf = malloc(header_len);
+ if (!header_buf) {
+ header_len = 0;
+ return; /* Uh-oh... */
+ }
+
+ http_do_bake_cookies(cookie_buf);
+}
+
+static const struct pxe_conn_ops http_conn_ops = {
+ .fill_buffer = tcp_fill_buffer,
+ .close = tcp_close_file,
+ .readdir = http_readdir,
+};
+
+void http_open(struct url_info *url, int flags, struct inode *inode,
+ const char **redir)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ int header_bytes;
+ const char *next;
+ char field_name[20];
+ char field_value[1024];
+ size_t field_name_len, field_value_len;
+ err_t err;
+ enum state {
+ st_httpver,
+ st_stcode,
+ st_skipline,
+ st_fieldfirst,
+ st_fieldname,
+ st_fieldvalue,
+ st_skip_fieldname,
+ st_skip_fieldvalue,
+ st_eoh,
+ } state;
+ struct ip_addr addr;
+ static char location[FILENAME_MAX];
+ uint32_t content_length; /* same as inode->size */
+ size_t response_size;
+ int status;
+ int pos;
+
+ (void)flags;
+
+ if (!header_buf)
+ return; /* http is broken... */
+
+ /* This is a straightforward TCP connection after headers */
+ socket->ops = &http_conn_ops;
+
+ /* Reset all of the variables */
+ inode->size = content_length = -1;
+
+ /* Start the http connection */
+ socket->private.conn = netconn_new(NETCONN_TCP);
+ if (!socket->private.conn) {
+ printf("netconn_new failed\n");
+ return;
+ }
+
+ addr.addr = url->ip;
+ if (!url->port)
+ url->port = HTTP_PORT;
+
+ err = netconn_connect(socket->private.conn, &addr, url->port);
+ if (err) {
+ printf("netconn_connect error %d\n", err);
+ goto fail;
+ }
+
+ strcpy(header_buf, "GET /");
+ header_bytes = 5;
+ header_bytes += url_escape_unsafe(header_buf+5, url->path,
+ header_len - 5);
+ if (header_bytes >= header_len)
+ goto fail; /* Buffer overflow */
+ header_bytes += snprintf(header_buf + header_bytes,
+ header_len - header_bytes,
+ " HTTP/1.0\r\n"
+ "Host: %s\r\n"
+ "User-Agent: Syslinux/" VERSION_STR "\r\n"
+ "Connection: close\r\n"
+ "%s"
+ "\r\n",
+ url->host, cookie_buf ? cookie_buf : "");
+ if (header_bytes >= header_len)
+ goto fail; /* Buffer overflow */
+
+ err = netconn_write(socket->private.conn, header_buf,
+ header_bytes, NETCONN_NOCOPY);
+ if (err) {
+ printf("netconn_write error %d\n", err);
+ goto fail;
+ }
+
+ /* Parse the HTTP header */
+ state = st_httpver;
+ pos = 0;
+ status = 0;
+ response_size = 0;
+ field_value_len = 0;
+ field_name_len = 0;
+
+ while (state != st_eoh) {
+ int ch = pxe_getc(inode);
+ /* Eof before I finish paring the header */
+ if (ch == -1)
+ goto fail;
+#if 0
+ printf("%c", ch);
+#endif
+ response_size++;
+ if (ch == '\r' || ch == '\0')
+ continue;
+ switch (state) {
+ case st_httpver:
+ if (ch == ' ') {
+ state = st_stcode;
+ pos = 0;
+ }
+ break;
+
+ case st_stcode:
+ if (ch < '0' || ch > '9')
+ goto fail;
+ status = (status*10) + (ch - '0');
+ if (++pos == 3)
+ state = st_skipline;
+ break;
+
+ case st_skipline:
+ if (ch == '\n')
+ state = st_fieldfirst;
+ break;
+
+ case st_fieldfirst:
+ if (ch == '\n')
+ state = st_eoh;
+ else if (isspace(ch)) {
+ /* A continuation line */
+ state = st_fieldvalue;
+ goto fieldvalue;
+ }
+ else if (is_token(ch)) {
+ /* Process the previous field before starting on the next one */
+ if (strcasecmp(field_name, "Content-Length") == 0) {
+ next = field_value;
+ /* Skip leading whitespace */
+ while (isspace(*next))
+ next++;
+ content_length = 0;
+ for (;(*next >= '0' && *next <= '9'); next++) {
+ if ((content_length * 10) < content_length)
+ break;
+ content_length = (content_length * 10) + (*next - '0');
+ }
+ /* In the case of overflow or other error ignore
+ * Content-Length.
+ */
+ if (*next)
+ content_length = -1;
+ }
+ else if (strcasecmp(field_name, "Location") == 0) {
+ next = field_value;
+ /* Skip leading whitespace */
+ while (isspace(*next))
+ next++;
+ strlcpy(location, next, sizeof location);
+ }
+ /* Start the field name and field value afress */
+ field_name_len = 1;
+ field_name[0] = ch;
+ field_name[1] = '\0';
+ field_value_len = 0;
+ field_value[0] = '\0';
+ state = st_fieldname;
+ }
+ else /* Bogus try to recover */
+ state = st_skipline;
+ break;
+
+ case st_fieldname:
+ if (ch == ':' ) {
+ state = st_fieldvalue;
+ }
+ else if (is_token(ch)) {
+ if (!append_ch(field_name, sizeof field_name, &field_name_len, ch))
+ state = st_skip_fieldname;
+ }
+ /* Bogus cases try to recover */
+ else if (ch == '\n')
+ state = st_fieldfirst;
+ else
+ state = st_skipline;
+ break;
+
+ case st_fieldvalue:
+ if (ch == '\n')
+ state = st_fieldfirst;
+ else {
+ fieldvalue:
+ if (!append_ch(field_value, sizeof field_value, &field_value_len, ch))
+ state = st_skip_fieldvalue;
+ }
+ break;
+
+ /* For valid fields whose names are longer than I choose to support. */
+ case st_skip_fieldname:
+ if (ch == ':')
+ state = st_skip_fieldvalue;
+ else if (is_token(ch))
+ state = st_skip_fieldname;
+ /* Bogus cases try to recover */
+ else if (ch == '\n')
+ state = st_fieldfirst;
+ else
+ state = st_skipline;
+ break;
+
+ /* For valid fields whose bodies are longer than I choose to support. */
+ case st_skip_fieldvalue:
+ if (ch == '\n')
+ state = st_fieldfirst;
+ break;
+
+ case st_eoh:
+ break; /* Should never happen */
+ }
+ }
+
+ if (state != st_eoh)
+ status = 0;
+
+ switch (status) {
+ case 200:
+ /*
+ * All OK, need to mark header data consumed and set up a file
+ * structure...
+ */
+ /* Treat the remainder of the bytes as data */
+ socket->tftp_filepos -= response_size;
+ break;
+ case 301:
+ case 302:
+ case 303:
+ case 307:
+ /* A redirect */
+ if (!location[0])
+ goto fail;
+ *redir = location;
+ goto fail;
+ default:
+ goto fail;
+ break;
+ }
+ return;
+fail:
+ inode->size = 0;
+ tcp_close_file(inode);
+ return;
+}
diff --git a/core/fs/pxe/http_readdir.c b/core/fs/pxe/http_readdir.c
new file mode 100644
index 00000000..b6e480e7
--- /dev/null
+++ b/core/fs/pxe/http_readdir.c
@@ -0,0 +1,471 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <dprintf.h>
+#include "pxe.h"
+
+enum http_readdir_state {
+ st_start, /* 0 Initial state */
+ st_open, /* 1 "<" */
+ st_a, /* 2 "<a" */
+ st_attribute, /* 3 "<a " */
+ st_h, /* 4 "<a h" */
+ st_hr, /* 5 */
+ st_hre, /* 6 */
+ st_href, /* 7 */
+ st_hrefeq, /* 8 */
+ st_hrefqu, /* 9 */
+ st_badtag, /* 10 */
+ st_badtagqu, /* 11 */
+ st_badattr, /* 12 */
+ st_badattrqu, /* 13 */
+};
+
+struct machine {
+ char xchar;
+ uint8_t st_xchar;
+ uint8_t st_left; /* < */
+ uint8_t st_right; /* > */
+ uint8_t st_space; /* white */
+ uint8_t st_other; /* anything else */
+};
+
+static const struct machine statemachine[] = {
+ /* xchar st_xchar st_left st_right st_space st_other */
+ { 0, 0, st_open, st_start, st_start, st_start },
+ { 'a', st_a, st_badtag, st_start, st_open, st_badtag },
+ { 0, 0, st_open, st_open, st_attribute, st_badtag },
+ { 'h', st_h, st_open, st_start, st_attribute, st_badattr },
+ { 'r', st_hr, st_open, st_start, st_attribute, st_badattr },
+ { 'e', st_hre, st_open, st_start, st_attribute, st_badattr },
+ { 'f', st_href, st_open, st_start, st_attribute, st_badattr },
+ { '=', st_hrefeq, st_open, st_start, st_attribute, st_badattr },
+ { '\"', st_hrefqu, st_open, st_start, st_attribute, st_hrefeq },
+ { '\"', st_attribute, st_hrefqu, st_hrefqu, st_hrefqu, st_hrefqu },
+ { '\"', st_badtagqu, st_open, st_start, st_badtag, st_badtag },
+ { '\"', st_badtag, st_badtagqu, st_badtagqu, st_badtagqu, st_badtagqu },
+ { '\"', st_badattrqu, st_open, st_start, st_attribute, st_badattr },
+ { '\"', st_attribute, st_badattrqu, st_badattrqu, st_badattrqu, st_badattrqu },
+};
+
+struct html_entity {
+ uint16_t ucs;
+ const char entity[9];
+};
+
+static const struct html_entity entities[] = {
+ { 34, "quot" },
+ { 38, "amp" },
+ { 60, "lt" },
+ { 62, "gt" },
+#ifdef HTTP_ALL_ENTITIES
+ { 160, "nbsp" },
+ { 161, "iexcl" },
+ { 162, "cent" },
+ { 163, "pound" },
+ { 164, "curren" },
+ { 165, "yen" },
+ { 166, "brvbar" },
+ { 167, "sect" },
+ { 168, "uml" },
+ { 169, "copy" },
+ { 170, "ordf" },
+ { 171, "laquo" },
+ { 172, "not" },
+ { 173, "shy" },
+ { 174, "reg" },
+ { 175, "macr" },
+ { 176, "deg" },
+ { 177, "plusmn" },
+ { 178, "sup2" },
+ { 179, "sup3" },
+ { 180, "acute" },
+ { 181, "micro" },
+ { 182, "para" },
+ { 183, "middot" },
+ { 184, "cedil" },
+ { 185, "sup1" },
+ { 186, "ordm" },
+ { 187, "raquo" },
+ { 188, "frac14" },
+ { 189, "frac12" },
+ { 190, "frac34" },
+ { 191, "iquest" },
+ { 192, "Agrave" },
+ { 193, "Aacute" },
+ { 194, "Acirc" },
+ { 195, "Atilde" },
+ { 196, "Auml" },
+ { 197, "Aring" },
+ { 198, "AElig" },
+ { 199, "Ccedil" },
+ { 200, "Egrave" },
+ { 201, "Eacute" },
+ { 202, "Ecirc" },
+ { 203, "Euml" },
+ { 204, "Igrave" },
+ { 205, "Iacute" },
+ { 206, "Icirc" },
+ { 207, "Iuml" },
+ { 208, "ETH" },
+ { 209, "Ntilde" },
+ { 210, "Ograve" },
+ { 211, "Oacute" },
+ { 212, "Ocirc" },
+ { 213, "Otilde" },
+ { 214, "Ouml" },
+ { 215, "times" },
+ { 216, "Oslash" },
+ { 217, "Ugrave" },
+ { 218, "Uacute" },
+ { 219, "Ucirc" },
+ { 220, "Uuml" },
+ { 221, "Yacute" },
+ { 222, "THORN" },
+ { 223, "szlig" },
+ { 224, "agrave" },
+ { 225, "aacute" },
+ { 226, "acirc" },
+ { 227, "atilde" },
+ { 228, "auml" },
+ { 229, "aring" },
+ { 230, "aelig" },
+ { 231, "ccedil" },
+ { 232, "egrave" },
+ { 233, "eacute" },
+ { 234, "ecirc" },
+ { 235, "euml" },
+ { 236, "igrave" },
+ { 237, "iacute" },
+ { 238, "icirc" },
+ { 239, "iuml" },
+ { 240, "eth" },
+ { 241, "ntilde" },
+ { 242, "ograve" },
+ { 243, "oacute" },
+ { 244, "ocirc" },
+ { 245, "otilde" },
+ { 246, "ouml" },
+ { 247, "divide" },
+ { 248, "oslash" },
+ { 249, "ugrave" },
+ { 250, "uacute" },
+ { 251, "ucirc" },
+ { 252, "uuml" },
+ { 253, "yacute" },
+ { 254, "thorn" },
+ { 255, "yuml" },
+ { 338, "OElig" },
+ { 339, "oelig" },
+ { 352, "Scaron" },
+ { 353, "scaron" },
+ { 376, "Yuml" },
+ { 402, "fnof" },
+ { 710, "circ" },
+ { 732, "tilde" },
+ { 913, "Alpha" },
+ { 914, "Beta" },
+ { 915, "Gamma" },
+ { 916, "Delta" },
+ { 917, "Epsilon" },
+ { 918, "Zeta" },
+ { 919, "Eta" },
+ { 920, "Theta" },
+ { 921, "Iota" },
+ { 922, "Kappa" },
+ { 923, "Lambda" },
+ { 924, "Mu" },
+ { 925, "Nu" },
+ { 926, "Xi" },
+ { 927, "Omicron" },
+ { 928, "Pi" },
+ { 929, "Rho" },
+ { 931, "Sigma" },
+ { 932, "Tau" },
+ { 933, "Upsilon" },
+ { 934, "Phi" },
+ { 935, "Chi" },
+ { 936, "Psi" },
+ { 937, "Omega" },
+ { 945, "alpha" },
+ { 946, "beta" },
+ { 947, "gamma" },
+ { 948, "delta" },
+ { 949, "epsilon" },
+ { 950, "zeta" },
+ { 951, "eta" },
+ { 952, "theta" },
+ { 953, "iota" },
+ { 954, "kappa" },
+ { 955, "lambda" },
+ { 956, "mu" },
+ { 957, "nu" },
+ { 958, "xi" },
+ { 959, "omicron" },
+ { 960, "pi" },
+ { 961, "rho" },
+ { 962, "sigmaf" },
+ { 963, "sigma" },
+ { 964, "tau" },
+ { 965, "upsilon" },
+ { 966, "phi" },
+ { 967, "chi" },
+ { 968, "psi" },
+ { 969, "omega" },
+ { 977, "thetasym" },
+ { 978, "upsih" },
+ { 982, "piv" },
+ { 8194, "ensp" },
+ { 8195, "emsp" },
+ { 8201, "thinsp" },
+ { 8204, "zwnj" },
+ { 8205, "zwj" },
+ { 8206, "lrm" },
+ { 8207, "rlm" },
+ { 8211, "ndash" },
+ { 8212, "mdash" },
+ { 8216, "lsquo" },
+ { 8217, "rsquo" },
+ { 8218, "sbquo" },
+ { 8220, "ldquo" },
+ { 8221, "rdquo" },
+ { 8222, "bdquo" },
+ { 8224, "dagger" },
+ { 8225, "Dagger" },
+ { 8226, "bull" },
+ { 8230, "hellip" },
+ { 8240, "permil" },
+ { 8242, "prime" },
+ { 8243, "Prime" },
+ { 8249, "lsaquo" },
+ { 8250, "rsaquo" },
+ { 8254, "oline" },
+ { 8260, "frasl" },
+ { 8364, "euro" },
+ { 8465, "image" },
+ { 8472, "weierp" },
+ { 8476, "real" },
+ { 8482, "trade" },
+ { 8501, "alefsym" },
+ { 8592, "larr" },
+ { 8593, "uarr" },
+ { 8594, "rarr" },
+ { 8595, "darr" },
+ { 8596, "harr" },
+ { 8629, "crarr" },
+ { 8656, "lArr" },
+ { 8657, "uArr" },
+ { 8658, "rArr" },
+ { 8659, "dArr" },
+ { 8660, "hArr" },
+ { 8704, "forall" },
+ { 8706, "part" },
+ { 8707, "exist" },
+ { 8709, "empty" },
+ { 8711, "nabla" },
+ { 8712, "isin" },
+ { 8713, "notin" },
+ { 8715, "ni" },
+ { 8719, "prod" },
+ { 8721, "sum" },
+ { 8722, "minus" },
+ { 8727, "lowast" },
+ { 8730, "radic" },
+ { 8733, "prop" },
+ { 8734, "infin" },
+ { 8736, "ang" },
+ { 8743, "and" },
+ { 8744, "or" },
+ { 8745, "cap" },
+ { 8746, "cup" },
+ { 8747, "int" },
+ { 8756, "there4" },
+ { 8764, "sim" },
+ { 8773, "cong" },
+ { 8776, "asymp" },
+ { 8800, "ne" },
+ { 8801, "equiv" },
+ { 8804, "le" },
+ { 8805, "ge" },
+ { 8834, "sub" },
+ { 8835, "sup" },
+ { 8836, "nsub" },
+ { 8838, "sube" },
+ { 8839, "supe" },
+ { 8853, "oplus" },
+ { 8855, "otimes" },
+ { 8869, "perp" },
+ { 8901, "sdot" },
+ { 8968, "lceil" },
+ { 8969, "rceil" },
+ { 8970, "lfloor" },
+ { 8971, "rfloor" },
+ { 9001, "lang" },
+ { 9002, "rang" },
+ { 9674, "loz" },
+ { 9824, "spades" },
+ { 9827, "clubs" },
+ { 9829, "hearts" },
+ { 9830, "diams" },
+#endif /* HTTP_ALL_ENTITIES */
+ { 0, "" }
+};
+
+struct entity_state {
+ char entity_buf[16];
+ char *ep;
+};
+
+static char *emit(char *p, int c, struct entity_state *st)
+{
+ const struct html_entity *ent;
+ unsigned int ucs;
+
+ if (!st->ep) {
+ if (c == '&') {
+ /* Entity open */
+ st->ep = st->entity_buf;
+ } else {
+ *p++ = c;
+ }
+ } else {
+ if (c == ';') {
+ st->ep = NULL;
+ *p = '\0';
+ if (st->entity_buf[0] == '#') {
+ if ((st->entity_buf[1] | 0x20)== 'x') {
+ ucs = strtoul(st->entity_buf + 2, NULL, 16);
+ } else {
+ ucs = strtoul(st->entity_buf + 1, NULL, 10);
+ }
+ } else {
+ for (ent = entities; ent->ucs; ent++) {
+ if (!strcmp(st->entity_buf, ent->entity))
+ break;
+ }
+ ucs = ent->ucs;
+ }
+ if (ucs < 32 || ucs >= 0x10ffff)
+ return p; /* Bogus */
+ if (ucs >= 0x10000) {
+ *p++ = 0xf0 + (ucs >> 18);
+ *p++ = 0x80 + ((ucs >> 12) & 0x3f);
+ *p++ = 0x80 + ((ucs >> 6) & 0x3f);
+ *p++ = 0x80 + (ucs & 0x3f);
+ } else if (ucs >= 0x800) {
+ *p++ = 0xe0 + (ucs >> 12);
+ *p++ = 0x80 + ((ucs >> 6) & 0x3f);
+ *p++ = 0x80 + (ucs & 0x3f);
+ } else if (ucs >= 0x80) {
+ *p++ = 0xc0 + (ucs >> 6);
+ *p++ = 0x80 + (ucs & 0x3f);
+ } else {
+ *p++ = ucs;
+ }
+ } else if (st->ep < st->entity_buf + sizeof st->entity_buf - 1) {
+ *st->ep++ = c;
+ }
+ }
+ return p;
+}
+
+static const char *http_get_filename(struct inode *inode, char *buf)
+{
+ int c, lc;
+ char *p;
+ const struct machine *sm;
+ struct entity_state es;
+ enum http_readdir_state state = st_start;
+ enum http_readdir_state pstate = st_start;
+
+ memset(&es, 0, sizeof es);
+
+ p = buf;
+ for (;;) {
+ c = pxe_getc(inode);
+ if (c == -1)
+ return NULL;
+
+ lc = tolower(c);
+
+ sm = &statemachine[state];
+
+ if (lc == sm->xchar)
+ state = sm->st_xchar;
+ else if (c == '<')
+ state = sm->st_left;
+ else if (c == '>')
+ state = sm->st_right;
+ else if (isspace(c))
+ state = sm->st_space;
+ else
+ state = sm->st_other;
+
+ if (state == st_hrefeq || state == st_hrefqu) {
+ if (state != pstate)
+ p = buf;
+ else if (p < buf + FILENAME_MAX)
+ p = emit(p, c, &es);
+ pstate = state;
+ } else {
+ if (pstate != st_start)
+ pstate = st_start;
+ if (p != buf && state == st_start) {
+ *p = '\0';
+ return buf;
+ }
+ }
+ }
+}
+
+int http_readdir(struct inode *inode, struct dirent *dirent)
+{
+ char buf[FILENAME_MAX + 6];
+ const char *fn, *sp;
+
+ for (;;) {
+ fn = http_get_filename(inode, buf);
+
+ if (!fn)
+ return -1; /* End of directory */
+
+ /* Ignore entries with http special characters */
+ if (strchr(fn, '#'))
+ continue;
+ if (strchr(fn, '?'))
+ continue;
+
+ /* A slash if present has to be the last character, and not the first */
+ sp = strchr(fn, '/');
+ if (sp) {
+ if (sp == fn || sp[1])
+ continue;
+ } else {
+ sp = strchr(fn, '\0');
+ }
+
+ if (sp > fn + NAME_MAX)
+ continue;
+
+ dirent->d_ino = 0; /* Not applicable */
+ dirent->d_off = 0; /* Not applicable */
+ dirent->d_reclen = offsetof(struct dirent, d_name) + (sp-fn) + 1;
+ dirent->d_type = *sp == '/' ? DT_DIR : DT_REG;
+ memcpy(dirent->d_name, fn, sp-fn);
+ dirent->d_name[sp-fn] = '\0';
+ return 0;
+ }
+}
diff --git a/core/fs/pxe/idle.c b/core/fs/pxe/idle.c
index 52a87c34..1d1bb8bc 100644
--- a/core/fs/pxe/idle.c
+++ b/core/fs/pxe/idle.c
@@ -19,91 +19,8 @@
#include <sys/cpu.h>
#include "pxe.h"
-static int pxe_idle_poll(void)
-{
- static __lowmem char junk_pkt[PKTBUF_SIZE];
- static __lowmem t_PXENV_UDP_READ read_buf;
-
- memset(&read_buf, 0, sizeof read_buf);
-
- read_buf.src_ip = 0; /* Any destination */
- 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;
- read_buf.buffer = FAR_PTR(junk_pkt);
-
- pxe_call(PXENV_UDP_READ, &read_buf);
-
- return 0;
-}
-
-static uint32_t pxe_detect_nic_type(void)
-{
- static __lowmem t_PXENV_UNDI_GET_NIC_TYPE nic_type;
-
- if (pxe_call(PXENV_UNDI_GET_NIC_TYPE, &nic_type))
- return -1; /* Unknown NIC */
-
- if (nic_type.NicType != PCI_NIC && nic_type.NicType != CardBus_NIC)
- return -1; /* Not a PCI NIC */
-
- /*
- * Return VID:DID as a single number, with the VID in the high word
- * -- this is opposite from the usual order, but it makes it easier to
- * enforce that the table is sorted.
- */
- return (nic_type.info.pci.Vendor_ID << 16) + nic_type.info.pci.Dev_ID;
-}
-
-#define PCI_DEV(vid, did) (((vid) << 16) + (did))
-
-/* This array should be sorted!! */
-static const uint32_t pxe_need_idle_drain[] =
-{
- /*
- * Older Broadcom NICs: they need receive calls on idle to avoid
- * FIFO stalls.
- */
- PCI_DEV(0x14e4, 0x1659), /* BCM5721 */
- PCI_DEV(0x14e4, 0x165a), /* BCM5722 */
- PCI_DEV(0x14e4, 0x165b), /* BCM5723 */
- PCI_DEV(0x14e4, 0x1668), /* BCM5714 */
- PCI_DEV(0x14e4, 0x1669), /* BCM5714S */
- PCI_DEV(0x14e4, 0x166a), /* BCM5780 */
- PCI_DEV(0x14e4, 0x1673), /* BCM5755M */
- PCI_DEV(0x14e4, 0x1674), /* BCM5756ME */
- PCI_DEV(0x14e4, 0x1678), /* BCM5715 */
- PCI_DEV(0x14e4, 0x1679), /* BCM5715S */
- PCI_DEV(0x14e4, 0x167b), /* BCM5755 */
-};
-
void pxe_idle_init(void)
{
- uint32_t dev_id = pxe_detect_nic_type();
- int l, h;
- bool found;
-
- l = 0;
- h = sizeof pxe_need_idle_drain / sizeof pxe_need_idle_drain[0] - 1;
-
- found = false;
- while (h >= l) {
- int x = (l+h) >> 1;
- uint32_t id = pxe_need_idle_drain[x];
-
- if (id == dev_id) {
- found = true;
- break;
- } else if (id < dev_id) {
- l = x+1;
- } else {
- h = x-1;
- }
- }
-
- if (found)
- idle_hook_func = pxe_idle_poll;
}
void pxe_idle_cleanup(void)
diff --git a/core/fs/pxe/isr.c b/core/fs/pxe/isr.c
new file mode 100644
index 00000000..069fefd5
--- /dev/null
+++ b/core/fs/pxe/isr.c
@@ -0,0 +1,278 @@
+/*
+ * core/fs/pxe/isr.c
+ *
+ * Stub invoked on return from real mode including from an interrupt.
+ * Interrupts are locked out on entry.
+ */
+
+#include "core.h"
+#include "thread.h"
+#include "pxe.h"
+#include <string.h>
+#include <sys/cpu.h>
+#include <sys/io.h>
+
+extern uint8_t pxe_irq_pending;
+extern volatile uint8_t pxe_need_poll;
+static DECLARE_INIT_SEMAPHORE(pxe_receive_thread_sem, 0);
+static DECLARE_INIT_SEMAPHORE(pxe_poll_thread_sem, 0);
+static struct thread *pxe_thread, *poll_thread;
+
+/*
+ * Note: this *must* be called with interrupts enabled.
+ */
+static bool install_irq_vector(uint8_t irq, void (*isr)(void), far_ptr_t *old)
+{
+ far_ptr_t *entry;
+ unsigned int vec;
+ uint8_t mask, mymask;
+ uint32_t now;
+ bool ok;
+
+ if (irq < 8)
+ vec = irq + 0x08;
+ else if (irq < 16)
+ vec = (irq - 8) + 0x70;
+ else
+ return false;
+
+ cli();
+
+ if (pxe_need_poll) {
+ sti();
+ return false;
+ }
+
+ entry = (far_ptr_t *)(vec << 2);
+ *old = *entry;
+ entry->ptr = (uint32_t)isr;
+
+ /* Enable this interrupt at the PIC level, just in case... */
+ mymask = ~(1 << (irq & 7));
+ if (irq >= 8) {
+ mask = inb(0x21);
+ mask &= ~(1 << 2); /* Enable cascade */
+ outb(mask, 0x21);
+ mask = inb(0xa1);
+ mask &= mymask;
+ outb(mask, 0xa1);
+ } else {
+ mask = inb(0x21);
+ mask &= mymask;
+ outb(mask, 0x21);
+ }
+
+ sti();
+
+ now = jiffies();
+
+ /* Some time to watch for stuck interrupts */
+ while (jiffies() - now < 4 && (ok = !pxe_need_poll))
+ hlt();
+
+ if (!ok)
+ *entry = *old; /* Restore the old vector */
+
+ printf("UNDI: IRQ %d(0x%02x): %04x:%04x -> %04x:%04x\n", irq, vec,
+ old->seg, old->offs, entry->seg, entry->offs);
+
+ return ok;
+}
+
+static bool uninstall_irq_vector(uint8_t irq, void (*isr), far_ptr_t *old)
+{
+ far_ptr_t *entry;
+ unsigned int vec;
+ bool rv;
+
+ if (!irq)
+ return true; /* Nothing to uninstall */
+
+ if (irq < 8)
+ vec = irq + 0x08;
+ else if (irq < 16)
+ vec = (irq - 8) + 0x70;
+ else
+ return false;
+
+ cli();
+
+ entry = (far_ptr_t *)(vec << 2);
+
+ if (entry->ptr != (uint32_t)isr) {
+ rv = false;
+ } else {
+ *entry = *old;
+ rv = true;
+ }
+
+ sti();
+ return rv;
+}
+
+static void pxe_poll_wakeups(void)
+{
+ static jiffies_t last_jiffies = 0;
+ jiffies_t now = jiffies();
+
+ if (pxe_need_poll == 1) {
+ /* If we need polling now, activate polling */
+ pxe_need_poll = 3;
+ sem_up(&pxe_poll_thread_sem);
+ }
+
+ if (now != last_jiffies) {
+ last_jiffies = now;
+ __thread_process_timeouts();
+ }
+
+ if (pxe_irq_pending) {
+ pxe_irq_pending = 0;
+ sem_up(&pxe_receive_thread_sem);
+ }
+}
+
+static void pxe_process_irq(void)
+{
+ static __lowmem t_PXENV_UNDI_ISR isr;
+
+ uint16_t func = PXENV_UNDI_ISR_IN_PROCESS; /* First time */
+ bool done = false;
+
+ while (!done) {
+ memset(&isr, 0, sizeof isr);
+ isr.FuncFlag = func;
+ func = PXENV_UNDI_ISR_IN_GET_NEXT; /* Next time */
+
+ pxe_call(PXENV_UNDI_ISR, &isr);
+
+ switch (isr.FuncFlag) {
+ case PXENV_UNDI_ISR_OUT_DONE:
+ done = true;
+ break;
+
+ case PXENV_UNDI_ISR_OUT_TRANSMIT:
+ /* Transmit complete - nothing for us to do */
+ break;
+
+ case PXENV_UNDI_ISR_OUT_RECEIVE:
+ undiif_input(&isr);
+ break;
+
+ case PXENV_UNDI_ISR_OUT_BUSY:
+ /* ISR busy, this should not happen */
+ done = true;
+ break;
+
+ default:
+ /* Invalid return code, this should not happen */
+ done = true;
+ break;
+ }
+ }
+}
+
+static void pxe_receive_thread(void *dummy)
+{
+ (void)dummy;
+
+ for (;;) {
+ sem_down(&pxe_receive_thread_sem, 0);
+ pxe_process_irq();
+ }
+}
+
+static bool pxe_isr_poll(void)
+{
+ static __lowmem t_PXENV_UNDI_ISR isr;
+
+ isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
+ pxe_call(PXENV_UNDI_ISR, &isr);
+
+ return isr.FuncFlag == PXENV_UNDI_ISR_OUT_OURS;
+}
+
+static void pxe_poll_thread(void *dummy)
+{
+ (void)dummy;
+
+ /* Block indefinitely unless activated */
+ sem_down(&pxe_poll_thread_sem, 0);
+
+ for (;;) {
+ cli();
+ if (pxe_receive_thread_sem.count < 0 && pxe_isr_poll())
+ sem_up(&pxe_receive_thread_sem);
+ else
+ __schedule();
+ sti();
+ cpu_relax();
+ }
+}
+
+/*
+ * This does preparations and enables the PXE thread
+ */
+void pxe_init_isr(void)
+{
+ start_idle_thread();
+ sched_hook_func = pxe_poll_wakeups;
+ /*
+ * Run the pxe receive thread at elevated priority, since the UNDI
+ * stack is likely to have very limited memory available; therefore to
+ * avoid packet loss we need to move it into memory that we ourselves
+ * manage, as soon as possible.
+ */
+ core_pm_hook = __schedule;
+
+ pxe_thread = start_thread("pxe receive", 16384, -20,
+ pxe_receive_thread, NULL);
+}
+
+/*
+ * Actually start the interrupt routine inside the UNDI stack
+ */
+void pxe_start_isr(void)
+{
+ int irq = pxe_undi_info.IntNumber;
+
+ if (irq == 2)
+ irq = 9; /* IRQ 2 is really IRQ 9 */
+ else if (irq > 15)
+ irq = 0; /* Invalid IRQ */
+
+ pxe_irq_vector = irq;
+
+ if (irq) {
+ if (!install_irq_vector(irq, pxe_isr, &pxe_irq_chain))
+ irq = 0; /* Install failed or stuck interrupt */
+ }
+
+ poll_thread = start_thread("pxe poll", 4096, POLL_THREAD_PRIORITY,
+ pxe_poll_thread, NULL);
+
+ if (!irq || !(pxe_undi_iface.ServiceFlags & PXE_UNDI_IFACE_FLAG_IRQ))
+ asm volatile("orb $1,%0" : "+m" (pxe_need_poll));
+}
+
+int reset_pxe(void)
+{
+ static __lowmem struct s_PXENV_UNDI_CLOSE undi_close;
+
+ sched_hook_func = NULL;
+ core_pm_hook = core_pm_null_hook;
+ kill_thread(pxe_thread);
+
+ memset(&undi_close, 0, sizeof(undi_close));
+ pxe_call(PXENV_UNDI_CLOSE, &undi_close);
+
+ if (undi_close.Status)
+ printf("PXENV_UNDI_CLOSE failed: 0x%x\n", undi_close.Status);
+
+ if (pxe_irq_vector)
+ uninstall_irq_vector(pxe_irq_vector, pxe_isr, &pxe_irq_chain);
+ if (poll_thread)
+ kill_thread(poll_thread);
+
+ return undi_close.Status;
+}
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index ae44cffe..4d694a1f 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -5,10 +5,16 @@
#include <bios.h>
#include <fs.h>
#include <minmax.h>
+#include <fcntl.h>
#include <sys/cpu.h>
#include "pxe.h"
+#include "thread.h"
+#include "url.h"
+#include "tftp.h"
+#include <net.h>
-#define GPXE 1
+__lowmem t_PXENV_UNDI_GET_INFORMATION pxe_undi_info;
+__lowmem t_PXENV_UNDI_GET_IFACE_INFO pxe_undi_iface;
static uint16_t real_base_mem; /* Amount of DOS memory after freeing */
@@ -16,45 +22,26 @@ 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) /* 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 */
-char dot_quad_buf[16];
static bool has_gpxe;
static uint32_t gpxe_funcs;
bool have_uuid = false;
-/* Common receive buffer */
-static __lowmem char packet_buf[PKTBUF_SIZE] __aligned(16);
-
-const uint8_t TimeoutTable[] = {
- 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44,
- 53, 64, 77, 92, 110, 132, 159, 191, 229, 255, 255, 255, 255, 0
-};
-
-struct tftp_options {
- const char *str_ptr; /* string pointer */
- size_t offset; /* offset into socket structre */
-};
-
-#define IFIELD(x) offsetof(struct inode, x)
-#define PFIELD(x) (offsetof(struct inode, pvt) + \
- offsetof(struct pxe_pvt_inode, x))
-
-static const struct tftp_options tftp_options[] =
-{
- { "tsize", IFIELD(size) },
- { "blksize", PFIELD(tftp_blksize) },
+static struct url_scheme {
+ const char *name;
+ void (*open)(struct url_info *, int, struct inode *, const char **);
+ int ok_flags;
+} url_schemes[] = {
+ { "tftp", tftp_open, 0 },
+#ifdef IS_LPXELINUX
+ { "http", http_open, O_DIRECTORY },
+ { "ftp", ftp_open, O_DIRECTORY },
+#endif
+ { NULL, NULL, 0 },
};
-static const int tftp_nopts = sizeof tftp_options / sizeof tftp_options[0];
-
-static void tftp_error(struct inode *file, uint16_t errnum,
- const char *errstr);
+#define OK_FLAGS_MASK (O_DIRECTORY|O_WRONLY)
/*
* Allocate a local UDP port structure and assign it a local port number.
@@ -67,108 +54,35 @@ static struct inode *allocate_socket(struct fs_info *fs)
if (!inode) {
malloc_error("socket structure");
} 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;
}
-static void free_socket(struct inode *inode)
+void free_socket(struct inode *inode)
{
struct pxe_pvt_inode *socket = PVT(inode);
- free_port(socket->tftp_localport);
+ free(socket->tftp_pktbuf); /* If we allocated a buffer, free it now */
free_inode(inode);
}
-#if GPXE
-static void gpxe_close_file(struct inode *inode)
-{
- struct pxe_pvt_inode *socket = PVT(inode);
- static __lowmem struct s_PXENV_FILE_CLOSE file_close;
-
- file_close.FileHandle = socket->tftp_remoteport;
- pxe_call(PXENV_FILE_CLOSE, &file_close);
-}
-#endif
-
static void pxe_close_file(struct file *file)
{
struct inode *inode = file->inode;
struct pxe_pvt_inode *socket = PVT(inode);
+ if (!inode)
+ return;
+
if (!socket->tftp_goteof) {
-#if GPXE
- if (socket->tftp_localport == 0xffff) {
- gpxe_close_file(inode);
- } else
-#endif
- if (socket->tftp_localport != 0) {
- tftp_error(inode, 0, "No error, file close");
- }
+ socket->ops->close(inode);
}
free_socket(inode);
}
-/**
- * Take a nubmer of bytes in memory and convert to lower-case hxeadecimal
- *
- * @param: dst, output buffer
- * @param: src, input buffer
- * @param: count, number of bytes
- *
- */
-static void lchexbytes(char *dst, const void *src, int count)
-{
- uint8_t half;
- uint8_t c;
- const uint8_t *s = src;
-
- for(; count > 0; count--) {
- c = *s++;
- half = ((c >> 4) & 0x0f) + '0';
- *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half;
-
- half = (c & 0x0f) + '0';
- *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half;
- }
-}
-
-/*
- * just like the lchexbytes, except to upper-case
- *
- */
-static void uchexbytes(char *dst, const void *src, int count)
-{
- uint8_t half;
- uint8_t c;
- const uint8_t *s = src;
-
- for(; count > 0; count--) {
- c = *s++;
- half = ((c >> 4) & 0x0f) + '0';
- *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half;
-
- half = (c & 0x0f) + '0';
- *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half;
- }
-}
-
-/*
- * Parse a single hexadecimal byte, which must be complete (two
- * digits). This is used in URL parsing.
- */
-static int hexbyte(const char *p)
-{
- if (!is_hex(p[0]) || !is_hex(p[1]))
- return -1;
- else
- return (hexval(p[0]) << 4) + hexval(p[1]);
-}
-
/*
* Tests an IP address in _ip_ for validity; return with 0 for bad, 1 for good.
* We used to refuse class E, but class E addresses are likely to become
@@ -197,57 +111,11 @@ bool ip_ok(uint32_t ip)
*/
static int gendotquad(char *dst, uint32_t ip)
{
- int part;
- int i = 0, j;
- char temp[4];
- char *p = dst;
-
- for (; i < 4; i++) {
- j = 0;
- part = ip & 0xff;
- do {
- temp[j++] = (part % 10) + '0';
- }while(part /= 10);
- for (; j > 0; j--)
- *p++ = temp[j-1];
- *p++ = '.';
-
- ip >>= 8;
- }
- /* drop the last dot '.' and zero-terminate string*/
- *(--p) = 0;
-
- return p - dst;
-}
-
-/*
- * parse the ip_str and return the ip address with *res.
- * return the the string address after the ip string
- *
- */
-static const char *parse_dotquad(const char *ip_str, uint32_t *res)
-{
- const char *p = ip_str;
- uint8_t part = 0;
- uint32_t ip = 0;
- int i;
-
- for (i = 0; i < 4; i++) {
- while (is_digit(*p)) {
- part = part * 10 + *p - '0';
- p++;
- }
- if (i != 3 && *p != '.')
- return NULL;
-
- ip = (ip << 8) | part;
- part = 0;
- p++;
- }
- p--;
-
- *res = htonl(ip);
- return p;
+ return sprintf(dst, "%u.%u.%u.%u",
+ ((const uint8_t *)&ip)[0],
+ ((const uint8_t *)&ip)[1],
+ ((const uint8_t *)&ip)[2],
+ ((const uint8_t *)&ip)[3]);
}
/*
@@ -256,11 +124,14 @@ static const char *parse_dotquad(const char *ip_str, uint32_t *res)
*/
__export int pxe_call(int opcode, void *data)
{
+ static DECLARE_INIT_SEMAPHORE(pxe_sem, 1);
extern void pxenv(void);
com32sys_t regs;
+ sem_down(&pxe_sem, 0);
+
#if 0
- printf("pxe_call op %04x data %p\n", opcode, data);
+ dprintf("pxe_call op %04x data %p\n", opcode, data);
#endif
memset(&regs, 0, sizeof regs);
@@ -269,77 +140,11 @@ __export int pxe_call(int opcode, void *data)
regs.edi.w[0] = OFFS(data);
call16(pxenv, &regs, &regs);
- return regs.eflags.l & EFLAGS_CF; /* CF SET if fail */
-}
-
-/**
- * Send an ERROR packet. This is used to terminate a connection.
- *
- * @inode: Inode structure
- * @errnum: Error number (network byte order)
- * @errstr: Error string (included in packet)
- */
-static void tftp_error(struct inode *inode, uint16_t errnum,
- const char *errstr)
-{
- static __lowmem struct {
- uint16_t err_op;
- uint16_t err_num;
- char err_msg[64];
- } __packed err_buf;
- static __lowmem struct s_PXENV_UDP_WRITE udp_write;
- int len = min(strlen(errstr), sizeof(err_buf.err_msg)-1);
- struct pxe_pvt_inode *socket = PVT(inode);
-
- err_buf.err_op = TFTP_ERROR;
- err_buf.err_num = errnum;
- memcpy(err_buf.err_msg, errstr, len);
- err_buf.err_msg[len] = '\0';
-
- udp_write.src_port = socket->tftp_localport;
- udp_write.dst_port = socket->tftp_remoteport;
- udp_write.ip = socket->tftp_remoteip;
- udp_write.gw = gateway(udp_write.ip);
- udp_write.buffer = FAR_PTR(&err_buf);
- udp_write.buffer_size = 4 + len + 1;
-
- /* If something goes wrong, there is nothing we can do, anyway... */
- pxe_call(PXENV_UDP_WRITE, &udp_write);
-}
-
-
-/**
- * Send ACK packet. This is a common operation and so is worth canning.
- *
- * @param: inode, Inode pointer
- * @param: ack_num, Packet # to ack (network byte order)
- *
- */
-static void ack_packet(struct inode *inode, uint16_t ack_num)
-{
- int err;
- static __lowmem uint16_t ack_packet_buf[2];
- static __lowmem struct s_PXENV_UDP_WRITE udp_write;
- struct pxe_pvt_inode *socket = PVT(inode);
+ sem_up(&pxe_sem);
- /* Packet number to ack */
- ack_packet_buf[0] = TFTP_ACK;
- ack_packet_buf[1] = 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 = gateway(udp_write.ip);
- udp_write.buffer = FAR_PTR(ack_packet_buf);
- udp_write.buffer_size = 4;
-
- err = pxe_call(PXENV_UDP_WRITE, &udp_write);
- (void)err;
-#if 0
- printf("sent %s\n", err ? "FAILED" : "OK");
-#endif
+ return regs.eflags.l & EFLAGS_CF; /* CF SET if fail */
}
-
/**
* Get a DHCP packet from the PXE stack into a lowmem buffer
*
@@ -353,7 +158,7 @@ static int pxe_get_cached_info(int type, void *buf, size_t bufsiz)
static __lowmem struct s_PXENV_GET_CACHED_INFO get_cached_info;
printf(" %02x", type);
- get_cached_info.Status = 0;
+ memset(&get_cached_info, 0, sizeof get_cached_info);
get_cached_info.PacketType = type;
get_cached_info.BufferSize = bufsiz;
get_cached_info.Buffer = FAR_PTR(buf);
@@ -366,104 +171,13 @@ static int pxe_get_cached_info(int type, void *buf, size_t bufsiz)
return get_cached_info.BufferSize;
}
-
-/*
- * Return the type of pathname passed.
- */
-enum pxe_path_type {
- PXE_RELATIVE, /* No :: or URL */
- PXE_HOMESERVER, /* Starting with :: */
- PXE_TFTP, /* host:: */
- PXE_URL_TFTP, /* tftp:// */
- PXE_URL, /* Absolute URL syntax */
-};
-
-static enum pxe_path_type pxe_path_type(const char *str)
-{
- const char *p;
-
- p = str;
-
- while (1) {
- switch (*p) {
- case ':':
- if (p[1] == ':') {
- if (p == str)
- return PXE_HOMESERVER;
- else
- return PXE_TFTP;
- } else if (p > str && p[1] == '/' && p[2] == '/') {
- if (!strncasecmp(str, "tftp://", 7))
- return PXE_URL_TFTP;
- else
- return PXE_URL;
- }
-
- /* else fall through */
- case '/': case '!': case '@': case '#': case '%':
- case '^': case '&': case '*': case '(': case ')':
- case '[': case ']': case '{': case '}': case '\\':
- case '|': case '=': case '`': case '~': case '\'':
- case '\"': case ';': case '>': case '<': case '?':
- case '\0':
- /* Any of these characters terminate the colon search */
- return PXE_RELATIVE;
- default:
- break;
- }
- p++;
- }
-}
-
-#if GPXE
-
-/**
- * Get a fresh packet from a gPXE socket
- * @param: inode -> Inode pointer
- *
- */
-static void get_packet_gpxe(struct inode *inode)
-{
- struct pxe_pvt_inode *socket = PVT(inode);
- static __lowmem struct s_PXENV_FILE_READ file_read;
- int err;
-
- while (1) {
- file_read.FileHandle = socket->tftp_remoteport;
- file_read.Buffer = FAR_PTR(packet_buf);
- file_read.BufferSize = PKTBUF_SIZE;
- err = pxe_call(PXENV_FILE_READ, &file_read);
- if (!err) /* successed */
- break;
-
- if (file_read.Status != PXENV_STATUS_TFTP_OPEN)
- kaboom();
- }
-
- memcpy(socket->tftp_pktbuf, packet_buf, file_read.BufferSize);
-
- socket->tftp_dataptr = socket->tftp_pktbuf;
- socket->tftp_bytesleft = file_read.BufferSize;
- socket->tftp_filepos += file_read.BufferSize;
-
- if (socket->tftp_bytesleft == 0)
- inode->size = socket->tftp_filepos;
-
- /* if we're done here, close the file */
- if (inode->size > socket->tftp_filepos)
- return;
-
- /* Got EOF, close it */
- socket->tftp_goteof = 1;
- gpxe_close_file(inode);
-}
-#endif /* GPXE */
-
-
/*
* mangle a filename pointed to by _src_ into a buffer pointed
* to by _dst_; ends on encountering any whitespace.
*
+ * This deliberately does not attempt to do any conversion of
+ * pathname separators.
+ *
*/
static void pxe_mangle_name(char *dst, const char *src)
{
@@ -476,109 +190,40 @@ static void pxe_mangle_name(char *dst, const char *src)
}
/*
- * Get a fresh packet if the buffer is drained, and we haven't hit
- * EOF yet. The buffer should be filled immediately after draining!
+ * Read a single character from the specified pxe inode.
+ * Very useful for stepping through http streams and
+ * parsing their headers.
*/
-static void fill_buffer(struct inode *inode)
+int pxe_getc(struct inode *inode)
{
- int err;
- int last_pkt;
- const uint8_t *timeout_ptr;
- uint8_t timeout;
- uint16_t buffersize;
- uint32_t oldtime;
- void *data = NULL;
- static __lowmem struct s_PXENV_UDP_READ udp_read;
struct pxe_pvt_inode *socket = PVT(inode);
+ unsigned char byte;
- if (socket->tftp_bytesleft || socket->tftp_goteof)
- return;
+ while (!socket->tftp_bytesleft) {
+ if (socket->tftp_goteof)
+ return -1;
-#if GPXE
- if (socket->tftp_localport == 0xffff) {
- get_packet_gpxe(inode);
- return;
+ socket->ops->fill_buffer(inode);
}
-#endif
-
- /*
- * Start by ACKing the previous packet; this should cause
- * the next packet to be sent.
- */
- timeout_ptr = TimeoutTable;
- timeout = *timeout_ptr++;
- oldtime = jiffies();
-
- ack_again:
- ack_packet(inode, socket->tftp_lastpkt);
-
- while (timeout) {
- udp_read.buffer = FAR_PTR(packet_buf);
- udp_read.buffer_size = PKTBUF_SIZE;
- udp_read.src_ip = socket->tftp_remoteip;
- 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);
- if (err) {
- uint32_t now = jiffies();
-
- if (now-oldtime >= timeout) {
- oldtime = now;
- timeout = *timeout_ptr++;
- if (!timeout)
- break;
- }
- continue;
- }
-
- if (udp_read.buffer_size < 4) /* Bad size for a DATA packet */
- continue;
- data = packet_buf;
- if (*(uint16_t *)data != TFTP_DATA) /* Not a data packet */
- continue;
-
- /* If goes here, recevie OK, break */
- break;
- }
+ byte = *socket->tftp_dataptr;
+ socket->tftp_bytesleft -= 1;
+ socket->tftp_dataptr += 1;
- /* time runs out */
- if (timeout == 0)
- kaboom();
+ return byte;
+}
- last_pkt = socket->tftp_lastpkt;
- last_pkt = ntohs(last_pkt); /* Host byte order */
- last_pkt++;
- last_pkt = htons(last_pkt); /* Network byte order */
- if (*(uint16_t *)(data + 2) != last_pkt) {
- /*
- * Wrong packet, ACK the packet and try again.
- * This is presumably because the ACK got lost,
- * so the server just resent the previous packet.
- */
-#if 0
- printf("Wrong packet, wanted %04x, got %04x\n", \
- htons(last_pkt), htons(*(uint16_t *)(data+2)));
-#endif
- goto ack_again;
- }
+/*
+ * Get a fresh packet if the buffer is drained, and we haven't hit
+ * EOF yet. The buffer should be filled immediately after draining!
+ */
+static void fill_buffer(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ if (socket->tftp_bytesleft || socket->tftp_goteof)
+ return;
- /* It's the packet we want. We're also EOF if the size < blocksize */
- socket->tftp_lastpkt = last_pkt; /* Update last packet number */
- buffersize = udp_read.buffer_size - 4; /* Skip TFTP header */
- memcpy(socket->tftp_pktbuf, packet_buf + 4, buffersize);
- socket->tftp_dataptr = socket->tftp_pktbuf;
- socket->tftp_filepos += buffersize;
- socket->tftp_bytesleft = buffersize;
- if (buffersize < socket->tftp_blksize) {
- /* it's the last block, ACK packet immediately */
- ack_packet(inode, *(uint16_t *)(data + 2));
-
- /* Make sure we know we are at end of file */
- inode->size = socket->tftp_filepos;
- socket->tftp_goteof = 1;
- }
+ return socket->ops->fill_buffer(inode);
}
@@ -635,8 +280,20 @@ static uint32_t pxe_getfssec(struct file *file, char *buf,
return bytes_read;
}
+/*
+ * Assign an IP address to a URL
+ */
+static void url_set_ip(struct url_info *url)
+{
+ url->ip = 0;
+ if (url->host)
+ url->ip = dns_resolv(url->host);
+ if (!url->ip)
+ url->ip = IPInfo.serverip;
+}
+
/**
- * Open a TFTP connection to the server
+ * Open the specified connection
*
* @param:filename, the file we wanna open
*
@@ -644,343 +301,86 @@ static uint32_t pxe_getfssec(struct file *file, char *buf,
* @out: the lenght of this file, stores in file->file_len
*
*/
-static void __pxe_searchdir(const char *filename, struct file *file);
+static void __pxe_searchdir(const char *filename, int flags, struct file *file);
extern uint16_t PXERetry;
-static void pxe_searchdir(const char *filename, struct file *file)
+static void pxe_searchdir(const char *filename, int flags, struct file *file)
{
int i = PXERetry;
do {
dprintf("PXE: file = %p, retries left = %d: ", file, i);
- __pxe_searchdir(filename, file);
+ __pxe_searchdir(filename, flags, file);
dprintf("%s\n", file->inode ? "ok" : "failed");
} while (!file->inode && i--);
}
-
-static void __pxe_searchdir(const char *filename, struct file *file)
+static void __pxe_searchdir(const char *filename, int flags, struct file *file)
{
struct fs_info *fs = file->fs;
struct inode *inode;
- struct pxe_pvt_inode *socket;
- char *buf;
- const char *np;
- char *p;
- char *options;
- char *data;
- static __lowmem struct s_PXENV_UDP_WRITE udp_write;
- static __lowmem struct s_PXENV_UDP_READ udp_read;
- static __lowmem struct s_PXENV_FILE_OPEN file_open;
- static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
- static __lowmem char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail];
- const struct tftp_options *tftp_opt;
- int i = 0;
- int err;
- int buffersize;
- int rrq_len;
- const uint8_t *timeout_ptr;
- uint32_t timeout;
- uint32_t oldtime;
- uint16_t tid;
- uint16_t opcode;
- uint16_t blk_num;
- uint32_t ip = 0;
- uint32_t opdata, *opdata_ptr;
- enum pxe_path_type path_type;
char fullpath[2*FILENAME_MAX];
- uint16_t server_port = TFTP_PORT; /* TFTP server port */
+#if GPXE
+ char urlsave[2*FILENAME_MAX];
+#endif
+ struct url_info url;
+ const struct url_scheme *us = NULL;
+ int redirect_count = 0;
+ bool found_scheme = false;
inode = file->inode = NULL;
-
- buf = rrq_packet_buf;
- *(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */
- buf += 2;
-
- path_type = pxe_path_type(filename);
- if (path_type == PXE_RELATIVE) {
- snprintf(fullpath, sizeof fullpath, "%s%s", fs->cwd_name, filename);
- path_type = pxe_path_type(filename = fullpath);
- }
- switch (path_type) {
- case PXE_RELATIVE: /* Really shouldn't happen... */
- case PXE_URL:
- buf = stpcpy(buf, filename);
- ip = IPInfo.serverip; /* Default server */
- break;
-
- case PXE_HOMESERVER:
- buf = stpcpy(buf, filename+2);
- ip = IPInfo.serverip;
- break;
-
- case PXE_TFTP:
- np = strchr(filename, ':');
- buf = stpcpy(buf, np+2);
- if (parse_dotquad(filename, &ip) != np)
- ip = dns_resolv(filename);
- break;
-
- case PXE_URL_TFTP:
- np = filename + 7;
- while (*np && *np != '/' && *np != ':')
- np++;
- if (np > filename + 7) {
- if (parse_dotquad(filename + 7, &ip) != np)
- ip = dns_resolv(filename + 7);
- }
- if (*np == ':') {
- np++;
- server_port = 0;
- while (*np >= '0' && *np <= '9')
- server_port = server_port * 10 + *np++ - '0';
- server_port = server_port ? htons(server_port) : TFTP_PORT;
- }
- if (*np == '/')
- np++; /* Do *NOT* eat more than one slash here... */
- /*
- * The ; is because of a quirk in the TFTP URI spec (RFC
- * 3617); it is to be followed by TFTP modes, which we just ignore.
- */
- while (*np && *np != ';') {
- int v;
- if (*np == '%' && (v = hexbyte(np+1)) > 0) {
- *buf++ = v;
- np += 3;
- } else {
- *buf++ = *np++;
- }
- }
- *buf = '\0';
- break;
- }
-
- buf++; /* Point *past* the final NULL */
- 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);
+ while (filename) {
+ if (redirect_count++ > 5)
+ break;
+ strlcpy(fullpath, filename, sizeof fullpath);
#if GPXE
- if (path_type == PXE_URL) {
- if (has_gpxe) {
- file_open.Status = PXENV_STATUS_BAD_FUNC;
- file_open.FileName = FAR_PTR(rrq_packet_buf + 2);
- err = pxe_call(PXENV_FILE_OPEN, &file_open);
- if (err)
- goto done;
-
- socket->tftp_localport = -1;
- socket->tftp_remoteport = file_open.FileHandle;
- inode->size = -1;
- goto done;
- } else {
- static bool already = false;
- if (!already) {
- printf("URL syntax, but gPXE extensions not detected, "
- "trying plain TFTP...\n");
- already = true;
- }
+ strcpy(urlsave, fullpath);
+#endif
+ parse_url(&url, fullpath);
+ if (url.type == URL_SUFFIX) {
+ snprintf(fullpath, sizeof fullpath, "%s%s", fs->cwd_name, filename);
+#if GPXE
+ strcpy(urlsave, fullpath);
+#endif
+ parse_url(&url, fullpath);
}
- }
-#endif /* GPXE */
-
- if (!ip)
- goto done; /* No server */
-
- timeout_ptr = TimeoutTable; /* Reset timeout */
-
-sendreq:
- timeout = *timeout_ptr++;
- if (!timeout) {
- free_socket(inode);
- 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 = gateway(udp_write.ip);
- udp_write.src_port = tid;
- udp_write.dst_port = server_port;
- 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 = IPInfo.myip;
- udp_read.d_port = tid;
- err = pxe_call(PXENV_UDP_READ, &udp_read);
- if (err || udp_read.status) {
- uint32_t now = jiffies();
- if (now - oldtime >= timeout)
- goto sendreq;
- } else {
- /* Make sure the packet actually came from the server */
- if (udp_read.src_ip == socket->tftp_remoteip)
+
+ inode = allocate_socket(fs);
+ if (!inode)
+ return; /* Allocation failure */
+
+ url_set_ip(&url);
+
+ filename = NULL;
+ found_scheme = false;
+ for (us = url_schemes; us->name; us++) {
+ if (!strcmp(us->name, url.scheme)) {
+ if ((flags & ~us->ok_flags & OK_FLAGS_MASK) == 0)
+ us->open(&url, flags, inode, &filename);
+ found_scheme = true;
break;
+ }
}
- }
-
- socket->tftp_remoteport = udp_read.s_port;
-
- /* filesize <- -1 == unknown */
- inode->size = -1;
- /* Default blksize unless blksize option negotiated */
- socket->tftp_blksize = TFTP_BLOCKSIZE;
- buffersize = udp_read.buffer_size - 2; /* bytes after opcode */
- if (buffersize < 0)
- goto wait_pkt; /* Garbled reply */
- /*
- * Get the opcode type, and parse it
- */
- opcode = *(uint16_t *)packet_buf;
- switch (opcode) {
- case TFTP_ERROR:
- inode->size = 0;
- break; /* ERROR reply; don't try again */
-
- case TFTP_DATA:
- /*
- * If the server doesn't support any options, we'll get a
- * DATA reply instead of OACK. Stash the data in the file
- * buffer and go with the default value for all options...
- *
- * We got a DATA packet, meaning no options are
- * suported. Save the data away and consider the
- * length undefined, *unless* this is the only
- * data packet...
- */
- buffersize -= 2;
- if (buffersize < 0)
- goto wait_pkt;
- data = packet_buf + 2;
- blk_num = *(uint16_t *)data;
- data += 2;
- if (blk_num != htons(1))
- goto wait_pkt;
- socket->tftp_lastpkt = blk_num;
- if (buffersize > TFTP_BLOCKSIZE)
- goto err_reply; /* Corrupt */
- else if (buffersize < TFTP_BLOCKSIZE) {
- /*
- * This is the final EOF packet, already...
- * We know the filesize, but we also want to
- * ack the packet and set the EOF flag.
- */
- inode->size = buffersize;
- socket->tftp_goteof = 1;
- ack_packet(inode, blk_num);
- }
-
- socket->tftp_bytesleft = buffersize;
- socket->tftp_dataptr = socket->tftp_pktbuf;
- memcpy(socket->tftp_pktbuf, data, buffersize);
- break;
-
- case TFTP_OACK:
- /*
- * Now we need to parse the OACK packet to get the transfer
- * and packet sizes.
- */
-
- options = packet_buf + 2;
- p = options;
-
- while (buffersize) {
- const char *opt = p;
-
- /*
- * If we find an option which starts with a NUL byte,
- * (a null option), we're either seeing garbage that some
- * TFTP servers add to the end of the packet, or we have
- * no clue how to parse the rest of the packet (what is
- * an option name and what is a value?) In either case,
- * discard the rest.
- */
- if (!*opt)
- goto done;
-
- while (buffersize) {
- if (!*p)
- break; /* Found a final null */
- *p++ |= 0x20;
- buffersize--;
- }
- if (!buffersize)
- break; /* Unterminated option */
-
- /* Consume the terminal null */
- p++;
- buffersize--;
-
- if (!buffersize)
- break; /* No option data */
-
- /*
- * Parse option pointed to by options; guaranteed to be
- * null-terminated
- */
- tftp_opt = tftp_options;
- for (i = 0; i < tftp_nopts; i++) {
- if (!strcmp(opt, tftp_opt->str_ptr))
- break;
- tftp_opt++;
- }
- if (i == tftp_nopts)
- goto err_reply; /* Non-negotitated option returned,
- no idea what it means ...*/
-
- /* get the address of the filed that we want to write on */
- opdata_ptr = (uint32_t *)((char *)inode + tftp_opt->offset);
- opdata = 0;
-
- /* do convert a number-string to decimal number, just like atoi */
- while (buffersize--) {
- uint8_t d = *p++;
- if (d == '\0')
- break; /* found a final null */
- d -= '0';
- if (d > 9)
- goto err_reply; /* Not a decimal digit */
- opdata = opdata*10 + d;
- }
- *opdata_ptr = opdata;
- }
- break;
+ /* filename here is set on a redirect */
+ }
- default:
- printf("TFTP unknown opcode %d\n", ntohs(opcode));
- goto err_reply;
+ if (!found_scheme) {
+#if GPXE
+ /* No URL scheme found, hand it to GPXE */
+ gpxe_open(inode, urlsave);
+#endif
}
-done:
- if (!inode->size) {
+ if (inode->size) {
+ file->inode = inode;
+ file->inode->mode = (flags & O_DIRECTORY) ? DT_DIR : DT_REG;
+ } else {
free_socket(inode);
- return;
}
- file->inode = inode;
- return;
-err_reply:
- /* Build the TFTP error packet */
- tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
- printf("TFTP server sent an incomprehesible reply\n");
- kaboom();
+ return;
}
@@ -1018,6 +418,24 @@ static void get_prefix(void)
}
printf("TFTP prefix: %s\n", path_prefix);
+
+ if (url_type(path_prefix) == URL_SUFFIX) {
+ /*
+ * Construct a ::-style TFTP path.
+ *
+ * We may have moved out of the root directory at the time
+ * this function is invoked, but to maintain compatibility
+ * with versions of Syslinux < 5.00, path_prefix must be
+ * relative to "::".
+ */
+ p = strdup(path_prefix);
+ if (!p)
+ return;
+
+ snprintf(path_prefix, sizeof path_prefix, "::%s", p);
+ free(p);
+ }
+
chdir(path_prefix);
}
@@ -1027,10 +445,8 @@ static void get_prefix(void)
static size_t pxe_realpath(struct fs_info *fs, char *dst, const char *src,
size_t bufsize)
{
- enum pxe_path_type path_type = pxe_path_type(src);
-
return snprintf(dst, bufsize, "%s%s",
- path_type == PXE_RELATIVE ? fs->cwd_name : "", src);
+ url_type(src) == URL_SUFFIX ? fs->cwd_name : "", src);
}
/*
@@ -1039,12 +455,13 @@ static size_t pxe_realpath(struct fs_info *fs, char *dst, const char *src,
static int pxe_chdir(struct fs_info *fs, const char *src)
{
/* The cwd for PXE is just a text prefix */
- enum pxe_path_type path_type = pxe_path_type(src);
+ enum url_type path_type = url_type(src);
- if (path_type == PXE_RELATIVE)
+ if (path_type == URL_SUFFIX)
strlcat(fs->cwd_name, src, sizeof fs->cwd_name);
else
strlcpy(fs->cwd_name, src, sizeof fs->cwd_name);
+ return 0;
dprintf("cwd = \"%s\"\n", fs->cwd_name);
return 0;
@@ -1065,9 +482,10 @@ static int pxe_open_config(struct com32_filedata *filedata)
char *last;
int tries = 8;
+ chdir(path_prefix);
if (DHCPMagic & 0x02) {
/* We got a DHCP option, try it first */
- if (open_file(ConfigName, filedata) >= 0)
+ if (open_file(ConfigName, O_RDONLY, filedata) >= 0)
return 0;
}
@@ -1077,23 +495,23 @@ static int pxe_open_config(struct com32_filedata *filedata)
config_file = stpcpy(ConfigName, cfgprefix);
/* Try loading by UUID */
- if (have_uuid) {
- strcpy(config_file, UUID_str);
- if (open_file(ConfigName, filedata) >= 0)
+ if (sysappend_strings[SYSAPPEND_SYSUUID]) {
+ strcpy(config_file, sysappend_strings[SYSAPPEND_SYSUUID]+8);
+ if (open_file(ConfigName, O_RDONLY, filedata) >= 0)
return 0;
}
/* Try loading by MAC address */
- strcpy(config_file, MAC_str);
- if (open_file(ConfigName, filedata) >= 0)
+ strcpy(config_file, sysappend_strings[SYSAPPEND_BOOTIF]+7);
+ if (open_file(ConfigName, O_RDONLY, filedata) >= 0)
return 0;
/* Nope, try hexadecimal IP prefixes... */
- uchexbytes(config_file, (uint8_t *)&IPInfo.myip, 4);
+ sprintf(config_file, "%08X", ntohl(IPInfo.myip));
last = &config_file[8];
while (tries) {
*last = '\0'; /* Zero-terminate string */
- if (open_file(ConfigName, filedata) >= 0)
+ if (open_file(ConfigName, O_RDONLY, filedata) >= 0)
return 0;
last--; /* Drop one character */
tries--;
@@ -1101,7 +519,7 @@ static int pxe_open_config(struct com32_filedata *filedata)
/* Final attempt: "default" string */
strcpy(config_file, default_str);
- if (open_file(ConfigName, filedata) >= 0)
+ if (open_file(ConfigName, O_RDONLY, filedata) >= 0)
return 0;
printf("%-68s\n", "Unable to locate configuration file");
@@ -1113,43 +531,17 @@ static int pxe_open_config(struct com32_filedata *filedata)
*/
static void make_bootif_string(void)
{
+ static char bootif_str[7+3*(MAC_MAX+1)];
const uint8_t *src;
- char *dst = BOOTIFStr;
+ char *dst = bootif_str;
int i;
dst += sprintf(dst, "BOOTIF=%02x", MAC_type);
src = MAC;
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';
- }
+ sysappend_strings[SYSAPPEND_BOOTIF] = bootif_str;
}
/*
@@ -1157,21 +549,22 @@ static void make_sysuuid_string(void)
* option into IPOption based on DHCP information in IPInfo.
*
*/
-char __bss16 IPOption[3+4*16];
-
static void genipopt(void)
{
- char *p = IPOption;
+ static char ip_option[3+4*16];
const uint32_t *v = &IPInfo.myip;
+ char *p;
int i;
- p = stpcpy(p, "ip=");
+ p = stpcpy(ip_option, "ip=");
for (i = 0; i < 4; i++) {
p += gendotquad(p, *v++);
*p++ = ':';
}
*--p = '\0';
+
+ sysappend_strings[SYSAPPEND_IP] = ip_option;
}
@@ -1179,6 +572,7 @@ static void genipopt(void)
static void ip_init(void)
{
uint32_t ip = IPInfo.myip;
+ char dot_quad_buf[16];
genipopt();
gendotquad(dot_quad_buf, ip);
@@ -1188,20 +582,6 @@ static void ip_init(void)
}
/*
- * Print the IPAPPEND strings, in order
- */
-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);
- }
-}
-
-/*
* Validity check on possible !PXE structure in buf
* return 1 for success, 0 for failure.
*
@@ -1402,6 +782,8 @@ static int pxe_init(bool quiet)
real_base_mem = max(code_seg, data_seg) >> 6; /* Convert to kilobytes */
+ probe_undi();
+
return 0;
}
@@ -1426,24 +808,6 @@ static void gpxe_init(void)
}
/*
- * Initialize UDP stack
- *
- */
-static void udp_init(void)
-{
- int err;
- static __lowmem struct s_PXENV_UDP_OPEN udp_open;
- 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 ");
- printf("%d\n", udp_open.status);
- kaboom();
- }
-}
-
-
-/*
* Network-specific initialization
*/
static void network_init(void)
@@ -1503,10 +867,12 @@ static void network_init(void)
lfree(bp);
make_bootif_string();
- make_sysuuid_string();
+ /* If DMI and DHCP disagree, which one should we set? */
+ if (have_uuid)
+ sysappend_set_uuid(uuid);
ip_init();
- print_ipappend();
+ /* print_sysappend(); */
/*
* Check to see if we got any PXELINUX-specific DHCP options; in particular,
* if we didn't get the magic enable, do not recognize any other options.
@@ -1514,7 +880,7 @@ static void network_init(void)
if ((DHCPMagic & 1) == 0)
DHCPMagic = 0;
- udp_init();
+ net_core_init();
}
/*
@@ -1525,9 +891,8 @@ static int pxe_fs_init(struct fs_info *fs)
{
(void)fs; /* drop the compile warning message */
- /* This block size is actually arbitrary... */
- fs->sector_shift = fs->block_shift = TFTP_BLOCKSIZE_LG2;
- fs->sector_size = fs->block_size = 1 << TFTP_BLOCKSIZE_LG2;
+ /* Prepare for handling pxe interrupts */
+ pxe_init_isr();
/* This block size is actually arbitrary... */
fs->sector_shift = fs->block_shift = TFTP_BLOCKSIZE_LG2;
@@ -1589,9 +954,9 @@ static inline bool is_efi(const struct efi_struct *efi)
return (efi->magic == EFI_MAGIC) && (efi->len >= 83);
}
+#if 0
static void install_int18_hack(void)
{
-#if 0
static const uint8_t int18_hack[] =
{
0xcd, 0x18, /* int $0x18 */
@@ -1627,30 +992,8 @@ static void install_int18_hack(void)
*(uint16_t *)(dst+46) = InitStack.seg;
}
}
-#endif
-}
-
-int reset_pxe(void)
-{
- static __lowmem struct s_PXENV_UDP_CLOSE udp_close;
- extern void gpxe_unload(void);
- int err = 0;
-
- pxe_idle_cleanup();
-
- pxe_call(PXENV_UDP_CLOSE, &udp_close);
-
- if (gpxe_funcs & 0x80) {
- /* gPXE special unload implemented */
- call16(gpxe_unload, &zero_regs, NULL);
-
- /* Locate the actual vendor stack... */
- err = pxe_init(true);
- }
-
- install_int18_hack();
- return err;
}
+#endif
/*
* This function unloads the PXE and UNDI stacks and
@@ -1659,6 +1002,12 @@ int reset_pxe(void)
__export void unload_pxe(uint16_t flags)
{
/* PXE unload sequences */
+ /*
+ * iPXE does:
+ * UNDI_SHUTDOWN, UNDI_CLEANUP, STOP_UNDI
+ * Older Syslinux did:
+ * UDP_CLOSE, UNDI_SHUTDOWN, UNLOAD_STACK, STOP_UNDI/UNDI_CLEANUP
+ */
static const uint8_t new_api_unload[] = {
PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_STOP_UNDI, 0
};
@@ -1678,6 +1027,7 @@ __export void unload_pxe(uint16_t flags)
uint16_t Status; /* All calls have this as the first member */
} unload_call;
+ dprintf("Called unload_pxe()...\n");
dprintf("FBM before unload = %d\n", bios_fbm());
err = reset_pxe();
@@ -1696,7 +1046,8 @@ __export void unload_pxe(uint16_t flags)
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);
+ printf("PXE unload API call %04x failed: 0x%x\n",
+ api, unload_call.Status);
goto cant_free;
}
}
@@ -1728,6 +1079,17 @@ cant_free:
return;
}
+static int pxe_readdir(struct file *file, struct dirent *dirent)
+{
+ struct inode *inode = file->inode;
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ if (socket->ops->readdir)
+ return socket->ops->readdir(inode, dirent);
+ else
+ return -1; /* No such operation */
+}
+
const struct fs_ops pxe_fs_ops = {
.fs_name = "pxe",
.fs_flags = FS_NODEV,
@@ -1740,4 +1102,5 @@ const struct fs_ops pxe_fs_ops = {
.mangle_name = pxe_mangle_name,
.chdir_start = pxe_chdir_start,
.open_config = pxe_open_config,
+ .readdir = pxe_readdir,
};
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index 3439dd6a..08172b08 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
*
* Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,67 +22,21 @@
#include <syslinux/pxe_api.h>
#include <syslinux/config.h>
-#include "fs.h" /* For MAX_OPEN, should go away */
+#include "fs.h" /* Mostly for FILENAME_MAX */
/*
* Some basic defines...
*/
-#define TFTP_PORT htons(69) /* Default TFTP port */
-#define TFTP_BLOCKSIZE_LG2 9
-#define TFTP_BLOCKSIZE (1 << TFTP_BLOCKSIZE_LG2)
-#define PKTBUF_SIZE 2048 /* */
+#define PKTBUF_SIZE 2048 /* Used mostly by the gPXE backend */
#define is_digit(c) (((c) >= '0') && ((c) <= '9'))
-static inline bool is_hex(char c)
-{
- return (c >= '0' && c <= '9') ||
- (c >= 'A' && c <= 'F') ||
- (c >= 'a' && c <= 'f');
-}
-
-static inline int hexval(char c)
-{
- return (c >= 'A') ? (c & ~0x20) - 'A' + 10 : (c - '0');
-}
-
-/*
- * TFTP operation codes
- */
-#define TFTP_RRQ htons(1) // Read rest
-#define TFTP_WRQ htons(2) // Write rest
-#define TFTP_DATA htons(3) // Data packet
-#define TFTP_ACK htons(4) // ACK packet
-#define TFTP_ERROR htons(5) // ERROR packet
-#define TFTP_OACK htons(6) // OACK packet
-
-/*
- * TFTP error codes
- */
-#define TFTP_EUNDEF htons(0) // Unspecified error
-#define TFTP_ENOTFOUND htons(1) // File not found
-#define TFTP_EACCESS htons(2) // Access violation
-#define TFTP_ENOSPACE htons(3) // Disk full
-#define TFTP_EBADOP htons(4) // Invalid TFTP operation
-#define TFTP_EBADID htons(5) // Unknown transfer
-#define TFTP_EEXISTS htons(6) // File exists
-#define TFTP_ENOUSER htons(7) // No such user
-#define TFTP_EOPTNEG htons(8) // Option negotiation failure
-
-
#define BOOTP_OPTION_MAGIC htonl(0x63825363)
#define MAC_MAX 32
-/* Defines for DNS */
-#define DNS_PORT htons(53) /* Default DNS port */
-#define DNS_MAX_PACKET 512 /* Defined by protocol */
-#define DNS_MAX_SERVERS 4 /* Max no of DNS servers */
-
-
/*
- * structures
+ * structures
*/
-
struct pxenv_t {
uint8_t signature[6]; /* PXENV+ */
uint16_t version;
@@ -150,22 +104,42 @@ struct bootp_t {
uint8_t options[1260]; /* Vendor options */
} __attribute__ ((packed));
+struct netconn;
+struct netbuf;
/*
* Our inode private information -- this includes the packet buffer!
*/
+struct pxe_conn_ops {
+ void (*fill_buffer)(struct inode *inode);
+ void (*close)(struct inode *inode);
+ int (*readdir)(struct inode *inode, struct dirent *dirent);
+};
+
+struct net_private {
+#ifdef IS_LPXELINUX
+ struct netconn *conn; /* lwip network connection */
+ struct netbuf *buf; /* lwip cached buffer */
+#else
+ uint16_t tftp_localport; /* Local port number (0=not in use) */
+ uint32_t tftp_remoteip; /* Remote IP address (0 = disconnected) */
+#endif
+
+};
+
struct pxe_pvt_inode {
- uint16_t tftp_localport; /* Local port number (0=not in us)*/
- uint16_t tftp_remoteport; /* Remote port number */
- uint32_t tftp_remoteip; /* Remote IP address */
- uint32_t tftp_filepos; /* bytes downloaded (includeing buffer) */
- uint32_t tftp_blksize; /* Block size for this connection(*) */
- uint16_t tftp_bytesleft; /* Unclaimed data bytes */
- uint16_t tftp_lastpkt; /* Sequence number of last packet (NBO) */
- char *tftp_dataptr; /* Pointer to available data */
- uint8_t tftp_goteof; /* 1 if the EOF packet received */
- uint8_t tftp_unused[3]; /* Currently unused */
- char tftp_pktbuf[PKTBUF_SIZE];
-} __attribute__ ((packed));
+ struct net_private private; /* Network stack private data */
+ uint16_t tftp_remoteport; /* Remote port number */
+ uint32_t tftp_filepos; /* bytes downloaded (including buffer) */
+ uint32_t tftp_blksize; /* Block size for this connection(*) */
+ uint16_t tftp_bytesleft; /* Unclaimed data bytes */
+ uint16_t tftp_lastpkt; /* Sequence number of last packet (HBO) */
+ char *tftp_dataptr; /* Pointer to available data */
+ uint8_t tftp_goteof; /* 1 if the EOF packet received */
+ uint8_t tftp_unused[3]; /* Currently unused */
+ char *tftp_pktbuf; /* Packet buffer */
+ struct inode *ctl; /* Control connection (for FTP) */
+ const struct pxe_conn_ops *ops;
+};
#define PVT(i) ((struct pxe_pvt_inode *)((i)->pvt))
@@ -174,6 +148,9 @@ struct pxe_pvt_inode {
*/
extern struct syslinux_ipinfo IPInfo;
+extern t_PXENV_UNDI_GET_INFORMATION pxe_undi_info;
+extern t_PXENV_UNDI_GET_IFACE_INFO pxe_undi_iface;
+
extern uint8_t MAC[];
extern char BOOTIFStr[];
extern uint8_t MAC_len;
@@ -186,9 +163,6 @@ extern char boot_file[];
extern char path_prefix[];
extern char LocalDomain[];
-extern char IPOption[];
-extern char dot_quad_buf[];
-
extern uint32_t dns_server[];
extern uint16_t APIVer;
@@ -201,8 +175,6 @@ extern bool have_uuid;
extern uint8_t uuid_type;
extern uint8_t uuid[];
-extern const uint8_t TimeoutTable[];
-
/*
* Compute the suitable gateway for a specific route -- too many
* vendor PXE stacks don't do this correctly...
@@ -216,24 +188,62 @@ static inline uint32_t gateway(uint32_t ip)
}
/*
- * functions
+ * functions
*/
+/* pxeisr.inc */
+extern uint8_t pxe_irq_vector;
+extern void pxe_isr(void);
+extern far_ptr_t pxe_irq_chain;
+extern void pxe_poll(void);
+
+/* isr.c */
+void pxe_init_isr(void);
+void pxe_start_isr(void);
+int reset_pxe(void);
+
/* pxe.c */
+struct url_info;
bool ip_ok(uint32_t);
+int pxe_getc(struct inode *inode);
+void free_socket(struct inode *inode);
+
+/* undiif.c */
+int undiif_start(uint32_t ip, uint32_t netmask, uint32_t gw);
+void undiif_input(t_PXENV_UNDI_ISR *isr);
/* dhcp_options.c */
void parse_dhcp(const void *, size_t);
-/* dnsresolv.c */
-int dns_mangle(char **, const char *);
-
/* idle.c */
void pxe_idle_init(void);
void pxe_idle_cleanup(void);
-/* socknum.c */
-uint16_t get_port(void);
-void free_port(uint16_t port);
+/* tftp.c */
+void tftp_open(struct url_info *url, int flags, struct inode *inode,
+ const char **redir);
+
+/* gpxeurl.c */
+void gpxe_open(struct inode *inode, const char *url);
+#define GPXE 0
+
+/* http.c */
+void http_open(struct url_info *url, int flags, struct inode *inode,
+ const char **redir);
+
+/* http_readdir.c */
+int http_readdir(struct inode *inode, struct dirent *dirent);
+
+/* ftp.c */
+void ftp_open(struct url_info *url, int flags, struct inode *inode,
+ const char **redir);
+
+/* ftp_readdir.c */
+int ftp_readdir(struct inode *inode, struct dirent *dirent);
+
+/* tcp.c */
+void tcp_close_file(struct inode *inode);
+void tcp_fill_buffer(struct inode *inode);
+const struct pxe_conn_ops tcp_conn_ops;
#endif /* pxe.h */
diff --git a/core/fs/pxe/tcp.c b/core/fs/pxe/tcp.c
new file mode 100644
index 00000000..7e7bdcad
--- /dev/null
+++ b/core/fs/pxe/tcp.c
@@ -0,0 +1,78 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * tcp.c
+ *
+ * Common operations for TCP-based network protocols
+ */
+
+#include <lwip/api.h>
+#include "pxe.h"
+#include "version.h"
+#include "url.h"
+
+void tcp_close_file(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ if (socket->private.conn) {
+ netconn_delete(socket->private.conn);
+ socket->private.conn = NULL;
+ }
+ if (socket->private.buf) {
+ netbuf_delete(socket->private.buf);
+ socket->private.buf = NULL;
+ }
+}
+
+void tcp_fill_buffer(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ void *data;
+ u16_t len;
+ err_t err;
+
+ /* Clean up or advance an inuse netbuf */
+ if (socket->private.buf) {
+ if (netbuf_next(socket->private.buf) < 0) {
+ netbuf_delete(socket->private.buf);
+ socket->private.buf = NULL;
+ }
+ }
+ /* If needed get a new netbuf */
+ if (!socket->private.buf) {
+ err = netconn_recv(socket->private.conn, &(socket->private.buf));
+ if (!socket->private.buf || err) {
+ socket->tftp_goteof = 1;
+ if (inode->size == -1)
+ inode->size = socket->tftp_filepos;
+ socket->ops->close(inode);
+ return;
+ }
+ }
+ /* Report the current fragment of the netbuf */
+ err = netbuf_data(socket->private.buf, &data, &len);
+ if (err) {
+ printf("netbuf_data err: %d\n", err);
+ kaboom();
+ }
+ socket->tftp_dataptr = data;
+ socket->tftp_filepos += len;
+ socket->tftp_bytesleft = len;
+ return;
+}
+
+const struct pxe_conn_ops tcp_conn_ops = {
+ .fill_buffer = tcp_fill_buffer,
+ .close = tcp_close_file,
+};
diff --git a/core/fs/pxe/tftp.c b/core/fs/pxe/tftp.c
new file mode 100644
index 00000000..9b755c93
--- /dev/null
+++ b/core/fs/pxe/tftp.c
@@ -0,0 +1,443 @@
+#include <minmax.h>
+#include <net.h>
+#include "pxe.h"
+#include "url.h"
+#include "tftp.h"
+
+const uint8_t TimeoutTable[] = {
+ 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44,
+ 53, 64, 77, 92, 110, 132, 159, 191, 229, 255, 255, 255, 255, 0
+};
+struct tftp_options {
+ const char *str_ptr; /* string pointer */
+ size_t offset; /* offset into socket structre */
+};
+struct tftp_packet {
+ uint16_t opcode;
+ uint16_t serial;
+ char data[];
+};
+
+#define IFIELD(x) offsetof(struct inode, x)
+#define PFIELD(x) (offsetof(struct inode, pvt) + \
+ offsetof(struct pxe_pvt_inode, x))
+
+static const struct tftp_options tftp_options[] =
+{
+ { "tsize", IFIELD(size) },
+ { "blksize", PFIELD(tftp_blksize) },
+};
+static const int tftp_nopts = sizeof tftp_options / sizeof tftp_options[0];
+
+static void tftp_error(struct inode *file, uint16_t errnum,
+ const char *errstr);
+
+static void tftp_close_file(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ if (!socket->tftp_goteof) {
+ tftp_error(inode, 0, "No error, file close");
+ }
+ net_core_close(socket);
+}
+
+/**
+ * Send an ERROR packet. This is used to terminate a connection.
+ *
+ * @inode: Inode structure
+ * @errnum: Error number (network byte order)
+ * @errstr: Error string (included in packet)
+ */
+static void tftp_error(struct inode *inode, uint16_t errnum,
+ const char *errstr)
+{
+ static struct {
+ uint16_t err_op;
+ uint16_t err_num;
+ char err_msg[64];
+ } __packed err_buf;
+ int len = min(strlen(errstr), sizeof(err_buf.err_msg)-1);
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ err_buf.err_op = TFTP_ERROR;
+ err_buf.err_num = errnum;
+ memcpy(err_buf.err_msg, errstr, len);
+ err_buf.err_msg[len] = '\0';
+
+ net_core_send(socket, &err_buf, 4 + len + 1);
+}
+
+/**
+ * Send ACK packet. This is a common operation and so is worth canning.
+ *
+ * @param: inode, Inode pointer
+ * @param: ack_num, Packet # to ack (host byte order)
+ *
+ */
+static void ack_packet(struct inode *inode, uint16_t ack_num)
+{
+ static uint16_t ack_packet_buf[2];
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ /* Packet number to ack */
+ ack_packet_buf[0] = TFTP_ACK;
+ ack_packet_buf[1] = htons(ack_num);
+
+ net_core_send(socket, ack_packet_buf, 4);
+}
+
+/*
+ * Get a fresh packet if the buffer is drained, and we haven't hit
+ * EOF yet. The buffer should be filled immediately after draining!
+ */
+static void tftp_get_packet(struct inode *inode)
+{
+ uint16_t last_pkt;
+ const uint8_t *timeout_ptr;
+ uint8_t timeout;
+ uint16_t buffersize;
+ uint16_t serial;
+ jiffies_t oldtime;
+ struct tftp_packet *pkt = NULL;
+ uint16_t buf_len;
+ struct pxe_pvt_inode *socket = PVT(inode);
+ uint16_t src_port;
+ uint32_t src_ip;
+ int err;
+
+ /*
+ * Start by ACKing the previous packet; this should cause
+ * the next packet to be sent.
+ */
+ timeout_ptr = TimeoutTable;
+ timeout = *timeout_ptr++;
+ oldtime = jiffies();
+
+ ack_again:
+ ack_packet(inode, socket->tftp_lastpkt);
+
+ while (timeout) {
+ buf_len = socket->tftp_blksize + 4;
+ err = net_core_recv(socket, socket->tftp_pktbuf, &buf_len,
+ &src_ip, &src_port);
+ if (err) {
+ jiffies_t now = jiffies();
+
+ if (now-oldtime >= timeout) {
+ oldtime = now;
+ timeout = *timeout_ptr++;
+ if (!timeout)
+ break;
+ goto ack_again;
+ }
+ continue;
+ }
+
+ if (buf_len < 4) /* Bad size for a DATA packet */
+ continue;
+
+ pkt = (struct tftp_packet *)(socket->tftp_pktbuf);
+ if (pkt->opcode != TFTP_DATA) /* Not a data packet */
+ continue;
+
+ /* If goes here, recevie OK, break */
+ break;
+ }
+
+ /* time runs out */
+ if (timeout == 0)
+ kaboom();
+
+ last_pkt = socket->tftp_lastpkt;
+ last_pkt++;
+ serial = ntohs(pkt->serial);
+ if (serial != last_pkt) {
+ /*
+ * Wrong packet, ACK the packet and try again.
+ * This is presumably because the ACK got lost,
+ * so the server just resent the previous packet.
+ */
+#if 0
+ printf("Wrong packet, wanted %04x, got %04x\n", \
+ htons(last_pkt), htons(*(uint16_t *)(data+2)));
+#endif
+ goto ack_again;
+ }
+
+ /* It's the packet we want. We're also EOF if the size < blocksize */
+ socket->tftp_lastpkt = last_pkt; /* Update last packet number */
+ buffersize = buf_len - 4; /* Skip TFTP header */
+ socket->tftp_dataptr = socket->tftp_pktbuf + 4;
+ socket->tftp_filepos += buffersize;
+ socket->tftp_bytesleft = buffersize;
+ if (buffersize < socket->tftp_blksize) {
+ /* it's the last block, ACK packet immediately */
+ ack_packet(inode, serial);
+
+ /* Make sure we know we are at end of file */
+ inode->size = socket->tftp_filepos;
+ socket->tftp_goteof = 1;
+ tftp_close_file(inode);
+ }
+}
+
+const struct pxe_conn_ops tftp_conn_ops = {
+ .fill_buffer = tftp_get_packet,
+ .close = tftp_close_file,
+};
+
+/**
+ * Open a TFTP connection to the server
+ *
+ * @param:inode, the inode to store our state in
+ * @param:ip, the ip to contact to get the file
+ * @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
+ *
+ */
+void tftp_open(struct url_info *url, int flags, struct inode *inode,
+ const char **redir)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ char *buf;
+ uint16_t buf_len;
+ char *p;
+ char *options;
+ char *data;
+ static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
+ char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail];
+ char reply_packet_buf[PKTBUF_SIZE];
+ const struct tftp_options *tftp_opt;
+ int i = 0;
+ int err;
+ int buffersize;
+ int rrq_len;
+ const uint8_t *timeout_ptr;
+ jiffies_t timeout;
+ jiffies_t oldtime;
+ uint16_t opcode;
+ uint16_t blk_num;
+ uint32_t opdata, *opdata_ptr;
+ uint16_t src_port;
+ uint32_t src_ip;
+
+ (void)redir; /* TFTP does not redirect */
+ (void)flags;
+
+ if (url->type != URL_OLD_TFTP) {
+ /*
+ * The TFTP URL specification allows the TFTP to end with a
+ * ;mode= which we just ignore.
+ */
+ url_unescape(url->path, ';');
+ }
+
+ if (!url->port)
+ url->port = TFTP_PORT;
+
+ socket->ops = &tftp_conn_ops;
+ if (net_core_open(socket, NET_CORE_UDP))
+ return;
+
+ buf = rrq_packet_buf;
+ *(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */
+ buf += 2;
+
+ buf = stpcpy(buf, url->path);
+
+ buf++; /* Point *past* the final NULL */
+ memcpy(buf, rrq_tail, sizeof rrq_tail);
+ buf += sizeof rrq_tail;
+
+ rrq_len = buf - rrq_packet_buf;
+
+ timeout_ptr = TimeoutTable; /* Reset timeout */
+sendreq:
+ net_core_disconnect(socket);
+ timeout = *timeout_ptr++;
+ if (!timeout)
+ return; /* No file available... */
+ oldtime = jiffies();
+
+ net_core_connect(socket, url->ip, url->port);
+ net_core_send(socket, rrq_packet_buf, rrq_len);
+
+ /* If the WRITE call fails, we let the timeout take care of it... */
+wait_pkt:
+ net_core_disconnect(socket);
+ for (;;) {
+ buf_len = sizeof(reply_packet_buf);
+
+ err = net_core_recv(socket, reply_packet_buf, &buf_len,
+ &src_ip, &src_port);
+ if (err) {
+ jiffies_t now = jiffies();
+ if (now - oldtime >= timeout)
+ goto sendreq;
+ } else {
+ /* Make sure the packet actually came from the server */
+ if (src_ip == url->ip)
+ break;
+ }
+ }
+
+ net_core_disconnect(socket);
+ net_core_connect(socket, src_ip, src_port);
+
+ /* filesize <- -1 == unknown */
+ inode->size = -1;
+ socket->tftp_blksize = TFTP_BLOCKSIZE;
+ buffersize = buf_len - 2; /* bytes after opcode */
+ if (buffersize < 0)
+ goto wait_pkt; /* Garbled reply */
+
+ /*
+ * Get the opcode type, and parse it
+ */
+ opcode = *(uint16_t *)reply_packet_buf;
+ switch (opcode) {
+ case TFTP_ERROR:
+ inode->size = 0;
+ goto done; /* ERROR reply; don't try again */
+
+ case TFTP_DATA:
+ /*
+ * If the server doesn't support any options, we'll get a
+ * DATA reply instead of OACK. Stash the data in the file
+ * buffer and go with the default value for all options...
+ *
+ * We got a DATA packet, meaning no options are
+ * suported. Save the data away and consider the
+ * length undefined, *unless* this is the only
+ * data packet...
+ */
+ buffersize -= 2;
+ if (buffersize < 0)
+ goto wait_pkt;
+ data = reply_packet_buf + 2;
+ blk_num = ntohs(*(uint16_t *)data);
+ data += 2;
+ if (blk_num != 1)
+ goto wait_pkt;
+ socket->tftp_lastpkt = blk_num;
+ if (buffersize > TFTP_BLOCKSIZE)
+ goto err_reply; /* Corrupt */
+
+ socket->tftp_pktbuf = malloc(TFTP_BLOCKSIZE + 4);
+ if (!socket->tftp_pktbuf)
+ goto err_reply; /* Internal error */
+
+ if (buffersize < TFTP_BLOCKSIZE) {
+ /*
+ * This is the final EOF packet, already...
+ * We know the filesize, but we also want to
+ * ack the packet and set the EOF flag.
+ */
+ inode->size = buffersize;
+ socket->tftp_goteof = 1;
+ ack_packet(inode, blk_num);
+ }
+
+ socket->tftp_bytesleft = buffersize;
+ socket->tftp_dataptr = socket->tftp_pktbuf;
+ memcpy(socket->tftp_pktbuf, data, buffersize);
+ goto done;
+
+ case TFTP_OACK:
+ /*
+ * Now we need to parse the OACK packet to get the transfer
+ * and packet sizes.
+ */
+
+ options = reply_packet_buf + 2;
+ p = options;
+
+ while (buffersize) {
+ const char *opt = p;
+
+ /*
+ * If we find an option which starts with a NUL byte,
+ * (a null option), we're either seeing garbage that some
+ * TFTP servers add to the end of the packet, or we have
+ * no clue how to parse the rest of the packet (what is
+ * an option name and what is a value?) In either case,
+ * discard the rest.
+ */
+ if (!*opt)
+ goto done;
+
+ while (buffersize) {
+ if (!*p)
+ break; /* Found a final null */
+ *p++ |= 0x20;
+ buffersize--;
+ }
+ if (!buffersize)
+ break; /* Unterminated option */
+
+ /* Consume the terminal null */
+ p++;
+ buffersize--;
+
+ if (!buffersize)
+ break; /* No option data */
+
+ /*
+ * Parse option pointed to by options; guaranteed to be
+ * null-terminated
+ */
+ tftp_opt = tftp_options;
+ for (i = 0; i < tftp_nopts; i++) {
+ if (!strcmp(opt, tftp_opt->str_ptr))
+ break;
+ tftp_opt++;
+ }
+ if (i == tftp_nopts)
+ goto err_reply; /* Non-negotitated option returned,
+ no idea what it means ...*/
+
+ /* get the address of the filed that we want to write on */
+ opdata_ptr = (uint32_t *)((char *)inode + tftp_opt->offset);
+ opdata = 0;
+
+ /* do convert a number-string to decimal number, just like atoi */
+ while (buffersize--) {
+ uint8_t d = *p++;
+ if (d == '\0')
+ break; /* found a final null */
+ d -= '0';
+ if (d > 9)
+ goto err_reply; /* Not a decimal digit */
+ opdata = opdata*10 + d;
+ }
+ *opdata_ptr = opdata;
+ }
+
+ if (socket->tftp_blksize < 64 || socket->tftp_blksize > PKTBUF_SIZE)
+ goto err_reply;
+
+ /* Parsing successful, allocate buffer */
+ socket->tftp_pktbuf = malloc(socket->tftp_blksize + 4);
+ if (!socket->tftp_pktbuf)
+ goto err_reply;
+ else
+ goto done;
+
+ default:
+ printf("TFTP unknown opcode %d\n", ntohs(opcode));
+ goto err_reply;
+ }
+
+err_reply:
+ /* Build the TFTP error packet */
+ tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
+ inode->size = 0;
+
+done:
+ if (!inode->size)
+ net_core_close(socket);
+
+ return;
+}
diff --git a/core/fs/pxe/tftp.h b/core/fs/pxe/tftp.h
new file mode 100644
index 00000000..114c221f
--- /dev/null
+++ b/core/fs/pxe/tftp.h
@@ -0,0 +1,54 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * tftp.h
+ */
+#ifndef PXE_TFTP_H
+#define PXE_TFTP_H
+
+/*
+ * TFTP default port number
+ */
+#define TFTP_PORT 69
+
+/*
+ * TFTP default block size
+ */
+#define TFTP_BLOCKSIZE_LG2 9
+#define TFTP_BLOCKSIZE (1 << TFTP_BLOCKSIZE_LG2)
+
+/*
+ * TFTP operation codes
+ */
+#define TFTP_RRQ htons(1) // Read rest
+#define TFTP_WRQ htons(2) // Write rest
+#define TFTP_DATA htons(3) // Data packet
+#define TFTP_ACK htons(4) // ACK packet
+#define TFTP_ERROR htons(5) // ERROR packet
+#define TFTP_OACK htons(6) // OACK packet
+
+/*
+ * TFTP error codes
+ */
+#define TFTP_EUNDEF htons(0) // Unspecified error
+#define TFTP_ENOTFOUND htons(1) // File not found
+#define TFTP_EACCESS htons(2) // Access violation
+#define TFTP_ENOSPACE htons(3) // Disk full
+#define TFTP_EBADOP htons(4) // Invalid TFTP operation
+#define TFTP_EBADID htons(5) // Unknown transfer
+#define TFTP_EEXISTS htons(6) // File exists
+#define TFTP_ENOUSER htons(7) // No such user
+#define TFTP_EOPTNEG htons(8) // Option negotiation failure
+
+#endif /* PXE_TFTP_H */
diff --git a/core/fs/pxe/url.h b/core/fs/pxe/url.h
new file mode 100644
index 00000000..53984f3a
--- /dev/null
+++ b/core/fs/pxe/url.h
@@ -0,0 +1,33 @@
+/*
+ * url.h
+ */
+
+#ifndef CORE_PXE_URL_H
+#define CORE_PXE_URL_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+enum url_type {
+ URL_NORMAL, /* It is a full URL */
+ URL_OLD_TFTP, /* It's a ::-style TFTP path */
+ URL_SUFFIX /* Prepend the pathname prefix */
+};
+
+struct url_info {
+ char *scheme;
+ char *user;
+ char *passwd;
+ char *host;
+ uint32_t ip; /* Placeholder field not set by parse_url() */
+ unsigned int port;
+ char *path; /* Includes query */
+ enum url_type type;
+};
+
+enum url_type url_type(const char *url);
+void parse_url(struct url_info *ui, char *url);
+size_t url_escape_unsafe(char *output, const char *input, size_t bufsize);
+char *url_unescape(char *buffer, char terminator);
+
+#endif /* CORE_PXE_URL_H */
diff --git a/core/fs/pxe/urlparse.c b/core/fs/pxe/urlparse.c
new file mode 100644
index 00000000..6b73ddb6
--- /dev/null
+++ b/core/fs/pxe/urlparse.c
@@ -0,0 +1,223 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * urlparse.c
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "url.h"
+
+/*
+ * Return the type of a URL without modifying the string
+ */
+enum url_type url_type(const char *url)
+{
+ const char *q;
+
+ q = strchr(url, ':');
+ if (!q)
+ return URL_SUFFIX;
+
+ if (q[1] == '/' && q[2] == '/')
+ return URL_NORMAL;
+
+ if (q[1] == ':')
+ return URL_OLD_TFTP;
+
+ return URL_SUFFIX;
+}
+
+/*
+ * Decompose a URL into its components. This is done in-place;
+ * this routine does not allocate any additional storage. Freeing the
+ * original buffer frees all storage used.
+ */
+void parse_url(struct url_info *ui, char *url)
+{
+ char *p = url;
+ char *q, *r, *s;
+ int c;
+
+ memset(ui, 0, sizeof *ui);
+
+ q = strchr(p, ':');
+ if (q && (q[1] == '/' && q[2] == '/')) {
+ ui->type = URL_NORMAL;
+
+ ui->scheme = p;
+ *q = '\0';
+ p = q+3;
+
+ q = strchr(p, '/');
+ if (q) {
+ *q = '\0';
+ ui->path = q+1;
+ q = strchr(q+1, '#');
+ if (q)
+ *q = '\0';
+ } else {
+ ui->path = "";
+ }
+
+ r = strchr(p, '@');
+ if (r) {
+ ui->user = p;
+ *r = '\0';
+ s = strchr(p, ':');
+ if (s) {
+ *s = '\0';
+ ui->passwd = s+1;
+ }
+ p = r+1;
+ }
+
+ ui->host = p;
+ r = strchr(p, ':');
+ if (r) {
+ *r++ = '\0';
+ ui->port = 0;
+ while ((c = *r++)) {
+ c -= '0';
+ if (c > 9)
+ break;
+ ui->port = ui->port * 10 + c;
+ }
+ }
+ } else if (q && q[1] == ':') {
+ *q = '\0';
+ ui->scheme = "tftp";
+ ui->host = p;
+ ui->path = q+2;
+ ui->type = URL_OLD_TFTP;
+ } else {
+ ui->path = p;
+ ui->type = URL_SUFFIX;
+ }
+}
+
+/*
+ * Escapes unsafe characters in a URL.
+ * This does *not* escape things like query characters!
+ * Returns the number of characters in the total output.
+ */
+size_t url_escape_unsafe(char *output, const char *input, size_t bufsize)
+{
+ static const char uchexchar[] = "0123456789ABCDEF";
+ const char *p;
+ unsigned char c;
+ char *q;
+ size_t n = 0;
+
+ q = output;
+ for (p = input; (c = *p); p++) {
+ if (c <= ' ' || c > '~') {
+ if (++n < bufsize) *q++ = '%';
+ if (++n < bufsize) *q++ = uchexchar[c >> 4];
+ if (++n < bufsize) *q++ = uchexchar[c & 15];
+ } else {
+ if (++n < bufsize) *q++ = c;
+ }
+ }
+
+ *q = '\0';
+ return n;
+}
+
+static int hexdigit(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ c |= 0x20;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+/*
+ * Unescapes a buffer, optionally ending at an *unescaped* terminator
+ * (like ; for TFTP). The unescaping is done in-place.
+ *
+ * If a terminator is reached, return a pointer to the first character
+ * after the terminator.
+ */
+char *url_unescape(char *buffer, char terminator)
+{
+ char *p = buffer;
+ char *q = buffer;
+ unsigned char c;
+ int x, y;
+
+ while ((c = *p)) {
+ if (c == terminator) {
+ *q = '\0';
+ return p;
+ }
+ p++;
+ if (c == '%') {
+ x = hexdigit(p[0]);
+ if (x >= 0) {
+ y = hexdigit(p[1]);
+ if (y >= 0) {
+ *q++ = (x << 4) + y;
+ p += 2;
+ continue;
+ }
+ }
+ }
+ *q++ = c;
+ }
+ *q = '\0';
+ return NULL;
+}
+
+#ifdef URL_TEST
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct url_info url;
+
+ for (i = 1; i < argc; i++) {
+ parse_url(&url, argv[i]);
+ printf("scheme: %s\n"
+ "user: %s\n"
+ "passwd: %s\n"
+ "host: %s\n"
+ "port: %d\n"
+ "path: %s\n"
+ "type: %d\n",
+ url.scheme, url.user, url.passwd, url.host, url.port,
+ url.path, url.type);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/core/fs/readdir.c b/core/fs/readdir.c
index e2d593fc..546a704a 100644
--- a/core/fs/readdir.c
+++ b/core/fs/readdir.c
@@ -1,3 +1,4 @@
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/dirent.h>
@@ -12,7 +13,7 @@ __export DIR *opendir(const char *path)
int rv;
struct file *file;
- rv = searchdir(path);
+ rv = searchdir(path, O_RDONLY|O_DIRECTORY);
if (rv < 0)
return NULL;
diff --git a/core/head.inc b/core/head.inc
index 71eb5744..286b9b4e 100644
--- a/core/head.inc
+++ b/core/head.inc
@@ -34,5 +34,6 @@
%include "tracers.inc"
%include "stack.inc"
%include "io.inc"
+%include "vkernel.inc"
%endif ; _HEAD_INC
diff --git a/core/idle.c b/core/idle.c
index 9514df88..a089b088 100644
--- a/core/idle.c
+++ b/core/idle.c
@@ -1,5 +1,5 @@
-/* -*- fundamental -*- ---------------------------------------------------
- *
+/* ----------------------------------------------------------------------- *
+ *
* Copyright 2008 H. Peter Anvin - All Rights Reserved
* Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
*
@@ -24,7 +24,7 @@
#define TICKS_TO_IDLE 4 /* Also in idle.inc */
-extern uint32_t _IdleTimer;
+extern jiffies_t _IdleTimer;
__export uint16_t NoHalt = 0;
int (*idle_hook_func)(void);
diff --git a/core/include/core.h b/core/include/core.h
index aa3bfb7a..1d20040a 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -11,6 +11,9 @@
#include <com32.h>
#include <errno.h>
#include <syslinux/pmapi.h>
+#include <syslinux/sysappend.h>
+#include <kaboom.h>
+#include <timer.h>
extern char core_xfer_buf[65536];
extern char core_cache_buf[65536];
@@ -45,6 +48,10 @@ extern uint16_t DisplayCon;
/* diskstart.inc isolinux.asm*/
extern void getlinsec(void);
+/* pm.inc */
+void core_pm_null_hook(void);
+extern void (*core_pm_hook)(void);
+
/* getc.inc */
extern void core_open(void);
@@ -63,6 +70,12 @@ extern void *zalloc(size_t);
extern void free(void *);
extern void mem_init(void);
+/* sysappend.c */
+extern void print_sysappend(void);
+extern const char *sysappend_strings[SYSAPPEND_MAX];
+extern uint32_t SysAppends;
+extern void sysappend_set_uuid(const uint8_t *uuid);
+
void __cdecl core_intcall(uint8_t, const com32sys_t *, com32sys_t *);
void __cdecl core_farcall(uint32_t, const com32sys_t *, com32sys_t *);
int __cdecl core_cfarcall(uint32_t, const void *, uint32_t);
@@ -77,31 +90,6 @@ void call16(void (*)(void), const com32sys_t *, com32sys_t *);
#define __bss16 __attribute__((nocommon,section(".bss16")))
/*
- * Section for very large aligned objects, not zeroed on startup
- */
-#define __hugebss __attribute__((nocommon,section(".hugebss"),aligned(4096)))
-
-/*
- * Death! The macro trick is to avoid symbol conflict with
- * the real-mode symbol kaboom.
- */
-__noreturn _kaboom(void);
-#define kaboom() _kaboom()
-
-/*
- * Basic timer function...
- */
-extern volatile uint32_t __jiffies, __ms_timer;
-static inline uint32_t jiffies(void)
-{
- return __jiffies;
-}
-static inline uint32_t ms_timer(void)
-{
- return __ms_timer;
-}
-
-/*
* Helper routine to return a specific set of flags
*/
static inline void set_flags(com32sys_t *regs, uint32_t flags)
@@ -114,7 +102,7 @@ static inline void set_flags(com32sys_t *regs, uint32_t flags)
regs->eflags.l = eflags;
}
-extern int start_ldlinux(char **argv);
+extern int start_ldlinux(int argc, char **argv);
extern int create_args_and_load(char *);
extern void write_serial(char data);
@@ -128,7 +116,11 @@ extern void cleanup_hardware(void);
extern void sirq_cleanup(void);
extern void adjust_screen(void);
-extern void execute(const char *cmdline, uint32_t type);
+extern void execute(const char *cmdline, uint32_t type, bool sysappend);
extern void load_kernel(const char *cmdline);
+extern void dmi_init(void);
+
+extern void do_sysappend(char *buf);
+
#endif /* CORE_H */
diff --git a/core/include/ctype.h b/core/include/ctype.h
index 048a77d6..6c7f57f4 100644
--- a/core/include/ctype.h
+++ b/core/include/ctype.h
@@ -22,9 +22,17 @@ static inline int tolower(int c)
return c;
}
-static inline int isspace(int c)
+static inline int isspace(int ch)
{
- return c <= ' ';
+ int space = 0;
+ if ((ch == ' ') ||
+ (ch == '\f') ||
+ (ch == '\n') ||
+ (ch == '\r') ||
+ (ch == '\t') ||
+ (ch == '\v'))
+ space = 1;
+ return space;
}
#endif /* CTYPE_H */
diff --git a/core/include/fs.h b/core/include/fs.h
index 560458b6..b4519cee 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -12,12 +12,9 @@
#include "disk.h"
/*
- * Maximum number of open files. This is *currently* constrained by the
- * fact that PXE needs to be able to fit all its packet buffers into a
- * 64K segment; this should be fixed by moving the packet buffers to high
- * memory.
+ * Maximum number of open files.
*/
-#define MAX_OPEN_LG2 5
+#define MAX_OPEN_LG2 7
#define MAX_OPEN (1 << MAX_OPEN_LG2)
#define FILENAME_MAX_LG2 8
@@ -56,7 +53,7 @@ struct fs_ops {
enum fs_flags fs_flags;
int (*fs_init)(struct fs_info *);
- void (*searchdir)(const char *, struct file *);
+ void (*searchdir)(const char *, int, struct file *);
uint32_t (*getfssec)(struct file *, char *, int, bool *);
void (*close_file)(struct file *);
void (*mangle_name)(char *, const char *);
@@ -192,10 +189,10 @@ void fs_init(const struct fs_ops **ops, void *priv);
void pm_mangle_name(com32sys_t *);
void pm_searchdir(com32sys_t *);
void mangle_name(char *, const char *);
-int searchdir(const char *name);
+int searchdir(const char *name, int flags);
void _close_file(struct file *);
size_t pmapi_read_file(uint16_t *handle, void *buf, size_t sectors);
-int open_file(const char *name, struct com32_filedata *filedata);
+int open_file(const char *name, int flags, struct com32_filedata *filedata);
void pm_open_file(com32sys_t *);
void close_file(uint16_t handle);
void pm_close_file(com32sys_t *);
diff --git a/core/include/kaboom.h b/core/include/kaboom.h
new file mode 100644
index 00000000..4a763be9
--- /dev/null
+++ b/core/include/kaboom.h
@@ -0,0 +1,11 @@
+#ifndef KABOOM_H
+#define KABOOM_H
+
+/*
+ * Death! The macro trick is to avoid symbol conflict with
+ * the real-mode symbol kaboom.
+ */
+__noreturn _kaboom(void);
+#define kaboom() _kaboom()
+
+#endif /* KABOOM_H */
diff --git a/core/include/mbox.h b/core/include/mbox.h
new file mode 100644
index 00000000..3c35ce4e
--- /dev/null
+++ b/core/include/mbox.h
@@ -0,0 +1,59 @@
+/*
+ * mbox.h
+ *
+ * Simple thread mailbox interface
+ */
+
+#ifndef _MBOX_H
+#define _MBOX_H
+
+#include "thread.h"
+
+/*
+ * If a mailbox is allocated statically (as a struct mailbox), this
+ * is the number of slots it gets.
+ */
+#define MAILBOX_STATIC_SIZE 512
+
+struct mailbox {
+ struct semaphore prod_sem; /* Producer semaphore (empty slots) */
+ struct semaphore cons_sem; /* Consumer semaphore (data slots) */
+ struct semaphore head_sem; /* Head pointer semaphore */
+ struct semaphore tail_sem; /* Tail pointer semaphore */
+ void **wrap; /* Where pointers wrap */
+ void **head; /* Head pointer */
+ void **tail; /* Tail pointer */
+
+ void *data[MAILBOX_STATIC_SIZE]; /* Data array */
+};
+
+/* The number of bytes for an mailbox of size s */
+#define MBOX_BYTES(s) (sizeof(struct mailbox) + \
+ ((s)-MAILBOX_STATIC_SIZE)*sizeof(void *))
+
+void mbox_init(struct mailbox *mbox, size_t size);
+int mbox_post(struct mailbox *mbox, void *msg, mstime_t timeout);
+mstime_t mbox_fetch(struct mailbox *mbox, void **msg, mstime_t timeout);
+
+/*
+ * This marks a mailbox object as unusable; it will remain unusable
+ * until sem_init() is called on it again. This DOES NOT clear the
+ * list of blocked processes on this mailbox!
+ *
+ * It is also possible to mark the mailbox invalid by zeroing its
+ * memory structure.
+ */
+static inline void mbox_set_invalid(struct mailbox *mbox)
+{
+ sem_set_invalid(&mbox->prod_sem);
+}
+
+/*
+ * Ask if a mailbox object has been initialized.
+ */
+static inline bool mbox_is_valid(struct mailbox *mbox)
+{
+ return sem_is_valid(&mbox->prod_sem);
+}
+
+#endif /* _MBOX_H */
diff --git a/core/include/net.h b/core/include/net.h
new file mode 100644
index 00000000..4f6819f9
--- /dev/null
+++ b/core/include/net.h
@@ -0,0 +1,33 @@
+#ifndef _NET_H
+#define _NET_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Protocol family */
+enum net_core_proto {
+ NET_CORE_TCP,
+ NET_CORE_UDP,
+};
+
+void net_core_init(void);
+
+struct pxe_pvt_inode;
+
+int net_core_open(struct pxe_pvt_inode *socket, enum net_core_proto proto);
+void net_core_close(struct pxe_pvt_inode *socket);
+
+void net_core_connect(struct pxe_pvt_inode *socket,
+ uint32_t ip, uint16_t port);
+void net_core_disconnect(struct pxe_pvt_inode *socket);
+
+int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
+ uint32_t *src_ip, uint16_t *src_port);
+
+void net_core_send(struct pxe_pvt_inode *socket,
+ const void *data, size_t len);
+
+void probe_undi(void);
+void pxe_init_isr(void);
+
+#endif /* _NET_H */
diff --git a/core/include/thread.h b/core/include/thread.h
new file mode 100644
index 00000000..6bfdfaa7
--- /dev/null
+++ b/core/include/thread.h
@@ -0,0 +1,115 @@
+#ifndef _THREAD_H
+#define _THREAD_H
+
+#include <stddef.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <timer.h>
+#include <sys/cpu.h>
+
+/* The idle thread runs at this priority */
+#define IDLE_THREAD_PRIORITY INT_MAX
+
+/* This priority should normally be used for hardware-polling threads */
+#define POLL_THREAD_PRIORITY (INT_MAX-1)
+
+struct semaphore;
+
+struct thread_list {
+ struct thread_list *next, *prev;
+};
+
+/*
+ * Stack frame used by __switch_to, see thread_asm.S
+ */
+struct thread_stack {
+ int errno;
+ uint16_t rmsp, rmss;
+ uint32_t edi, esi, ebp, ebx;
+ void (*eip)(void);
+};
+
+struct thread_block {
+ struct thread_list list;
+ struct thread *thread;
+ struct semaphore *semaphore;
+ mstime_t block_time;
+ mstime_t timeout;
+ bool timed_out;
+};
+
+#define THREAD_MAGIC 0x3568eb7d
+
+struct thread {
+ struct thread_stack *esp; /* Must be first; stack pointer */
+ unsigned int thread_magic;
+ const char *name; /* Name (for debugging) */
+ struct thread_list list;
+ struct thread_block *blocked;
+ void *stack, *rmstack; /* Stacks, iff allocated by malloc/lmalloc */
+ void *pvt; /* For the benefit of lwIP */
+ int prio;
+};
+
+extern void (*sched_hook_func)(void);
+
+void __thread_process_timeouts(void);
+void __schedule(void);
+void __switch_to(struct thread *);
+void thread_yield(void);
+
+extern struct thread *__current;
+static inline struct thread *current(void)
+{
+ return __current;
+}
+
+struct semaphore {
+ int count;
+ struct thread_list list;
+};
+
+#define DECLARE_INIT_SEMAPHORE(sem, cnt) \
+ struct semaphore sem = { \
+ .count = (cnt), \
+ .list = { \
+ .next = &sem.list, \
+ .prev = &sem.list \
+ } \
+ }
+
+mstime_t sem_down(struct semaphore *, mstime_t);
+void sem_up(struct semaphore *);
+void sem_init(struct semaphore *, int);
+
+/*
+ * This marks a semaphore object as unusable; it will remain unusable
+ * until sem_init() is called on it again. This DOES NOT clear the
+ * list of blocked processes on this semaphore!
+ *
+ * It is also possible to mark the semaphore invalid by zeroing its
+ * memory structure.
+ */
+static inline void sem_set_invalid(struct semaphore *sem)
+{
+ sem->list.next = NULL;
+}
+
+/*
+ * Ask if a semaphore object has been initialized.
+ */
+static inline bool sem_is_valid(struct semaphore *sem)
+{
+ return !!sem->list.next;
+}
+
+struct thread *start_thread(const char *name, size_t stack_size, int prio,
+ void (*start_func)(void *), void *func_arg);
+void __exit_thread(void);
+void kill_thread(struct thread *);
+
+void start_idle_thread(void);
+void test_thread(void);
+
+#endif /* _THREAD_H */
diff --git a/core/include/timer.h b/core/include/timer.h
new file mode 100644
index 00000000..1d66ba73
--- /dev/null
+++ b/core/include/timer.h
@@ -0,0 +1,21 @@
+#ifndef TIMER_H
+#define TIMER_H
+
+/*
+ * Basic timer function...
+ */
+typedef uint32_t jiffies_t;
+extern volatile jiffies_t __jiffies, __ms_timer;
+static inline jiffies_t jiffies(void)
+{
+ return __jiffies;
+}
+
+typedef uint32_t mstime_t;
+typedef int32_t mstimediff_t;
+static inline mstime_t ms_timer(void)
+{
+ return __ms_timer;
+}
+
+#endif /* TIMER_H */
diff --git a/core/isolinux.asm b/core/isolinux.asm
index b54beb4a..bd4e9556 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -35,23 +35,6 @@ SECTOR_SIZE equ (1 << SECTOR_SHIFT)
ROOT_DIR_WORD equ 0x002F
-;
-; The following structure is used for "virtual kernels"; i.e. LILO-style
-; option labels. The options we permit here are `kernel' and `append
-; Since there is no room in the bottom 64K for all of these, we
-; stick them in high memory and copy them down before we need them.
-;
- struc vkernel
-vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
-vk_rname: resb FILENAME_MAX ; Real name
-vk_appendlen: resw 1
-vk_type: resb 1 ; Type of file
- alignb 4
-vk_append: resb max_cmd_len+1 ; Command line
- alignb 4
-vk_end: equ $ ; Should be <= vk_size
- endstruc
-
; ---------------------------------------------------------------------------
; BEGIN CODE
; ---------------------------------------------------------------------------
@@ -1219,17 +1202,6 @@ FuncFlag resb 1 ; Escape sequences received from keyboard
KernelType resb 1 ; Kernel type, from vkernel, if known
global KernelName
KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .data16
- global IPAppends, numIPAppends
-%if IS_PXELINUX
- extern IPOption
- alignz 2
-IPAppends dw IPOption
-numIPAppends equ ($-IPAppends)/2
-%else
-IPAppends equ 0
-numIPAppends equ 0
-%endif
section .text16
;
diff --git a/core/keywords b/core/keywords
index 7f585b48..8af0095f 100644
--- a/core/keywords
+++ b/core/keywords
@@ -34,6 +34,8 @@ onerror
noescape
nocomplete
nohalt
+sysappend
+sendcookies
f0
f1
f2
diff --git a/core/keywords.inc b/core/keywords.inc
index 08d77c64..d91ca4ff 100644
--- a/core/keywords.inc
+++ b/core/keywords.inc
@@ -92,9 +92,11 @@ keywd_table:
keyword f0, pc_filename, FKeyN(10)
keyword f11, pc_filename, FKeyN(11)
keyword f12, pc_filename, FKeyN(12)
+ keyword ipappend, pc_sysappend
+ keyword sysappend, pc_sysappend
+ keyword localboot, pc_localboot
%if IS_PXELINUX
- keyword ipappend, pc_ipappend
+ keyword sendcookies, pc_sendcookies
%endif
- keyword localboot, pc_localboot
keywd_count equ ($-keywd_table)/keywd_size
diff --git a/core/layout.inc b/core/layout.inc
index be797ede..53ca783d 100644
--- a/core/layout.inc
+++ b/core/layout.inc
@@ -65,6 +65,7 @@ STACK32_LEN equ 64*1024
section .config write progbits align=4
section .replacestub exec write progbits align=16
section .gentextnr exec write nobits align=16
+ section .stack16 write nobits align=16
; Use .bss16 for things that doesn't have to be in low memory;
; .earlybss should be used for things that absolutely have
diff --git a/core/legacynet/core.c b/core/legacynet/core.c
new file mode 100644
index 00000000..2163c693
--- /dev/null
+++ b/core/legacynet/core.c
@@ -0,0 +1,186 @@
+#include <syslinux/pxe_api.h>
+#include <com32.h>
+#include <core.h>
+#include <net.h>
+#include <pxe.h>
+#include <minmax.h>
+
+/* Common receive buffer */
+static __lowmem char packet_buf[PKTBUF_SIZE] __aligned(16);
+
+extern uint16_t get_port(void);
+extern void free_port(uint16_t);
+
+/**
+ * Open a socket
+ *
+ * @param:socket, the socket to open
+ * @param:proto, the protocol of the new connection
+ *
+ * @out: error code, 0 on success, -1 on failure
+ */
+int net_core_open(struct pxe_pvt_inode *socket __unused,
+ enum net_core_proto proto)
+{
+ struct net_private *priv = &socket->private;
+
+ /* The legacy stack only supports UDP */
+ if (proto != NET_CORE_UDP)
+ return -1;
+
+ /* Allocate local UDP port number */
+ priv->tftp_localport = get_port();
+
+ return 0;
+}
+
+/**
+ * Close a socket
+ *
+ * @param:socket, the socket to open
+ */
+void net_core_close(struct pxe_pvt_inode *socket)
+{
+ struct net_private *priv = &socket->private;
+
+ if (priv->tftp_localport)
+ free_port(priv->tftp_localport);
+}
+
+/**
+ * Establish a connection on an open socket
+ *
+ * @param:socket, the open socket
+ * @param:ip, the ip address
+ * @param:port, the port number, host-byte order
+ */
+void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip,
+ uint16_t port)
+{
+ struct net_private *priv = &socket->private;
+
+ socket->tftp_remoteport = htons(port);
+ priv->tftp_remoteip = ip;
+
+}
+
+/**
+ * Tear down a connection on an open socket
+ *
+ * @param:socket, the open socket
+ */
+void net_core_disconnect(struct pxe_pvt_inode *socket __unused)
+{
+}
+
+/**
+ * Read data from the network stack
+ *
+ * @param:socket, the open socket
+ * @param:buf, location of buffer to store data
+ * @param:buf_len, size of buffer
+
+ * @out: src_ip, ip address of the data source
+ * @out: src_port, port number of the data source, host-byte order
+ */
+int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
+ uint32_t *src_ip, uint16_t *src_port)
+{
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+ struct net_private *priv = &socket->private;
+ uint16_t bytes;
+ int err;
+
+ udp_read.status = 0;
+ udp_read.buffer = FAR_PTR(packet_buf);
+ udp_read.buffer_size = PKTBUF_SIZE;
+ udp_read.dest_ip = IPInfo.myip;
+ udp_read.d_port = priv->tftp_localport;
+
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ if (err)
+ return err;
+
+ if (udp_read.status)
+ return udp_read.status;
+
+ bytes = min(udp_read.buffer_size, *buf_len);
+ memcpy(buf, packet_buf, bytes);
+
+ *src_ip = udp_read.src_ip;
+ *src_port = ntohs(udp_read.s_port);
+ *buf_len = bytes;
+
+ return 0;
+}
+
+/**
+ * Send a UDP packet.
+ *
+ * @param:socket, the open socket
+ * @param:data, data buffer to send
+ * @param:len, size of data bufer
+ */
+void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
+{
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ struct net_private *priv = &socket->private;
+ void *lbuf;
+ uint16_t tid;
+
+ lbuf = lmalloc(len);
+ if (!lbuf)
+ return;
+
+ memcpy(lbuf, data, len);
+
+ tid = priv->tftp_localport; /* TID(local port No) */
+ udp_write.buffer = FAR_PTR(lbuf);
+ udp_write.ip = priv->tftp_remoteip;
+ udp_write.gw = gateway(udp_write.ip);
+ udp_write.src_port = tid;
+ udp_write.dst_port = socket->tftp_remoteport;
+ udp_write.buffer_size = len;
+
+ pxe_call(PXENV_UDP_WRITE, &udp_write);
+
+ lfree(lbuf);
+}
+
+/**
+ * Network stack-specific initialization
+ *
+ * Initialize UDP stack
+ */
+void net_core_init(void)
+{
+ int err;
+ static __lowmem struct s_PXENV_UDP_OPEN udp_open;
+ 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 ");
+ printf("%d\n", udp_open.status);
+ kaboom();
+ }
+}
+
+void probe_undi(void)
+{
+}
+
+void pxe_init_isr(void)
+{
+}
+
+int reset_pxe(void)
+{
+ static __lowmem struct s_PXENV_UDP_CLOSE udp_close;
+ int err = 0;
+
+ pxe_idle_cleanup();
+
+ pxe_call(PXENV_UDP_CLOSE, &udp_close);
+
+ return err;
+}
diff --git a/core/legacynet/dnsresolv.c b/core/legacynet/dnsresolv.c
new file mode 100644
index 00000000..fab36aef
--- /dev/null
+++ b/core/legacynet/dnsresolv.c
@@ -0,0 +1,353 @@
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include "pxe.h"
+
+/* DNS CLASS values we care about */
+#define CLASS_IN 1
+
+/* DNS TYPE values we care about */
+#define TYPE_A 1
+#define TYPE_CNAME 5
+
+/*
+ * The DNS header structure
+ */
+struct dnshdr {
+ uint16_t id;
+ uint16_t flags;
+ /* number of entries in the question section */
+ uint16_t qdcount;
+ /* number of resource records in the answer section */
+ uint16_t ancount;
+ /* number of name server resource records in the authority records section*/
+ uint16_t nscount;
+ /* number of resource records in the additional records section */
+ uint16_t arcount;
+} __attribute__ ((packed));
+
+/*
+ * The DNS query structure
+ */
+struct dnsquery {
+ uint16_t qtype;
+ uint16_t qclass;
+} __attribute__ ((packed));
+
+/*
+ * The DNS Resource recodes structure
+ */
+struct dnsrr {
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t rdlength; /* The lenght of this rr data */
+ char rdata[];
+} __attribute__ ((packed));
+
+
+#define DNS_PORT htons(53) /* Default DNS port */
+#define DNS_MAX_SERVERS 4 /* Max no of DNS servers */
+
+uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
+
+
+/*
+ * 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)
+{
+ char *q = *dst;
+ char *count_ptr;
+ char c;
+ int dots = 0;
+
+ count_ptr = q;
+ *q++ = 0;
+
+ while (1) {
+ c = *p++;
+ if (c == 0 || c == ':' || c == '/')
+ break;
+ if (c == '.') {
+ dots++;
+ count_ptr = q;
+ *q++ = 0;
+ continue;
+ }
+
+ *count_ptr += 1;
+ *q++ = c;
+ }
+
+ if (*count_ptr)
+ *q++ = 0;
+
+ /* update the strings */
+ *dst = q;
+ return dots;
+}
+
+
+/*
+ * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_
+ * is allowed pointers relative to a packet in buf.
+ *
+ */
+static bool dns_compare(const void *s1, const void *s2, const void *buf)
+{
+ const uint8_t *q = s1;
+ const uint8_t *p = s2;
+ unsigned int c0, c1;
+
+ while (1) {
+ c0 = p[0];
+ if (c0 >= 0xc0) {
+ /* Follow pointer */
+ c1 = p[1];
+ p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
+ } else if (c0) {
+ c0++; /* Include the length byte */
+ if (memcmp(q, p, c0))
+ return false;
+ q += c0;
+ p += c0;
+ } else {
+ return *q == 0;
+ }
+ }
+}
+
+/*
+ * Copy a DNS label into a buffer, considering the possibility that we might
+ * have to follow pointers relative to "buf".
+ * Returns a pointer to the first free byte *after* the terminal null.
+ */
+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) {
+ /* Follow pointer */
+ c1 = p[1];
+ p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
+ } else if (c0) {
+ c0++; /* Include the length byte */
+ memcpy(q, p, c0);
+ p += c0;
+ q += c0;
+ } else {
+ *q++ = 0;
+ return q;
+ }
+ }
+}
+
+/*
+ * Skip past a DNS label set in DS:SI
+ */
+static char *dns_skiplabel(char *label)
+{
+ uint8_t c;
+
+ while (1) {
+ c = *label++;
+ if (c >= 0xc0)
+ return ++label; /* pointer is two bytes */
+ if (c == 0)
+ return label;
+ label += c;
+ }
+}
+
+extern const uint8_t TimeoutTable[];
+extern uint16_t get_port(void);
+extern void free_port(uint16_t port);
+
+/*
+ * Actual resolver function
+ * Points to a null-terminated or :-terminated string in _name_
+ * and returns the ip addr in _ip_ if it exists and can be found.
+ * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
+ *
+ * XXX: probably need some caching here.
+ */
+__export uint32_t dns_resolv(const char *name)
+{
+ static char __lowmem DNSSendBuf[PKTBUF_SIZE];
+ static char __lowmem DNSRecvBuf[PKTBUF_SIZE];
+ char *p;
+ int err;
+ int dots;
+ int same;
+ int rd_len;
+ int ques, reps; /* number of questions and replies */
+ uint8_t timeout;
+ const uint8_t *timeout_ptr = TimeoutTable;
+ uint32_t oldtime;
+ uint32_t srv;
+ uint32_t *srv_ptr;
+ struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf;
+ 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;
+ uint16_t local_port;
+ uint32_t result = 0;
+
+ /*
+ * Return failure on an empty input... this can happen during
+ * some types of URL parsing, and this is the easiest place to
+ * check for it.
+ */
+ if (!name || !*name)
+ return 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();
+
+ /* First, fill the DNS header struct */
+ hd1->id++; /* New query ID */
+ hd1->flags = htons(0x0100); /* Recursion requested */
+ hd1->qdcount = htons(1); /* One question */
+ 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 */
+ p = stpcpy(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++;
+ 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 = 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)
+ continue;
+
+ oldtime = jiffies();
+ do {
+ if (jiffies() - oldtime >= timeout)
+ goto again;
+
+ udp_read.status = 0;
+ udp_read.src_ip = srv;
+ udp_read.dest_ip = IPInfo.myip;
+ udp_read.s_port = DNS_PORT;
+ udp_read.d_port = local_port;
+ udp_read.buffer_size = PKTBUF_SIZE;
+ udp_read.buffer = FAR_PTR(DNSRecvBuf);
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ } while (err || udp_read.status || hd2->id != hd1->id);
+
+ if ((hd2->flags ^ 0x80) & htons(0xf80f))
+ goto badness;
+
+ ques = htons(hd2->qdcount); /* Questions */
+ reps = htons(hd2->ancount); /* Replies */
+ p = DNSRecvBuf + sizeof(struct dnshdr);
+ while (ques--) {
+ p = dns_skiplabel(p); /* Skip name */
+ p += 4; /* Skip question trailer */
+ }
+
+ /* Parse the replies */
+ while (reps--) {
+ same = dns_compare(DNSSendBuf + sizeof(struct dnshdr),
+ p, DNSRecvBuf);
+ p = dns_skiplabel(p);
+ rr = (struct dnsrr *)p;
+ rd_len = ntohs(rr->rdlength);
+ if (same && ntohs(rr->class) == CLASS_IN) {
+ switch (ntohs(rr->type)) {
+ case TYPE_A:
+ if (rd_len == 4) {
+ result = *(uint32_t *)rr->rdata;
+ goto done;
+ }
+ break;
+ case TYPE_CNAME:
+ dns_copylabel(DNSSendBuf + sizeof(struct dnshdr),
+ rr->rdata, DNSRecvBuf);
+ /*
+ * We should probably rescan the packet from the top
+ * here, and technically we might have to send a whole
+ * new request here...
+ */
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* not the one we want, try next */
+ p += sizeof(struct dnsrr) + rd_len;
+ }
+
+ badness:
+ /*
+ *
+ ; We got back no data from this server.
+ ; Unfortunately, for a recursive, non-authoritative
+ ; query there is no such thing as an NXDOMAIN reply,
+ ; which technically means we can't draw any
+ ; conclusions. However, in practice that means the
+ ; 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))
+ continue;
+
+ break; /* failed */
+
+ again:
+ continue;
+ }
+
+done:
+ free_port(local_port); /* Return port number to the free pool */
+
+ return result;
+}
diff --git a/core/legacynet/idle.c b/core/legacynet/idle.c
new file mode 100644
index 00000000..e0892379
--- /dev/null
+++ b/core/legacynet/idle.c
@@ -0,0 +1,112 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+#include <minmax.h>
+#include <sys/cpu.h>
+#include "pxe.h"
+
+static int pxe_idle_poll(void)
+{
+ static __lowmem char junk_pkt[PKTBUF_SIZE];
+ static __lowmem t_PXENV_UDP_READ read_buf;
+
+ memset(&read_buf, 0, sizeof read_buf);
+
+ read_buf.src_ip = 0; /* Any destination */
+ 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;
+ read_buf.buffer = FAR_PTR(junk_pkt);
+
+ pxe_call(PXENV_UDP_READ, &read_buf);
+
+ return 0;
+}
+
+static uint32_t pxe_detect_nic_type(void)
+{
+ static __lowmem t_PXENV_UNDI_GET_NIC_TYPE nic_type;
+
+ if (pxe_call(PXENV_UNDI_GET_NIC_TYPE, &nic_type))
+ return -1; /* Unknown NIC */
+
+ if (nic_type.NicType != PCI_NIC && nic_type.NicType != CardBus_NIC)
+ return -1; /* Not a PCI NIC */
+
+ /*
+ * Return VID:DID as a single number, with the VID in the high word
+ * -- this is opposite from the usual order, but it makes it easier to
+ * enforce that the table is sorted.
+ */
+ return (nic_type.info.pci.Vendor_ID << 16) + nic_type.info.pci.Dev_ID;
+}
+
+#define PCI_DEV(vid, did) (((vid) << 16) + (did))
+
+/* This array should be sorted!! */
+static const uint32_t pxe_need_idle_drain[] =
+{
+ /*
+ * Older Broadcom NICs: they need receive calls on idle to avoid
+ * FIFO stalls.
+ */
+ PCI_DEV(0x14e4, 0x1659), /* BCM5721 */
+ PCI_DEV(0x14e4, 0x165a), /* BCM5722 */
+ PCI_DEV(0x14e4, 0x165b), /* BCM5723 */
+ PCI_DEV(0x14e4, 0x1668), /* BCM5714 */
+ PCI_DEV(0x14e4, 0x1669), /* BCM5714S */
+ PCI_DEV(0x14e4, 0x166a), /* BCM5780 */
+ PCI_DEV(0x14e4, 0x1673), /* BCM5755M */
+ PCI_DEV(0x14e4, 0x1674), /* BCM5756ME */
+ PCI_DEV(0x14e4, 0x1678), /* BCM5715 */
+ PCI_DEV(0x14e4, 0x1679), /* BCM5715S */
+ PCI_DEV(0x14e4, 0x167b), /* BCM5755 */
+};
+
+void pxe_idle_init(void)
+{
+ uint32_t dev_id = pxe_detect_nic_type();
+ int l, h;
+ bool found;
+
+ l = 0;
+ h = sizeof pxe_need_idle_drain / sizeof pxe_need_idle_drain[0] - 1;
+
+ found = false;
+ while (h >= l) {
+ int x = (l+h) >> 1;
+ uint32_t id = pxe_need_idle_drain[x];
+
+ if (id == dev_id) {
+ found = true;
+ break;
+ } else if (id < dev_id) {
+ l = x+1;
+ } else {
+ h = x-1;
+ }
+ }
+
+ if (found)
+ idle_hook_func = pxe_idle_poll;
+}
+
+void pxe_idle_cleanup(void)
+{
+ idle_hook_func = NULL;
+}
diff --git a/core/fs/pxe/portnum.c b/core/legacynet/portnum.c
index 19af0cd0..e10af29e 100644
--- a/core/fs/pxe/portnum.c
+++ b/core/legacynet/portnum.c
@@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------- *
- *
+ *
* Copyright 2010 Intel Corporation; author: H. Peter Anvin
*
* This program is free software; you can redistribute it and/or modify
diff --git a/core/lwip/CHANGELOG b/core/lwip/CHANGELOG
new file mode 100644
index 00000000..6e27a66b
--- /dev/null
+++ b/core/lwip/CHANGELOG
@@ -0,0 +1,3050 @@
+HISTORY
+
+(CVS HEAD)
+
+ * [Enter new changes just after this line - do not remove this line]
+
+ ++ New features:
+
+
+ ++ Bugfixes:
+
+
+
+
+(STABLE-1.4.0)
+
+ ++ New features:
+
+ 2011-03-27: Simon Goldschmidt
+ * tcp_impl.h, tcp_in.c, tcp_out.c: Removed 'dataptr' from 'struct tcp_seg' and
+ calculate it in tcp_zero_window_probe (the only place where it was used).
+
+ 2010-11-21: Simon Goldschmidt
+ * dhcp.c/.h: Added a function to deallocate the struct dhcp from a netif
+ (fixes bug #31525).
+
+ 2010-07-12: Simon Goldschmidt (patch by Stephane Lesage)
+ * ip.c, udp.c/.h, pbuf.h, sockets.c: task #10495: Added support for
+ IP_MULTICAST_LOOP at socket- and raw-API level.
+
+ 2010-06-16: Simon Goldschmidt
+ * ip.c: Added an optional define (LWIP_IP_ACCEPT_UDP_PORT) that can allow
+ link-layer-addressed UDP traffic to be received while a netif is down (just
+ like DHCP during configuration)
+
+ 2010-05-22: Simon Goldschmidt
+ * many many files: bug #27352: removed packing from ip_addr_t, the packed
+ version is now only used in protocol headers. Added global storage for
+ current src/dest IP address while in input functions.
+
+ 2010-05-16: Simon Goldschmidt
+ * def.h: task #10391: Add preprocessor-macros for compile-time htonl
+ calculation (and use them throughout the stack where applicable)
+
+ 2010-05-16: Simon Goldschmidt
+ * opt.h, memp_std.h, memp.c, ppp_oe.h/.c: PPPoE now uses its own MEMP pool
+ instead of the heap (moved struct pppoe_softc from ppp_oe.c to ppp_oe.h)
+
+ 2010-05-16: Simon Goldschmidt
+ * opt.h, memp_std.h, dns.h/.c: DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own
+ MEMP pool instead of the heap
+
+ 2010-05-13: Simon Goldschmidt
+ * tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly), added
+ new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast
+ packets to more than one pcb.
+
+ 2010-05-02: Simon Goldschmidt
+ * netbuf.h/.c, sockets.c, api_msg.c: use checksum-on-copy for sending
+ UDP data for LWIP_NETIF_TX_SINGLE_PBUF==1
+
+ 2010-04-30: Simon Goldschmidt
+ * udp.h/.c, pbuf.h/.c: task #6849: added udp_send(_to/_if) functions that
+ take a precalculated checksum, added pbuf_fill_chksum() to copy data
+ into a pbuf and at the same time calculating the checksum for that data
+
+ 2010-04-29: Simon Goldschmidt
+ * ip_addr.h, etharp.h/.c, autoip.c: Create overridable macros for copying
+ 2-byte-aligned IP addresses and MAC addresses
+
+ 2010-04-28: Patch by Bill Auerbach
+ * ip.c: Inline generating IP checksum to save a function call
+
+ 2010-04-14: Simon Goldschmidt
+ * tcpip.h/.c, timers.c: Added an overridable define to get informed when the
+ tcpip_thread processes messages or timeouts to implement a watchdog.
+
+ 2010-03-28: Simon Goldschmidt
+ * ip_frag.c: create a new (contiguous) PBUF_RAM for every outgoing
+ fragment if LWIP_NETIF_TX_SINGLE_PBUF==1
+
+ 2010-03-27: Simon Goldschmidt
+ * etharp.c: Speedup TX by moving code from find_entry to etharp_output/
+ etharp_query to prevent unnecessary function calls (inspired by
+ patch #7135).
+
+ 2010-03-20: Simon Goldschmidt
+ * opt.h, tcpip.c/.h: Added an option to disable tcpip_(un)timeout code
+ since the linker cannot do this automatically to save space.
+
+ 2010-03-20: Simon Goldschmidt
+ * opt.h, etharp.c/.h: Added support for static ARP table entries
+
+ 2010-03-14: Simon Goldschmidt
+ * tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum
+ when creating TCP segments, not when (re-)transmitting them.
+
+ 2010-03-07: Simon Goldschmidt
+ * sockets.c: bug #28775 (select/event_callback: only check select_cb_list
+ on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code.
+ This should speed up receiving data on sockets as the select code in
+ event_callback is only executed when select is waiting.
+
+ 2010-03-06: Simon Goldschmidt
+ * tcp_out.c: task #7013 (Create option to have all packets delivered to
+ netif->output in one piece): Always copy to try to create single pbufs
+ in tcp_write.
+
+ 2010-03-06: Simon Goldschmidt
+ * api.h, api_lib.c, sockets.c: task #10167 (sockets: speed up TCP recv
+ by not allocating a netbuf): added function netconn_recv_tcp_pbuf()
+ for tcp netconns to receive pbufs, not netbufs; use that function
+ for tcp sockets.
+
+ 2010-03-05: Jakob Ole Stoklundsen / Simon Goldschmidt
+ * opt.h, tcp.h, tcp_impl.h, tcp.c, tcp_in.c, tcp_out.c: task #7040:
+ Work on tcp_enqueue: Don't waste memory when chaining segments,
+ added option TCP_OVERSIZE to prevent creating many small pbufs when
+ calling tcp_write with many small blocks of data. Instead, pbufs are
+ allocated larger than needed and the space is used for later calls to
+ tcp_write.
+
+ 2010-02-21: Simon Goldschmidt
+ * stats.c/.h: Added const char* name to mem- and memp-stats for easier
+ debugging.
+
+ 2010-02-21: Simon Goldschmidt
+ * tcp.h (and usages), added tcp_impl.h: Splitted API and internal
+ implementation of tcp to make API usage cleare to application programmers
+
+ 2010-02-14: Simon Goldschmidt/Stephane Lesage
+ * ip_addr.h: Improved some defines working on ip addresses, added faster
+ macro to copy addresses that cannot be NULL
+
+ 2010-02-13: Simon Goldschmidt
+ * api.h, api_lib.c, api_msg.c, sockets.c: task #7865 (implement non-
+ blocking send operation)
+
+ 2010-02-12: Simon Goldschmidt
+ * sockets.c/.h: Added a minimal version of posix fctl() to have a
+ standardised way to set O_NONBLOCK for nonblocking sockets.
+
+ 2010-02-12: Simon Goldschmidt
+ * dhcp.c/.h, autoip.c/.h: task #10139 (Prefer statically allocated
+ memory): added autoip_set_struct() and dhcp_set_struct() to let autoip
+ and dhcp work with user-allocated structs instead of callin mem_malloc
+
+ 2010-02-12: Simon Goldschmidt/Jeff Barber
+ * tcp.c/h: patch #6865 (SO_REUSEADDR for TCP): if pcb.so_options has
+ SOF_REUSEADDR set, allow binding to endpoint in TIME_WAIT
+
+ 2010-02-12: Simon Goldschmidt
+ * sys layer: task #10139 (Prefer statically allocated memory): converted
+ mbox and semaphore functions to take pointers to sys_mbox_t/sys_sem_t;
+ converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
+ task #7212: Add Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX
+ to let sys.h use binary semaphores instead of mutexes - as before)
+
+ 2010-02-09: Simon Goldschmidt (Simon Kallweit)
+ * timers.c/.h: Added function sys_restart_timeouts() from patch #7085
+ (Restart system timeout handling)
+
+ 2010-02-09: Simon Goldschmidt
+ * netif.c/.h, removed loopif.c/.h: task #10153 (Integrate loopif into
+ netif.c) - loopif does not have to be created by the port any more,
+ just define LWIP_HAVE_LOOPIF to 1.
+
+ 2010-02-08: Simon Goldschmidt
+ * inet.h, ip_addr.c/.h: Added reentrant versions of inet_ntoa/ipaddr_ntoa
+ inet_ntoa_r/ipaddr_ntoa_r
+
+ 2010-02-08: Simon Goldschmidt
+ * netif.h: Added netif_s/get_igmp_mac_filter() macros
+
+ 2010-02-05: Simon Goldschmidt
+ * netif.h: Added function-like macros to get/set the hostname on a netif
+
+ 2010-02-04: Simon Goldschmidt
+ * nearly every file: Replaced struct ip_addr by typedef ip_addr_t to
+ make changing the actual implementation behind the typedef easier.
+
+ 2010-02-01: Simon Goldschmidt
+ * opt.h, memp_std.h, dns.h, netdb.c, memp.c: Let netdb use a memp pool
+ for allocating memory when getaddrinfo() is called.
+
+ 2010-01-31: Simon Goldschmidt
+ * dhcp.h, dhcp.c: Reworked the code that parses DHCP options: parse
+ them once instead of parsing for every option. This also removes
+ the need for mem_malloc from dhcp_recv and makes it possible to
+ correctly retrieve the BOOTP file.
+
+ 2010-01-30: simon Goldschmidt
+ * sockets.c: Use SYS_LIGHTWEIGHT_PROT instead of a semaphore to protect
+ the sockets array.
+
+ 2010-01-29: Simon Goldschmidt (patch by Laura Garrett)
+ * api.h, api_msg.c, sockets.c: Added except set support in select
+ (patch #6860)
+
+ 2010-01-29: Simon Goldschmidt (patch by Laura Garrett)
+ * api.h, sockets.h, err.h, api_lib.c, api_msg.c, sockets.c, err.c:
+ Add non-blocking support for connect (partly from patch #6860),
+ plus many cleanups in socket & netconn API.
+
+ 2010-01-27: Simon Goldschmidt
+ * opt.h, tcp.h, init.c, api_msg.c: Added TCP_SNDQUEUELOWAT corresponding
+ to TCP_SNDLOWAT and added tcp_sndqueuelen() - this fixes bug #28605
+
+ 2010-01-26: Simon Goldschmidt
+ * snmp: Use memp pools for snmp instead of the heap; added 4 new pools.
+
+ 2010-01-14: Simon Goldschmidt
+ * ppp.c/.h: Fixed bug #27856: PPP: Set netif link- and status-callback
+ by adding ppp_set_netif_statuscallback()/ppp_set_netif_linkcallback()
+
+ 2010-01-13: Simon Goldschmidt
+ * mem.c: The heap now may be moved to user-defined memory by defining
+ LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
+ (patch #6966 and bug #26133)
+
+ 2010-01-10: Simon Goldschmidt (Bill Auerbach)
+ * opt.h, memp.c: patch #6822 (Add option to place memory pools in
+ separate arrays)
+
+ 2010-01-10: Simon Goldschmidt
+ * init.c, igmp.c: patch #6463 (IGMP - Adding Random Delay): added define
+ LWIP_RAND() for lwip-wide randomization (to be defined in cc.h)
+
+ 2009-12-31: Simon Goldschmidt
+ * tcpip.c, init.c, memp.c, sys.c, memp_std.h, sys.h, tcpip.h
+ added timers.c/.h: Separated timer implementation from semaphore/mbox
+ implementation, moved timer implementation to timers.c/.h, timers are
+ now only called from tcpip_thread or by explicitly checking them.
+ (TASK#7235)
+
+ 2009-12-27: Simon Goldschmidt
+ * opt.h, etharp.h/.c, init.c, tcpip.c: Added an additional option
+ LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE)
+
+
+ ++ Bugfixes:
+
+ 2011-04-20: Simon Goldschmidt
+ * sys_arch.txt: sys_arch_timeouts() is not needed any more.
+
+ 2011-04-13: Simon Goldschmidt
+ * tcp.c, udp.c: Fixed bug #33048 (Bad range for IP source port numbers) by
+ using ports in the IANA private/dynamic range (49152 through 65535).
+
+ 2011-03-29: Simon Goldschmidt, patch by Emil Lhungdahl:
+ * etharp.h/.c: Fixed broken VLAN support.
+
+ 2011-03-27: Simon Goldschmidt
+ * tcp.c: Fixed bug #32926 (TCP_RMV(&tcp_bound_pcbs) is called on unbound tcp
+ pcbs) by checking if the pcb was bound (local_port != 0).
+
+ 2011-03-27: Simon Goldschmidt
+ * ppp.c: Fixed bug #32280 (ppp: a pbuf is freed twice)
+
+ 2011-03-27: Simon Goldschmidt
+ * sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and
+ raw pcbs with LWIP_TCPIP_CORE_LOCKING==1.
+
+ 2011-03-27: Simon Goldschmidt
+ * tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route
+ is present never times out) by starting retransmission timer before checking
+ route.
+
+ 2011-03-22: Simon Goldschmidt
+ * ppp.c: Fixed bug #32648 (PPP code crashes when terminating a link) by only
+ calling sio_read_abort() if the file descriptor is valid.
+
+ 2011-03-14: Simon Goldschmidt
+ * err.h/.c, sockets.c, api_msg.c: fixed bug #31748 (Calling non-blocking connect
+ more than once can render a socket useless) since it mainly involves changing
+ "FATAL" classification of error codes: ERR_USE and ERR_ISCONN just aren't fatal.
+
+ 2011-03-13: Simon Goldschmidt
+ * sockets.c: fixed bug #32769 (ESHUTDOWN is linux-specific) by fixing
+ err_to_errno_table (ERR_CLSD: ENOTCONN instead of ESHUTDOWN), ERR_ISCONN:
+ use EALRADY instead of -1
+
+ 2011-03-13: Simon Goldschmidt
+ * api_lib.c: netconn_accept: return ERR_ABRT instead of ERR_CLSD if the
+ connection has been aborted by err_tcp (since this is not a normal closing
+ procedure).
+
+ 2011-03-13: Simon Goldschmidt
+ * tcp.c: tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind
+ with pcb->state != CLOSED
+
+ 2011-02-17: Simon Goldschmidt
+ * rawapi.txt: Fixed bug #32561 tcp_poll argument definition out-of-order in
+ documentation
+
+ 2011-02-17: Simon Goldschmidt
+ * many files: Added missing U/UL modifiers to fix 16-bit-arch portability.
+
+ 2011-01-24: Simon Goldschmidt
+ * sockets.c: Fixed bug #31741: lwip_select seems to have threading problems
+
+ 2010-12-02: Simon Goldschmidt
+ * err.h: Fixed ERR_IS_FATAL so that ERR_WOULDBLOCK is not fatal.
+
+ 2010-11-23: Simon Goldschmidt
+ * api.h, api_lib.c, api_msg.c, sockets.c: netconn.recv_avail is only used for
+ LWIP_SO_RCVBUF and ioctl/FIONREAD.
+
+ 2010-11-23: Simon Goldschmidt
+ * etharp.c: Fixed bug #31720: ARP-queueing: RFC 1122 recommends to queue at
+ least 1 packet -> ARP_QUEUEING==0 now queues the most recent packet.
+
+ 2010-11-23: Simon Goldschmidt
+ * tcp_in.c: Fixed bug #30577: tcp_input: don't discard ACK-only packets after
+ refusing 'refused_data' again.
+
+ 2010-11-22: Simon Goldschmidt
+ * sockets.c: Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS
+ after a successful nonblocking connection.
+
+ 2010-11-22: Simon Goldschmidt
+ * etharp.c: Fixed bug #31722: IP packets sent with an AutoIP source addr
+ must be sent link-local
+
+ 2010-11-22: Simon Goldschmidt
+ * timers.c: patch #7329: tcp_timer_needed prototype was ifdef'ed out for
+ LWIP_TIMERS==0
+
+ 2010-11-20: Simon Goldschmidt
+ * sockets.c: Fixed bug #31170: lwip_setsockopt() does not set socket number
+
+ 2010-11-20: Simon Goldschmidt
+ * sockets.h: Fixed bug #31304: Changed SHUT_RD, SHUT_WR and SHUT_RDWR to
+ resemble other stacks.
+
+ 2010-11-20: Simon Goldschmidt
+ * dns.c: Fixed bug #31535: TCP_SND_QUEUELEN must be at least 2 or else
+ no-copy TCP writes will never succeed.
+
+ 2010-11-20: Simon Goldschmidt
+ * dns.c: Fixed bug #31701: Error return value from dns_gethostbyname() does
+ not match documentation: return ERR_ARG instead of ERR_VAL if not
+ initialized or wrong argument.
+
+ 2010-10-20: Simon Goldschmidt
+ * sockets.h: Fixed bug #31385: sizeof(struct sockaddr) is 30 but should be 16
+
+ 2010-10-05: Simon Goldschmidt
+ * dhcp.c: Once again fixed #30038: DHCP/AutoIP cooperation failed when
+ replugging the network cable after an AutoIP address was assigned.
+
+ 2010-08-10: Simon Goldschmidt
+ * tcp.c: Fixed bug #30728: tcp_new_port() did not check listen pcbs
+
+ 2010-08-03: Simon Goldschmidt
+ * udp.c, raw.c: Don't chain empty pbufs when sending them (fixes bug #30625)
+
+ 2010-08-01: Simon Goldschmidt (patch by Greg Renda)
+ * ppp.c: Applied patch #7264 (PPP protocols are rejected incorrectly on big
+ endian architectures)
+
+ 2010-07-28: Simon Goldschmidt
+ * api_lib.c, api_msg.c, sockets.c, mib2.c: Fixed compilation with TCP or UDP
+ disabled.
+
+ 2010-07-27: Simon Goldschmidt
+ * tcp.c: Fixed bug #30565 (tcp_connect() check bound list): that check did no
+ harm but never did anything
+
+ 2010-07-21: Simon Goldschmidt
+ * ip.c: Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not
+ add IP options)
+
+ 2010-07-16: Kieran Mansley
+ * msg_in.c: Fixed SNMP ASN constant defines to not use ! operator
+
+ 2010-07-10: Simon Goldschmidt
+ * ip.c: Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options
+
+ 2010-06-30: Simon Goldschmidt
+ * api_msg.c: fixed bug #30300 (shutdown parameter was not initialized in
+ netconn_delete)
+
+ 2010-06-28: Kieran Mansley
+ * timers.c remove unportable printing of C function pointers
+
+ 2010-06-24: Simon Goldschmidt
+ * init.c, timers.c/.h, opt.h, memp_std.h: From patch #7221: added flag
+ NO_SYS_NO_TIMERS to drop timer support for NO_SYS==1 for easier upgrading
+
+ 2010-06-24: Simon Goldschmidt
+ * api(_lib).c/.h, api_msg.c/.h, sockets.c/.h: Fixed bug #10088: Correctly
+ implemented shutdown at socket level.
+
+ 2010-06-21: Simon Goldschmidt
+ * pbuf.c/.h, ip_frag.c/.h, opt.h, memp_std.h: Fixed bug #29361 (ip_frag has
+ problems with zero-copy DMA MACs) by adding custom pbufs and implementing
+ custom pbufs that reference other (original) pbufs. Additionally set
+ IP_FRAG_USES_STATIC_BUF=0 as default to be on the safe side.
+
+ 2010-06-15: Simon Goldschmidt
+ * dhcp.c: Fixed bug #29970: DHCP endian issue parsing option responses
+
+ 2010-06-14: Simon Goldschmidt
+ * autoip.c: Fixed bug #30039: AutoIP does not reuse previous addresses
+
+ 2010-06-12: Simon Goldschmidt
+ * dhcp.c: Fixed bug #30038: dhcp_network_changed doesn't reset AUTOIP coop
+ state
+
+ 2010-05-17: Simon Goldschmidt
+ * netdb.c: Correctly NULL-terminate h_addr_list
+
+ 2010-05-16: Simon Goldschmidt
+ * def.h/.c: changed the semantics of LWIP_PREFIX_BYTEORDER_FUNCS to prevent
+ "symbol already defined" i.e. when linking to winsock
+
+ 2010-05-05: Simon Goldschmidt
+ * def.h, timers.c: Fixed bug #29769 (sys_check_timeouts: sys_now() may
+ overflow)
+
+ 2010-04-21: Simon Goldschmidt
+ * api_msg.c: Fixed bug #29617 (sometime cause stall on delete listening
+ connection)
+
+ 2010-03-28: Luca Ceresoli
+ * ip_addr.c/.h: patch #7143: Add a few missing const qualifiers
+
+ 2010-03-27: Luca Ceresoli
+ * mib2.c: patch #7130: remove meaningless const qualifiers
+
+ 2010-03-26: Simon Goldschmidt
+ * tcp_out.c: Make LWIP_NETIF_TX_SINGLE_PBUF work for TCP, too
+
+ 2010-03-26: Simon Goldschmidt
+ * various files: Fixed compiling with different options disabled (TCP/UDP),
+ triggered by bug #29345; don't allocate acceptmbox if LWIP_TCP is disabled
+
+ 2010-03-25: Simon Goldschmidt
+ * sockets.c: Fixed bug #29332: lwip_select() processes readset incorrectly
+
+ 2010-03-25: Simon Goldschmidt
+ * tcp_in.c, test_tcp_oos.c: Fixed bug #29080: Correctly handle remote side
+ overrunning our rcv_wnd in ooseq case.
+
+ 2010-03-22: Simon Goldschmidt
+ * tcp.c: tcp_listen() did not copy the pcb's prio.
+
+ 2010-03-19: Simon Goldschmidt
+ * snmp_msg.c: Fixed bug #29256: SNMP Trap address was not correctly set
+
+ 2010-03-14: Simon Goldschmidt
+ * opt.h, etharp.h: Fixed bug #29148 (Incorrect PBUF_POOL_BUFSIZE for ports
+ where ETH_PAD_SIZE > 0) by moving definition of ETH_PAD_SIZE to opt.h
+ and basing PBUF_LINK_HLEN on it.
+
+ 2010-03-08: Simon Goldschmidt
+ * netif.c, ipv4/ip.c: task #10241 (AutoIP: don't break existing connections
+ when assiging routable address): when checking incoming packets and
+ aborting existing connection on address change, filter out link-local
+ addresses.
+
+ 2010-03-06: Simon Goldschmidt
+ * sockets.c: Fixed LWIP_NETIF_TX_SINGLE_PBUF for LWIP_TCPIP_CORE_LOCKING
+
+ 2010-03-06: Simon Goldschmidt
+ * ipv4/ip.c: Don't try to forward link-local addresses
+
+ 2010-03-06: Simon Goldschmidt
+ * etharp.c: Fixed bug #29087: etharp: don't send packets for LinkLocal-
+ addresses to gw
+
+ 2010-03-05: Simon Goldschmidt
+ * dhcp.c: Fixed bug #29072: Correctly set ciaddr based on message-type
+ and state.
+
+ 2010-03-05: Simon Goldschmidt
+ * api_msg.c: Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split
+ into multiple calls to tcp_write.
+
+ 2010-02-21: Simon Goldschmidt
+ * opt.h, mem.h, dns.c: task #10140: Remove DNS_USES_STATIC_BUF (keep
+ the implementation of DNS_USES_STATIC_BUF==1)
+
+ 2010-02-20: Simon Goldschmidt
+ * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Task #10088: Correctly implement
+ close() vs. shutdown(). Now the application does not get any more
+ recv callbacks after calling tcp_close(). Added tcp_shutdown().
+
+ 2010-02-19: Simon Goldschmidt
+ * mem.c/.h, pbuf.c: Renamed mem_realloc() to mem_trim() to prevent
+ confusion with realloc()
+
+ 2010-02-15: Simon Goldschmidt/Stephane Lesage
+ * netif.c/.h: Link status does not depend on LWIP_NETIF_LINK_CALLBACK
+ (fixes bug #28899)
+
+ 2010-02-14: Simon Goldschmidt
+ * netif.c: Fixed bug #28877 (Duplicate ARP gratuitous packet with
+ LWIP_NETIF_LINK_CALLBACK set on) by only sending if both link- and
+ admin-status of a netif are up
+
+ 2010-02-14: Simon Goldschmidt
+ * opt.h: Disable ETHARP_TRUST_IP_MAC by default since it slows down packet
+ reception and is not really necessary
+
+ 2010-02-14: Simon Goldschmidt
+ * etharp.c/.h: Fixed ARP input processing: only add a new entry if a
+ request was directed as us (RFC 826, Packet Reception), otherwise
+ only update existing entries; internalized some functions
+
+ 2010-02-14: Simon Goldschmidt
+ * netif.h, etharp.c, tcpip.c: Fixed bug #28183 (ARP and TCP/IP cannot be
+ disabled on netif used for PPPoE) by adding a new netif flag
+ (NETIF_FLAG_ETHERNET) that tells the stack the device is an ethernet
+ device but prevents usage of ARP (so that ethernet_input can be used
+ for PPPoE).
+
+ 2010-02-12: Simon Goldschmidt
+ * netif.c: netif_set_link_up/down: only do something if the link state
+ actually changes
+
+ 2010-02-12: Simon Goldschmidt/Stephane Lesage
+ * api_msg.c: Fixed bug #28865 (Cannot close socket/netconn in non-blocking
+ connect)
+
+ 2010-02-12: Simon Goldschmidt
+ * mem.h: Fixed bug #28866 (mem_realloc function defined in mem.h)
+
+ 2010-02-09: Simon Goldschmidt
+ * api_lib.c, api_msg.c, sockets.c, api.h, api_msg.h: Fixed bug #22110
+ (recv() makes receive window update for data that wasn't received by
+ application)
+
+ 2010-02-09: Simon Goldschmidt/Stephane Lesage
+ * sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out
+ or any netconn_recv() error)
+
+ 2010-02-09: Simon Goldschmidt
+ * ppp.c: task #10154 (PPP: Update snmp in/out counters for tx/rx packets)
+
+ 2010-02-09: Simon Goldschmidt
+ * netif.c: For loopback packets, adjust the stats- and snmp-counters
+ for the loopback netif.
+
+ 2010-02-08: Simon Goldschmidt
+ * igmp.c/.h, ip.h: Moved most defines from igmp.h to igmp.c for clarity
+ since they are not used anywhere else.
+
+ 2010-02-08: Simon Goldschmidt (Stéphane Lesage)
+ * igmp.c, igmp.h, stats.c, stats.h: Improved IGMP stats
+ (patch from bug #28798)
+
+ 2010-02-08: Simon Goldschmidt (Stéphane Lesage)
+ * igmp.c: Fixed bug #28798 (Error in "Max Response Time" processing) and
+ another bug when LWIP_RAND() returns zero.
+
+ 2010-02-04: Simon Goldschmidt
+ * nearly every file: Use macros defined in ip_addr.h (some of them new)
+ to work with IP addresses (preparation for bug #27352 - Change ip_addr
+ from struct to typedef (u32_t) - and better code).
+
+ 2010-01-31: Simon Goldschmidt
+ * netif.c: Don't call the link-callback from netif_set_up/down() since
+ this invalidly retriggers DHCP.
+
+ 2010-01-29: Simon Goldschmidt
+ * ip_addr.h, inet.h, def.h, inet.c, def.c, more: Cleanly separate the
+ portability file inet.h and its contents from the stack: moved htonX-
+ functions to def.h (and the new def.c - they are not ipv4 dependent),
+ let inet.h depend on ip_addr.h and not the other way round.
+ This fixes bug #28732.
+
+ 2010-01-28: Kieran Mansley
+ * tcp.c: Ensure ssthresh >= 2*MSS
+
+ 2010-01-27: Simon Goldschmidt
+ * tcp.h, tcp.c, tcp_in.c: Fixed bug #27871: Calling tcp_abort() in recv
+ callback can lead to accessing unallocated memory. As a consequence,
+ ERR_ABRT means the application has called tcp_abort()!
+
+ 2010-01-25: Simon Goldschmidt
+ * snmp_structs.h, msg_in.c: Partly fixed bug #22070 (MIB_OBJECT_WRITE_ONLY
+ not implemented in SNMP): write-only or not-accessible are still
+ returned by getnext (though not by get)
+
+ 2010-01-24: Simon Goldschmidt
+ * snmp: Renamed the private mib node from 'private' to 'mib_private' to
+ not use reserved C/C++ keywords
+
+ 2010-01-23: Simon Goldschmidt
+ * sockets.c: Fixed bug #28716: select() returns 0 after waiting for less
+ than 1 ms
+
+ 2010-01-21: Simon Goldschmidt
+ * tcp.c, api_msg.c: Fixed bug #28651 (tcp_connect: no callbacks called
+ if tcp_enqueue fails) both in raw- and netconn-API
+
+ 2010-01-19: Simon Goldschmidt
+ * api_msg.c: Fixed bug #27316: netconn: Possible deadlock in err_tcp
+
+ 2010-01-18: Iordan Neshev/Simon Goldschmidt
+ * src/netif/ppp: reorganised PPP sourcecode to 2.3.11 including some
+ bugfix backports from 2.4.x.
+
+ 2010-01-18: Simon Goldschmidt
+ * mem.c: Fixed bug #28679: mem_realloc calculates mem_stats wrong
+
+ 2010-01-17: Simon Goldschmidt
+ * api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c):
+ task #10102: "netconn: clean up conn->err threading issues" by adding
+ error return value to struct api_msg_msg
+
+ 2010-01-17: Simon Goldschmidt
+ * api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept()
+ to return err_t (bugs #27709 and #28087)
+
+ 2010-01-14: Simon Goldschmidt
+ * ...: Use typedef for function prototypes throughout the stack.
+
+ 2010-01-13: Simon Goldschmidt
+ * api_msg.h/.c, api_lib.c: Fixed bug #26672 (close connection when receive
+ window = 0) by correctly draining recvmbox/acceptmbox
+
+ 2010-01-11: Simon Goldschmidt
+ * pap.c: Fixed bug #13315 (PPP PAP authentication can result in
+ erroneous callbacks) by copying the code from recent pppd
+
+ 2010-01-10: Simon Goldschmidt
+ * raw.c: Fixed bug #28506 (raw_bind should filter received packets)
+
+ 2010-01-10: Simon Goldschmidt
+ * tcp.h/.c: bug #28127 (remove call to tcp_output() from tcp_ack(_now)())
+
+ 2010-01-08: Simon Goldschmidt
+ * sockets.c: Fixed bug #28519 (lwip_recvfrom bug with len > 65535)
+
+ 2010-01-08: Simon Goldschmidt
+ * dns.c: Copy hostname for DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 since string
+ passed to dns_local_addhost() might be volatile
+
+ 2010-01-07: Simon Goldschmidt
+ * timers.c, tcp.h: Call tcp_timer_needed() with NO_SYS==1, too
+
+ 2010-01-06: Simon Goldschmidt
+ * netdb.h: Fixed bug #28496: missing include guards in netdb.h
+
+ 2009-12-31: Simon Goldschmidt
+ * many ppp files: Reorganised PPP source code from ucip structure to pppd
+ structure to easily compare our code against the pppd code (around v2.3.1)
+
+ 2009-12-27: Simon Goldschmidt
+ * tcp_in.c: Another fix for bug #28241 (ooseq processing) and adapted
+ unit test
+
+
+(STABLE-1.3.2)
+
+ ++ New features:
+
+ 2009-10-27 Simon Goldschmidt/Stephan Lesage
+ * netifapi.c/.h: Added netifapi_netif_set_addr()
+
+ 2009-10-07 Simon Goldschmidt/Fabian Koch
+ * api_msg.c, netbuf.c/.h, opt.h: patch #6888: Patch for UDP Netbufs to
+ support dest-addr and dest-port (optional: LWIP_NETBUF_RECVINFO)
+
+ 2009-08-26 Simon Goldschmidt/Simon Kallweit
+ * slipif.c/.h: bug #26397: SLIP polling support
+
+ 2009-08-25 Simon Goldschmidt
+ * opt.h, etharp.h/.c: task #9033: Support IEEE 802.1q tagged frame (VLAN),
+ New configuration options ETHARP_SUPPORT_VLAN and ETHARP_VLAN_CHECK.
+
+ 2009-08-25 Simon Goldschmidt
+ * ip_addr.h, netdb.c: patch #6900: added define ip_ntoa(struct ip_addr*)
+
+ 2009-08-24 Jakob Stoklund Olesen
+ * autoip.c, dhcp.c, netif.c: patch #6725: Teach AutoIP and DHCP to respond
+ to netif_set_link_up().
+
+ 2009-08-23 Simon Goldschmidt
+ * tcp.h/.c: Added function tcp_debug_state_str() to convert a tcp state
+ to a human-readable string.
+
+ ++ Bugfixes:
+
+ 2009-12-24: Kieran Mansley
+ * tcp_in.c Apply patches from Oleg Tyshev to improve OOS processing
+ (BUG#28241)
+
+ 2009-12-06: Simon Goldschmidt
+ * ppp.h/.c: Fixed bug #27079 (Yet another leak in PPP): outpacket_buf can
+ be statically allocated (like in ucip)
+
+ 2009-12-04: Simon Goldschmidt (patch by Ioardan Neshev)
+ * pap.c: patch #6969: PPP: missing PAP authentication UNTIMEOUT
+
+ 2009-12-03: Simon Goldschmidt
+ * tcp.h, tcp_in.c, tcp_out.c: Fixed bug #28106: dup ack for fast retransmit
+ could have non-zero length
+
+ 2009-12-02: Simon Goldschmidt
+ * tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting
+ tcp_input_pcb until after calling the pcb's callbacks
+
+ 2009-11-29: Simon Goldschmidt
+ * tcp_in.c: Fixed bug #28054: Two segments with FIN flag on the out-of-
+ sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code
+
+ 2009-11-29: Simon Goldschmidt
+ * pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by
+ queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty
+
+ 2009-11-26: Simon Goldschmidt
+ * tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending
+ segment
+
+ 2009-11-26: Simon Goldschmidt
+ * tcp.h, sockets.c: Fixed bug #28099: API required to disable Nagle
+ algorithm at PCB level
+
+ 2009-11-22: Simon Goldschmidt
+ * tcp_out.c: Fixed bug #27905: FIN isn't combined with data on unsent
+
+ 2009-11-22: Simon Goldschmidt (suggested by Bill Auerbach)
+ * tcp.c: tcp_alloc: prevent increasing stats.err for MEMP_TCP_PCB when
+ reusing time-wait pcb
+
+ 2009-11-20: Simon Goldschmidt (patch by Albert Bartel)
+ * sockets.c: Fixed bug #28062: Data received directly after accepting
+ does not wake up select
+
+ 2009-11-11: Simon Goldschmidt
+ * netdb.h: Fixed bug #27994: incorrect define for freeaddrinfo(addrinfo)
+
+ 2009-10-30: Simon Goldschmidt
+ * opt.h: Increased default value for TCP_MSS to 536, updated default
+ value for TCP_WND to 4*TCP_MSS to keep delayed ACK working.
+
+ 2009-10-28: Kieran Mansley
+ * tcp_in.c, tcp_out.c, tcp.h: re-work the fast retransmission code
+ to follow algorithm from TCP/IP Illustrated
+
+ 2009-10-27: Kieran Mansley
+ * tcp_in.c: fix BUG#27445: grow cwnd with every duplicate ACK
+
+ 2009-10-25: Simon Goldschmidt
+ * tcp.h: bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if
+ pcb->recv is NULL to keep rcv_wnd correct)
+
+ 2009-10-25: Simon Goldschmidt
+ * tcp_in.c: Fixed bug #26251: RST process in TIME_WAIT TCP state
+
+ 2009-10-23: Simon Goldschmidt (David Empson)
+ * tcp.c: Fixed bug #27783: Silly window avoidance for small window sizes
+
+ 2009-10-21: Simon Goldschmidt
+ * tcp_in.c: Fixed bug #27215: TCP sent() callback gives leading and
+ trailing 1 byte len (SYN/FIN)
+
+ 2009-10-21: Simon Goldschmidt
+ * tcp_out.c: Fixed bug #27315: zero window probe and FIN
+
+ 2009-10-19: Simon Goldschmidt
+ * dhcp.c/.h: Minor code simplification (don't store received pbuf, change
+ conditional code to assert where applicable), check pbuf length before
+ testing for valid reply
+
+ 2009-10-19: Simon Goldschmidt
+ * dhcp.c: Removed most calls to udp_connect since they aren't necessary
+ when using udp_sendto_if() - always stay connected to IP_ADDR_ANY.
+
+ 2009-10-16: Simon Goldschmidt
+ * ip.c: Fixed bug #27390: Source IP check in ip_input() causes it to drop
+ valid DHCP packets -> allow 0.0.0.0 as source address when LWIP_DHCP is
+ enabled
+
+ 2009-10-15: Simon Goldschmidt (Oleg Tyshev)
+ * tcp_in.c: Fixed bug #27329: dupacks by unidirectional data transmit
+
+ 2009-10-15: Simon Goldschmidt
+ * api_lib.c: Fixed bug #27709: conn->err race condition on netconn_recv()
+ timeout
+
+ 2009-10-15: Simon Goldschmidt
+ * autoip.c: Fixed bug #27704: autoip starts with wrong address
+ LWIP_AUTOIP_CREATE_SEED_ADDR() returned address in host byte order instead
+ of network byte order
+
+ 2009-10-11 Simon Goldschmidt (Jörg Kesten)
+ * tcp_out.c: Fixed bug #27504: tcp_enqueue wrongly concatenates segments
+ which are not consecutive when retransmitting unacked segments
+
+ 2009-10-09 Simon Goldschmidt
+ * opt.h: Fixed default values of some stats to only be enabled if used
+ Fixes bug #27338: sys_stats is defined when NO_SYS = 1
+
+ 2009-08-30 Simon Goldschmidt
+ * ip.c: Fixed bug bug #27345: "ip_frag() does not use the LWIP_NETIF_LOOPBACK
+ function" by checking for loopback before calling ip_frag
+
+ 2009-08-25 Simon Goldschmidt
+ * dhcp.c: fixed invalid dependency to etharp_query if DHCP_DOES_ARP_CHECK==0
+
+ 2009-08-23 Simon Goldschmidt
+ * ppp.c: bug #27078: Possible memory leak in pppInit()
+
+ 2009-08-23 Simon Goldschmidt
+ * netdb.c, dns.c: bug #26657: DNS, if host name is "localhost", result
+ is error.
+
+ 2009-08-23 Simon Goldschmidt
+ * opt.h, init.c: bug #26649: TCP fails when TCP_MSS > TCP_SND_BUF
+ Fixed wrong parenthesis, added check in init.c
+
+ 2009-08-23 Simon Goldschmidt
+ * ppp.c: bug #27266: wait-state debug message in pppMain occurs every ms
+
+ 2009-08-23 Simon Goldschmidt
+ * many ppp files: bug #27267: Added include to string.h where needed
+
+ 2009-08-23 Simon Goldschmidt
+ * tcp.h: patch #6843: tcp.h macro optimization patch (for little endian)
+
+
+(STABLE-1.3.1)
+
+ ++ New features:
+
+ 2009-05-10 Simon Goldschmidt
+ * opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option
+ LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only
+ one pbuf to help MACs that don't support scatter-gather DMA.
+
+ 2009-05-09 Simon Goldschmidt
+ * icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming
+ ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
+
+ 2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen
+ * ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive
+ extended info about the currently received packet.
+
+ 2009-04-27 Simon Goldschmidt
+ * sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1
+
+ 2009-04-25 Simon Goldschmidt
+ * mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next
+ bigger malloc pool if one is empty (only usable with MEM_USE_POOLS).
+
+ 2009-04-21 Simon Goldschmidt
+ * dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static
+ hosts table. New configuration options DNS_LOCAL_HOSTLIST and
+ DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined
+ as an external function for lookup.
+
+ 2009-04-15 Simon Goldschmidt
+ * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique
+
+ 2009-03-31 Kieran Mansley
+ * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for
+ TCP timestamp options, off by default. Rework tcp_enqueue() to
+ take option flags rather than specified option data
+
+ 2009-02-18 Simon Goldschmidt
+ * cc.h: Added printf formatter for size_t: SZT_F
+
+ 2009-02-16 Simon Goldschmidt (patch by Rishi Khan)
+ * icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast
+ pings
+
+ 2009-02-12 Simon Goldschmidt
+ * init.h: Added LWIP_VERSION to get the current version of the stack
+
+ 2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler)
+ * opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead
+ of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc
+ is otherwise used)
+
+ 2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach)
+ * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial()
+ is only used by UDPLITE at present, so conditionalise it.
+
+ 2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli)
+ * autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP
+ "seed" address. This should reduce AUTOIP conflicts if
+ LWIP_AUTOIP_CREATE_SEED_ADDR is overridden.
+
+ 2008-10-02 Jonathan Larmour and Rishi Khan
+ * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking
+ socket.
+
+ 2008-06-30 Simon Goldschmidt
+ * mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from
+ interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows
+ mem_free to run between mem_malloc iterations. Added illegal counter for
+ mem stats.
+
+ 2008-06-27 Simon Goldschmidt
+ * stats.h/.c, some other files: patch #6483: stats module improvement:
+ Added defines to display each module's statistic individually, added stats
+ defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter.
+
+ 2008-06-17 Simon Goldschmidt
+ * err.h: patch #6459: Made err_t overridable to use a more efficient type
+ (define LWIP_ERR_T in cc.h)
+
+ 2008-06-17 Simon Goldschmidt
+ * slipif.c: patch #6480: Added a configuration option for slipif for symmetry
+ to loopif
+
+ 2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli)
+ * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly
+ modified version of patch # 6370: Moved loopif code to netif.c so that
+ loopback traffic is supported on all netifs (all local IPs).
+ Added option to limit loopback packets for each netifs.
+
+
+ ++ Bugfixes:
+ 2009-08-12 Kieran Mansley
+ * tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when
+ out of window or out of order properly
+
+ 2009-08-12 Kieran Mansley
+ * tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1
+
+ 2009-07-28 Simon Goldschmidt
+ * mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s
+
+ 2009-07-27 Kieran Mansley
+ * api.h api_msg.h netdb.h sockets.h: add missing #include directives
+
+ 2009-07-09 Kieran Mansley
+ * api_msg.c, sockets.c, api.h: BUG23240 use signed counters for
+ recv_avail and don't increment counters until message successfully
+ sent to mbox
+
+ 2009-06-25 Kieran Mansley
+ * api_msg.c api.h: BUG26722: initialise netconn write variables
+ in netconn_alloc
+
+ 2009-06-25 Kieran Mansley
+ * tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set
+
+ 2009-06-25 Kieran Mansley
+ * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct
+ simultaneous close behaviour, and make snd_nxt have the same meaning
+ as in the RFCs.
+
+ 2009-05-12 Simon Goldschmidt
+ * etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on
+ arp_table / uses etharp_query" by adding etharp_gratuitous()
+
+ 2009-05-12 Simon Goldschmidt
+ * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options
+ to the IP header (used by igmp_ip_output_if)
+
+ 2009-05-06 Simon Goldschmidt
+ * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if
+ defined) for SWAP_BYTES_IN_WORD to speed up checksumming.
+
+ 2009-05-05 Simon Goldschmidt
+ * sockets.c: bug #26405: Prematurely released semaphore causes lwip_select()
+ to crash
+
+ 2009-05-04 Simon Goldschmidt
+ * init.c: snmp was not initialized in lwip_init()
+
+ 2009-05-04 Frédéric Bernon
+ * dhcp.c, netbios.c: Changes if IP_SOF_BROADCAST is enabled.
+
+ 2009-05-03 Simon Goldschmidt
+ * tcp.h: bug #26349: Nagle algorithm doesn't send although segment is full
+ (and unsent->next == NULL)
+
+ 2009-05-02 Simon Goldschmidt
+ * tcpip.h, tcpip.c: fixed tcpip_untimeout (does not need the time, broken after
+ 1.3.0 in CVS only) - fixes compilation of ppp_oe.c
+
+ 2009-05-02 Simon Goldschmidt
+ * msg_in.c: fixed bug #25636: SNMPSET value is ignored for integer fields
+
+ 2009-05-01 Simon Goldschmidt
+ * pap.c: bug #21680: PPP upap_rauthnak() drops legal NAK packets
+
+ 2009-05-01 Simon Goldschmidt
+ * ppp.c: bug #24228: Memory corruption with PPP and DHCP
+
+ 2009-04-29 Frédéric Bernon
+ * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the
+ SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception
+ of broadcast packets even when this option wasn't set. Port maintainers
+ which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h.
+ If you want this option also filter broadcast on recv operations, you also
+ have to set IP_SOF_BROADCAST_RECV=1 in opt.h.
+
+ 2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen
+ * dhcp.c: patch #6721, bugs #25575, #25576: Some small fixes to DHCP and
+ DHCP/AUTOIP cooperation
+
+ 2009-04-25 Simon Goldschmidt, Oleg Tyshev
+ * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd
+ Fixed by sorting the unsent and unacked queues (segments are inserted at the
+ right place in tcp_output and tcp_rexmit).
+
+ 2009-04-25 Simon Goldschmidt
+ * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation
+ when debugging": memp_sizes contained the wrong sizes (including sanity
+ regions); memp pools for MEM_USE_POOLS were too small
+
+ 2009-04-24 Simon Goldschmidt, Frédéric Bernon
+ * inet.c: patch #6765: Fix a small problem with the last changes (incorrect
+ behavior, with with ip address string not ended by a '\0', a space or a
+ end of line)
+
+ 2009-04-19 Simon Goldschmidt
+ * rawapi.txt: Fixed bug #26069: Corrected documentation: if tcp_connect fails,
+ pcb->err is called, not pcb->connected (with an error code).
+
+ 2009-04-19 Simon Goldschmidt
+ * tcp_out.c: Fixed bug #26236: "TCP options (timestamp) don't work with
+ no-copy-tcpwrite": deallocate option data, only concat segments with same flags
+
+ 2009-04-19 Simon Goldschmidt
+ * tcp_out.c: Fixed bug #25094: "Zero-length pbuf" (options are now allocated
+ in the header pbuf, not the data pbuf)
+
+ 2009-04-18 Simon Goldschmidt
+ * api_msg.c: fixed bug #25695: Segmentation fault in do_writemore()
+
+ 2009-04-15 Simon Goldschmidt
+ * sockets.c: tried to fix bug #23559: lwip_recvfrom problem with tcp
+
+ 2009-04-15 Simon Goldschmidt
+ * dhcp.c: task #9192: mem_free of dhcp->options_in and dhcp->msg_in
+
+ 2009-04-15 Simon Goldschmidt
+ * ip.c, ip6.c, tcp_out.c, ip.h: patch #6808: Add a utility function
+ ip_hinted_output() (for smaller code mainly)
+
+ 2009-04-15 Simon Goldschmidt
+ * inet.c: patch #6765: Supporting new line characters in inet_aton()
+
+ 2009-04-15 Simon Goldschmidt
+ * dhcp.c: patch #6764: DHCP rebind and renew did not send hostnam option;
+ Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu
+ is big enough in dhcp_start
+
+ 2009-04-15 Simon Goldschmidt
+ * netbuf.c: bug #26027: netbuf_chain resulted in pbuf memory leak
+
+ 2009-04-15 Simon Goldschmidt
+ * sockets.c, ppp.c: bug #25763: corrected 4 occurrences of SMEMCPY to MEMCPY
+
+ 2009-04-15 Simon Goldschmidt
+ * sockets.c: bug #26121: set_errno can be overridden
+
+ 2009-04-09 Kieran Mansley (patch from Luca Ceresoli <lucaceresoli>)
+ * init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when
+ LWIP_TCP==0
+
+ 2009-04-09 Kieran Mansley (patch from Roy Lee <roylee17>)
+ * tcp.h: Patch#6802 Add do-while-clauses to those function like
+ macros in tcp.h
+
+ 2009-03-31 Kieran Mansley
+ * tcp.c, tcp_in.c, tcp_out.c, tcp.h, opt.h: Rework the way window
+ updates are calculated and sent (BUG20515)
+
+ * tcp_in.c: cope with SYN packets received during established states,
+ and retransmission of initial SYN.
+
+ * tcp_out.c: set push bit correctly when tcp segments are merged
+
+ 2009-03-27 Kieran Mansley
+ * tcp_out.c set window correctly on probes (correcting change made
+ yesterday)
+
+ 2009-03-26 Kieran Mansley
+ * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping
+ connections where no reset required (bug #25622)
+
+ * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes
+ (bug #20779)
+
+ 2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach)
+ * ip_frag.c: patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be
+ too small depending on MEM_ALIGNMENT
+
+ 2009-02-16 Simon Goldschmidt
+ * sockets.h/.c, api_*.h/.c: fixed arguments of socket functions to match the standard;
+ converted size argument of netconn_write to 'size_t'
+
+ 2009-02-16 Simon Goldschmidt
+ * tcp.h, tcp.c: fixed bug #24440: TCP connection close problem on 64-bit host
+ by moving accept callback function pointer to TCP_PCB_COMMON
+
+ 2009-02-12 Simon Goldschmidt
+ * dhcp.c: fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size"
+ option)
+
+ 2009-02-11 Simon Goldschmidt
+ * dhcp.c: fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start)
+
+ 2009-02-11 Simon Goldschmidt
+ * opt.h, api_msg.c: added configurable default valud for netconn->recv_bufsize:
+ RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv())
+
+ 2009-02-10 Simon Goldschmidt
+ * tcp.c: fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD:
+ Accepts_pending is decrease on a corresponding listen pcb when a connection
+ in state SYN_RCVD is close.
+
+ 2009-01-28 Jonathan Larmour
+ * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run
+ out of pool pbufs.
+
+ 2008-12-19 Simon Goldschmidt
+ * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2
+
+ 2008-12-10 Tamas Somogyi, Frédéric Bernon
+ * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and
+ port uses deleted netbuf.
+
+ 2008-10-18 Simon Goldschmidt
+ * tcp_in.c: fixed bug ##24596: Vulnerability on faulty TCP options length
+ in tcp_parseopt
+
+ 2008-10-15 Simon Goldschmidt
+ * ip_frag.c: fixed bug #24517: IP reassembly crashes on unaligned IP headers
+ by packing the struct ip_reass_helper.
+
+ 2008-10-03 David Woodhouse, Jonathan Larmour
+ * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address.
+
+ 2008-10-02 Jonathan Larmour
+ * dns.c: Hard-code structure sizes, to avoid issues on some compilers where
+ padding is included.
+
+ 2008-09-30 Jonathan Larmour
+ * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an
+ assertion check that addrlen isn't NULL.
+
+ 2008-09-30 Jonathan Larmour
+ * tcp.c: Fix bug #24227, wrong error message in tcp_bind.
+
+ 2008-08-26 Simon Goldschmidt
+ * inet.h, ip_addr.h: fixed bug #24132: Cross-dependency between ip_addr.h and
+ inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h
+
+ 2008-08-14 Simon Goldschmidt
+ * api_msg.c: fixed bug #23847: do_close_internal references freed memory (when
+ tcp_close returns != ERR_OK)
+
+ 2008-07-08 Frédéric Bernon
+ * stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters
+ in macros, mainly if MEM_STATS=0 and MEMP_STATS=0).
+
+ 2008-06-24 Jonathan Larmour
+ * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused
+ if tcp_seg_copy fails.
+
+ 2008-06-17 Simon Goldschmidt
+ * inet_chksum.c: Checked in some ideas of patch #6460 (loop optimizations)
+ and created defines for swapping bytes and folding u32 to u16.
+
+ 2008-05-30 Kieran Mansley
+ * tcp_in.c Remove redundant "if" statement, and use real rcv_wnd
+ rather than rcv_ann_wnd when deciding if packets are in-window.
+ Contributed by <arasmussen@consultant.datasys.swri.edu>
+
+ 2008-05-30 Kieran Mansley
+ * mem.h: Fix BUG#23254. Change macro definition of mem_* to allow
+ passing as function pointers when MEM_LIBC_MALLOC is defined.
+
+ 2008-05-09 Jonathan Larmour
+ * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to
+ stop it being treated as a fatal error.
+
+ 2008-04-15 Simon Goldschmidt
+ * dhcp.c: fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP
+ (flag now cleared)
+
+ 2008-03-27 Simon Goldschmidt
+ * mem.c, tcpip.c, tcpip.h, opt.h: fixed bug #21433 (Calling mem_free/pbuf_free
+ from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1
+ in lwipopts.h or use pbuf_free_callback(p)/mem_free_callback(m) to free pbufs
+ or heap memory from interrupt context
+
+ 2008-03-26 Simon Goldschmidt
+ * tcp_in.c, tcp.c: fixed bug #22249: division by zero could occur if a remote
+ host sent a zero mss as TCP option.
+
+
+(STABLE-1.3.0)
+
+ ++ New features:
+
+ 2008-03-10 Jonathan Larmour
+ * inet_chksum.c: Allow choice of one of the sample algorithms to be
+ made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM.
+
+ 2008-01-22 Frédéric Bernon
+ * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in
+ TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names.
+
+ 2008-01-14 Frédéric Bernon
+ * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable
+ to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the
+ tcp_recv callback (see rawapi.txt).
+
+ 2008-01-14 Frédéric Bernon, Marc Chaland
+ * ip.c: Integrate patch #6369" ip_input : checking before realloc".
+
+ 2008-01-12 Frédéric Bernon
+ * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field
+ netconn::sem per netconn::op_completed like suggested for the task #7490
+ "Add return value to sys_mbox_post".
+
+ 2008-01-12 Frédéric Bernon
+ * api_msg.c, opt.h: replace DEFAULT_RECVMBOX_SIZE per DEFAULT_TCP_RECVMBOX_SIZE,
+ DEFAULT_UDP_RECVMBOX_SIZE and DEFAULT_RAW_RECVMBOX_SIZE (to optimize queues
+ sizes), like suggested for the task #7490 "Add return value to sys_mbox_post".
+
+ 2008-01-10 Frédéric Bernon
+ * tcpip.h, tcpip.c: add tcpip_callback_with_block function for the task #7490
+ "Add return value to sys_mbox_post". tcpip_callback is always defined as
+ "blocking" ("block" parameter = 1).
+
+ 2008-01-10 Frédéric Bernon
+ * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field
+ netconn::mbox (sys_mbox_t) per netconn::sem (sys_sem_t) for the task #7490
+ "Add return value to sys_mbox_post".
+
+ 2008-01-05 Frédéric Bernon
+ * sys_arch.txt, api.h, api_lib.c, api_msg.h, api_msg.c, tcpip.c, sys.h, opt.h:
+ Introduce changes for task #7490 "Add return value to sys_mbox_post" with some
+ modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which
+ indicate the number of pointers query by the mailbox. There is three defines
+ in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the
+ netconn::acceptmbox. Port maintainers, you can decide to just add this new
+ parameter in your implementation, but to ignore it to keep the previous behavior.
+ The new sys_mbox_trypost function return a value to know if the mailbox is
+ full or if the message is posted. Take a look to sys_arch.txt for more details.
+ This new function is used in tcpip_input (so, can be called in an interrupt
+ context since the function is not blocking), and in recv_udp and recv_raw.
+
+ 2008-01-04 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour
+ * rawapi.txt, api.h, api_lib.c, api_msg.h, api_msg.c, sockets.c, tcp.h, tcp.c,
+ tcp_in.c, init.c, opt.h: rename backlog options with TCP_ prefix, limit the
+ "backlog" parameter in an u8_t, 0 is interpreted as "smallest queue", add
+ documentation in the rawapi.txt file.
+
+ 2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm)
+ * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer
+
+ 2007-12-31 Frédéric Bernon, Luca Ceresoli
+ * autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets
+ in autoip". The change in etharp_raw could be removed, since all calls to
+ etharp_raw use ethbroadcast for the "ethdst_addr" parameter. But it could be
+ wrong in the future.
+
+ 2007-12-30 Frédéric Bernon, Tom Evans
+ * ip.c: Fix bug #21846 "LwIP doesn't appear to perform any IP Source Address
+ Filtering" reported by Tom Evans.
+
+ 2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour
+ * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c,
+ sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API
+ applications have to call 'tcp_accepted(pcb)' in their accept callback to
+ keep accepting new connections.
+
+ 2007-12-13 Frédéric Bernon
+ * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result"
+ by err_t type. Add a new err_t code "ERR_INPROGRESS".
+
+ 2007-12-12 Frédéric Bernon
+ * dns.h, dns.c, opt.h: move DNS options to the "right" place. Most visibles
+ are the one which have ram usage.
+
+ 2007-12-05 Frédéric Bernon
+ * netdb.c: add a LWIP_DNS_API_HOSTENT_STORAGE option to decide to use a static
+ set of variables (=0) or a local one (=1). In this last case, your port should
+ provide a function "struct hostent* sys_thread_hostent( struct hostent* h)"
+ which have to do a copy of "h" and return a pointer ont the "per-thread" copy.
+
+ 2007-12-03 Simon Goldschmidt
+ * ip.c: ip_input: check if a packet is for inp first before checking all other
+ netifs on netif_list (speeds up packet receiving in most cases)
+
+ 2007-11-30 Simon Goldschmidt
+ * udp.c, raw.c: task #7497: Sort lists (pcb, netif, ...) for faster access
+ UDP: move a (connected) pcb selected for input to the front of the list of
+ pcbs so that it is found faster next time. Same for RAW pcbs that have eaten
+ a packet.
+
+ 2007-11-28 Simon Goldschmidt
+ * etharp.c, stats.c, stats.h, opt.h: Introduced ETHARP_STATS
+
+ 2007-11-25 Simon Goldschmidt
+ * dhcp.c: dhcp_unfold_reply() uses pbuf_copy_partial instead of its own copy
+ algorithm.
+
+ 2007-11-24 Simon Goldschmidt
+ * netdb.h, netdb.c, sockets.h/.c: Moved lwip_gethostbyname from sockets.c
+ to the new file netdb.c; included lwip_getaddrinfo.
+
+ 2007-11-21 Simon Goldschmidt
+ * tcp.h, opt.h, tcp.c, tcp_in.c: implemented calculating the effective send-mss
+ based on the MTU of the netif used to send. Enabled by default. Disable by
+ setting LWIP_CALCULATE_EFF_SEND_MSS to 0. This fixes bug #21492.
+
+ 2007-11-19 Frédéric Bernon
+ * api_msg.c, dns.h, dns.c: Implement DNS_DOES_NAME_CHECK option (check if name
+ received match the name query), implement DNS_USES_STATIC_BUF (the place where
+ copy dns payload to parse the response), return an error if there is no place
+ for a new query, and fix some minor problems.
+
+ 2007-11-16 Simon Goldschmidt
+ * new files: ipv4/inet.c, ipv4/inet_chksum.c, ipv6/inet6.c
+ removed files: core/inet.c, core/inet6.c
+ Moved inet files into ipv4/ipv6 directory; splitted inet.c/inet.h into
+ inet and chksum part; changed includes in all lwIP files as appropriate
+
+ 2007-11-16 Simon Goldschmidt
+ * api.h, api_msg.h, api_lib.c, api_msg.c, socket.h, socket.c: Added sequential
+ dns resolver function for netconn api (netconn_gethostbyname) and socket api
+ (gethostbyname/gethostbyname_r).
+
+ 2007-11-15 Jim Pettinato, Frédéric Bernon
+ * opt.h, init.c, tcpip.c, dhcp.c, dns.h, dns.c: add DNS client for simple name
+ requests with RAW api interface. Initialization is done in lwip_init() with
+ build time options. DNS timer is added in tcpip_thread context. DHCP can set
+ DNS server ip addresses when options are received. You need to set LWIP_DNS=1
+ in your lwipopts.h file (LWIP_DNS=0 in opt.h). DNS_DEBUG can be set to get
+ some traces with LWIP_DEBUGF. Sanity check have been added. There is a "todo"
+ list with points to improve.
+
+ 2007-11-06 Simon Goldschmidt
+ * opt.h, mib2.c: Patch #6215: added ifAdminStatus write support (if explicitly
+ enabled by defining SNMP_SAFE_REQUESTS to 0); added code to check link status
+ for ifOperStatus if LWIP_NETIF_LINK_CALLBACK is defined.
+
+ 2007-11-06 Simon Goldschmidt
+ * api.h, api_msg.h and dependent files: Task #7410: Removed the need to include
+ core header files in api.h (ip/tcp/udp/raw.h) to hide the internal
+ implementation from netconn api applications.
+
+ 2007-11-03 Frédéric Bernon
+ * api.h, api_lib.c, api_msg.c, sockets.c, opt.h: add SO_RCVBUF option for UDP &
+ RAW netconn. You need to set LWIP_SO_RCVBUF=1 in your lwipopts.h (it's disabled
+ by default). Netconn API users can use the netconn_recv_bufsize macro to access
+ it. This is a first release which have to be improve for TCP. Note it used the
+ netconn::recv_avail which need to be more "thread-safe" (note there is already
+ the problem for FIONREAD with lwip_ioctl/ioctlsocket).
+
+ 2007-11-01 Frédéric Bernon, Marc Chaland
+ * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, tcp.h, tcp_out.c:
+ Integrate "patch #6250 : MSG_MORE flag for send". MSG_MORE is used at socket api
+ layer, NETCONN_MORE at netconn api layer, and TCP_WRITE_FLAG_MORE at raw api
+ layer. This option enable to delayed TCP PUSH flag on multiple "write" calls.
+ Note that previous "copy" parameter for "write" APIs is now called "apiflags".
+
+ 2007-10-24 Frédéric Bernon
+ * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than
+ TCP_EVENT_xxx macros to get a code more readable. It could also help to remove
+ some code (like we have talk in "patch #5919 : Create compile switch to remove
+ select code"), but it could be done later.
+
+ 2007-10-08 Simon Goldschmidt
+ * many files: Changed initialization: many init functions are not needed any
+ more since we now rely on the compiler initializing global and static
+ variables to zero!
+
+ 2007-10-06 Simon Goldschmidt
+ * ip_frag.c, memp.c, mib2.c, ip_frag.h, memp_std.h, opt.h: Changed IP_REASSEMBLY
+ to enqueue the received pbufs so that multiple packets can be reassembled
+ simultaneously and no static reassembly buffer is needed.
+
+ 2007-10-05 Simon Goldschmidt
+ * tcpip.c, etharp.h, etharp.c: moved ethernet_input from tcpip.c to etharp.c so
+ all netifs (or ports) can use it.
+
+ 2007-10-05 Frédéric Bernon
+ * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the
+ common function to reduce a little bit the footprint (for all functions using
+ only the "netif" parameter).
+
+ 2007-10-03 Frédéric Bernon
+ * netifapi.h, netifapi.c: add functions netifapi_netif_set_up, netifapi_netif_set_down,
+ netifapi_autoip_start and netifapi_autoip_stop. Use a common function to reduce
+ a little bit the footprint (for all functions using only the "netif" parameter).
+
+ 2007-09-15 Frédéric Bernon
+ * udp.h, udp.c, sockets.c: Changes for "#20503 IGMP Improvement". Add IP_MULTICAST_IF
+ option in socket API, and a new field "multicast_ip" in "struct udp_pcb" (for
+ netconn and raw API users), only if LWIP_IGMP=1. Add getsockopt processing for
+ IP_MULTICAST_TTL and IP_MULTICAST_IF.
+
+ 2007-09-10 Frédéric Bernon
+ * snmp.h, mib2.c: enable to remove SNMP timer (which consumne several cycles
+ even when it's not necessary). snmp_agent.txt tell to call snmp_inc_sysuptime()
+ each 10ms (but, it's intrusive if you use sys_timeout feature). Now, you can
+ decide to call snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but
+ call to a lower frequency). Or, you can decide to not call snmp_inc_sysuptime()
+ or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
+ This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
+ snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
+ when it's queried (any direct call to "sysuptime" is changed by a call to
+ snmp_get_sysuptime).
+
+ 2007-09-09 Frédéric Bernon, Bill Florac
+ * igmp.h, igmp.c, netif.h, netif.c, ip.c: To enable to have interfaces with IGMP,
+ and others without it, there is a new NETIF_FLAG_IGMP flag to set in netif->flags
+ if you want IGMP on an interface. igmp_stop() is now called inside netif_remove().
+ igmp_report_groups() is now called inside netif_set_link_up() (need to have
+ LWIP_NETIF_LINK_CALLBACK=1) to resend reports once the link is up (avoid to wait
+ the next query message to receive the matching multicast streams).
+
+ 2007-09-08 Frédéric Bernon
+ * sockets.c, ip.h, api.h, tcp.h: declare a "struct ip_pcb" which only contains
+ IP_PCB. Add in the netconn's "pcb" union a "struct ip_pcb *ip;" (no size change).
+ Use this new field to access to common pcb fields (ttl, tos, so_options, etc...).
+ Enable to access to these fields with LWIP_TCP=0.
+
+ 2007-09-05 Frédéric Bernon
+ * udp.c, ipv4/icmp.c, ipv4/ip.c, ipv6/icmp.c, ipv6/ip6.c, ipv4/icmp.h,
+ ipv6/icmp.h, opt.h: Integrate "task #7272 : LWIP_ICMP option". The new option
+ LWIP_ICMP enable/disable ICMP module inside the IP stack (enable per default).
+ Be careful, disabling ICMP make your product non-compliant to RFC1122, but
+ help to reduce footprint, and to reduce "visibility" on the Internet.
+
+ 2007-09-05 Frédéric Bernon, Bill Florac
+ * opt.h, sys.h, tcpip.c, slipif.c, ppp.c, sys_arch.txt: Change parameters list
+ for sys_thread_new (see "task #7252 : Create sys_thread_new_ex()"). Two new
+ parameters have to be provided: a task name, and a task stack size. For this
+ one, since it's platform dependant, you could define the best one for you in
+ your lwipopts.h. For port maintainers, you can just add these new parameters
+ in your sys_arch.c file, and but it's not mandatory, use them in your OS
+ specific functions.
+
+ 2007-09-05 Frédéric Bernon
+ * inet.c, autoip.c, msg_in.c, msg_out.c, init.c: Move some build time checkings
+ inside init.c for task #7142 "Sanity check user-configurable values".
+
+ 2007-09-04 Frédéric Bernon, Bill Florac
+ * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by
+ memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the
+ value). It will avoid potential fragmentation problems, use a counter to know
+ how many times a group is used on an netif, and free it when all applications
+ leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity
+ check if LWIP_IGMP!=0).
+
+ 2007-09-03 Frédéric Bernon
+ * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement".
+ Initialize igmp_mac_filter to NULL in netif_add (this field should be set in
+ the netif's "init" function). Use the "imr_interface" field (for socket layer)
+ and/or the "interface" field (for netconn layer), for join/leave operations.
+ The igmp_join/leavegroup first parameter change from a netif to an ipaddr.
+ This field could be a netif's ipaddr, or "any" (same meaning than ip_addr_isany).
+
+ 2007-08-30 Frédéric Bernon
+ * Add netbuf.h, netbuf.c, Change api.h, api_lib.c: #7249 "Split netbuf functions
+ from api/api_lib". Now netbuf API is independant of netconn, and can be used
+ with other API (application based on raw API, or future "socket2" API). Ports
+ maintainers just have to add src/api/netbuf.c in their makefile/projects.
+
+ 2007-08-30 Frédéric Bernon, Jonathan Larmour
+ * init.c: Add first version of lwip_sanity_check for task #7142 "Sanity check
+ user-configurable values".
+
+ 2007-08-29 Frédéric Bernon
+ * igmp.h, igmp.c, tcpip.c, init.c, netif.c: change igmp_init and add igmp_start.
+ igmp_start is call inside netif_add. Now, igmp initialization is in the same
+ spirit than the others modules. Modify some IGMP debug traces.
+
+ 2007-08-29 Frédéric Bernon
+ * Add init.h, init.c, Change opt.h, tcpip.c: Task #7213 "Add a lwip_init function"
+ Add lwip_init function to regroup all modules initializations, and to provide
+ a place to add code for task #7142 "Sanity check user-configurable values".
+ Ports maintainers should remove direct initializations calls from their code,
+ and add init.c in their makefiles. Note that lwip_init() function is called
+ inside tcpip_init, but can also be used by raw api users since all calls are
+ disabled when matching options are disabled. Also note that their is new options
+ in opt.h, you should configure in your lwipopts.h (they are enabled per default).
+
+ 2007-08-26 Marc Boucher
+ * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL
+ since they can under certain circumstances be called with an invalid conn
+ pointer after the connection has been closed (and conn has been freed).
+
+ 2007-08-25 Frédéric Bernon (Artem Migaev's Patch)
+ * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up".
+ Add a netif_is_link_up() function if LWIP_NETIF_LINK_CALLBACK option is set.
+
+ 2007-08-22 Frédéric Bernon
+ * netif.h, netif.c, opt.h: Rename LWIP_NETIF_CALLBACK in LWIP_NETIF_STATUS_CALLBACK
+ to be coherent with new LWIP_NETIF_LINK_CALLBACK option before next release.
+
+ 2007-08-22 Frédéric Bernon
+ * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT &
+ ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the
+ name is tcpip_input (we keep the name of 1.2.0 function).
+
+ 2007-08-17 Jared Grubb
+ * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool
+ settings into new memp_std.h and optional user file lwippools.h. This adds
+ more dynamic mempools, and allows the user to create an arbitrary number of
+ mempools for mem_malloc.
+
+ 2007-08-16 Marc Boucher
+ * api_msg.c: Initialize newconn->state to NETCONN_NONE in accept_function;
+ otherwise it was left to NETCONN_CLOSE and sent_tcp() could prematurely
+ close the connection.
+
+ 2007-08-16 Marc Boucher
+ * sockets.c: lwip_accept(): check netconn_peer() error return.
+
+ 2007-08-16 Marc Boucher
+ * mem.c, mem.h: Added mem_calloc().
+
+ 2007-08-16 Marc Boucher
+ * tcpip.c, tcpip.h memp.c, memp.h: Added distinct memp (MEMP_TCPIP_MSG_INPKT)
+ for input packets to prevent floods from consuming all of MEMP_TCPIP_MSG
+ and starving other message types.
+ Renamed MEMP_TCPIP_MSG to MEMP_TCPIP_MSG_API
+
+ 2007-08-16 Marc Boucher
+ * pbuf.c, pbuf.h, etharp.c, tcp_in.c, sockets.c: Split pbuf flags in pbuf
+ type and flgs (later renamed to flags).
+ Use enum pbuf_flag as pbuf_type. Renumber PBUF_FLAG_*.
+ Improved lwip_recvfrom(). TCP push now propagated.
+
+ 2007-08-16 Marc Boucher
+ * ethernetif.c, contrib/ports/various: ethbroadcast now a shared global
+ provided by etharp.
+
+ 2007-08-16 Marc Boucher
+ * ppp_oe.c ppp_oe.h, auth.c chap.c fsm.c lcp.c ppp.c ppp.h,
+ etharp.c ethernetif.c, etharp.h, opt.h tcpip.h, tcpip.c:
+ Added PPPoE support and various PPP improvements.
+
+ 2007-07-25 Simon Goldschmidt
+ * api_lib.c, ip_frag.c, pbuf.c, api.h, pbuf.h: Introduced pbuf_copy_partial,
+ making netbuf_copy_partial use this function.
+
+ 2007-07-25 Simon Goldschmidt
+ * tcp_in.c: Fix bug #20506: Slow start / initial congestion window starts with
+ 2 * mss (instead of 1 * mss previously) to comply with some newer RFCs and
+ other stacks.
+
+ 2007-07-13 Jared Grubb (integrated by Frédéric Bernon)
+ * opt.h, netif.h, netif.c, ethernetif.c: Add new configuration option to add
+ a link callback in the netif struct, and functions to handle it. Be carefull
+ for port maintainers to add the NETIF_FLAG_LINK_UP flag (like in ethernetif.c)
+ if you want to be sure to be compatible with future changes...
+
+ 2007-06-30 Frédéric Bernon
+ * sockets.h, sockets.c: Implement MSG_PEEK flag for recv/recvfrom functions.
+
+ 2007-06-21 Simon Goldschmidt
+ * etharp.h, etharp.c: Combined etharp_request with etharp_raw for both
+ LWIP_AUTOIP =0 and =1 to remove redundant code.
+
+ 2007-06-21 Simon Goldschmidt
+ * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option
+ MEM_USE_POOLS to use 4 pools with different sized elements instead of a
+ heap. This both prevents memory fragmentation and gives a higher speed
+ at the cost of more memory consumption. Turned off by default.
+
+ 2007-06-21 Simon Goldschmidt
+ * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of
+ netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into
+ int to be able to send a bigger buffer than 64K with one time (mainly
+ used from lwip_send).
+
+ 2007-06-21 Simon Goldschmidt
+ * tcp.h, api_msg.c: Moved the nagle algorithm from netconn_write/do_write
+ into a define (tcp_output_nagle) in tcp.h to provide it to raw api users, too.
+
+ 2007-06-21 Simon Goldschmidt
+ * api.h, api_lib.c, api_msg.c: Fixed bug #20021: Moved sendbuf-processing in
+ netconn_write from api_lib.c to api_msg.c to also prevent multiple context-
+ changes on low memory or empty send-buffer.
+
+ 2007-06-18 Simon Goldschmidt
+ * etharp.c, etharp.h: Changed etharp to use a defined hardware address length
+ of 6 to avoid loading netif->hwaddr_len every time (since this file is only
+ used for ethernet and struct eth_addr already had a defined length of 6).
+
+ 2007-06-17 Simon Goldschmidt
+ * sockets.c, sockets.h: Implemented socket options SO_NO_CHECK for UDP sockets
+ to disable UDP checksum generation on transmit.
+
+ 2007-06-13 Frédéric Bernon, Simon Goldschmidt
+ * debug.h, api_msg.c: change LWIP_ERROR to use it to check errors like invalid
+ pointers or parameters, and let the possibility to redefined it in cc.h. Use
+ this macro to check "conn" parameter in api_msg.c functions.
+
+ 2007-06-11 Simon Goldschmidt
+ * sockets.c, sockets.h: Added UDP lite support for sockets
+
+ 2007-06-10 Simon Goldschmidt
+ * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled
+ by default) to switch off UDP-Lite support if not needed (reduces udp.c code
+ size)
+
+ 2007-06-09 Dominik Spies (integrated by Frédéric Bernon)
+ * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h:
+ AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and
+ LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt
+ (see TODO mark in the source code).
+
+ 2007-06-09 Simon Goldschmidt
+ * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for
+ etharp_output() to match netif->output so etharp_output() can be used
+ directly as netif->output to save one function call.
+
+ 2007-06-08 Simon Goldschmidt
+ * netif.h, ethernetif.c, slipif.c, loopif.c: Added define
+ NETIF_INIT_SNMP(netif, type, speed) to initialize per-netif snmp variables,
+ added initialization of those to ethernetif, slipif and loopif.
+
+ 2007-05-18 Simon Goldschmidt
+ * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF
+ (defaulting to off for now) that can be set to 0 to send fragmented
+ packets by passing PBUF_REFs down the stack.
+
+ 2007-05-23 Frédéric Bernon
+ * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP
+ connections, such present in patch #5959.
+
+ 2007-05-23 Frédéric Bernon
+ * api.h, api_lib.c, api_msg.c, sockets.c: group the different NETCONN_UDPxxx
+ code in only one part...
+
+ 2007-05-18 Simon Goldschmidt
+ * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp
+ elements to overflow. This is achieved by adding some bytes before and after
+ each pool element (increasing their size, of course), filling them with a
+ prominent value and checking them on freeing the element.
+ Set it to 2 to also check every element in every pool each time memp_malloc()
+ or memp_free() is called (slower but more helpful).
+
+ 2007-05-10 Simon Goldschmidt
+ * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for
+ PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce
+ code size.
+
+ 2007-05-11 Frédéric Bernon
+ * sockets.c, api_lib.c, api_msg.h, api_msg.c, netifapi.h, netifapi.c, tcpip.c:
+ Include a function pointer instead of a table index in the message to reduce
+ footprint. Disable some part of lwip_send and lwip_sendto if some options are
+ not set (LWIP_TCP, LWIP_UDP, LWIP_RAW).
+
+ 2007-05-10 Simon Goldschmidt
+ * *.h (except netif/ppp/*.h): Included patch #5448: include '#ifdef __cplusplus
+ \ extern "C" {' in all header files. Now you can write your application using
+ the lwIP stack in C++ and simply #include the core files. Note I have left
+ out the netif/ppp/*h header files for now, since I don't know which files are
+ included by applications and which are for internal use only.
+
+ 2007-05-09 Simon Goldschmidt
+ * opt.h, *.c/*.h: Included patch #5920: Create define to override C-library
+ memcpy. 2 Defines are created: MEMCPY() for normal memcpy, SMEMCPY() for
+ situations where some compilers might inline the copy and save a function
+ call. Also replaced all calls to memcpy() with calls to (S)MEMCPY().
+
+ 2007-05-08 Simon Goldschmidt
+ * mem.h: If MEM_LIBC_MALLOC==1, allow the defines (e.g. mem_malloc() -> malloc())
+ to be overriden in case the C-library malloc implementation is not protected
+ against concurrent access.
+
+ 2007-05-04 Simon Goldschmidt (Atte Kojo)
+ * etharp.c: Introduced fast one-entry-cache to speed up ARP lookup when sending
+ multiple packets to the same host.
+
+ 2007-05-04 Frédéric Bernon, Jonathan Larmour
+ * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fix bug #19162 "lwip_sento: a possible
+ to corrupt remote addr/port connection state". Reduce problems "not enought memory" with
+ netbuf (if we receive lot of datagrams). Improve lwip_sendto (only one exchange between
+ sockets api and api_msg which run in tcpip_thread context). Add netconn_sento function.
+ Warning, if you directly access to "fromaddr" & "fromport" field from netbuf struct,
+ these fields are now renamed "addr" & "port".
+
+ 2007-04-11 Jonathan Larmour
+ * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new
+ sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return
+ with SYS_MBOX_EMPTY. sys_arch_mbox_tryfetch can be implemented as a function-like macro
+ by the port in sys_arch.h if desired.
+
+ 2007-04-06 Frédéric Bernon, Simon Goldschmidt
+ * opt.h, tcpip.h, tcpip.c, netifapi.h, netifapi.c: New configuration option LWIP_NETIF_API
+ allow to use thread-safe functions to add/remove netif in list, and to start/stop dhcp
+ clients, using new functions from netifapi.h. Disable as default (no port change to do).
+
+ 2007-04-05 Frédéric Bernon
+ * sockets.c: remplace ENOBUFS errors on alloc_socket by ENFILE to be more BSD compliant.
+
+ 2007-04-04 Simon Goldschmidt
+ * arch.h, api_msg.c, dhcp.c, msg_in.c, sockets.c: Introduced #define LWIP_UNUSED_ARG(x)
+ use this for and architecture-independent form to tell the compiler you intentionally
+ are not using this variable. Can be overriden in cc.h.
+
+ 2007-03-28 Frédéric Bernon
+ * opt.h, netif.h, dhcp.h, dhcp.c: New configuration option LWIP_NETIF_HOSTNAME allow to
+ define a hostname in netif struct (this is just a pointer, so, you can use a hardcoded
+ string, point on one of your's ethernetif field, or alloc a string you will free yourself).
+ It will be used by DHCP to register a client hostname, but can also be use when you call
+ snmp_set_sysname.
+
+ 2007-03-28 Frédéric Bernon
+ * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to
+ initialize a network interface's flag with. It tell this interface is an ethernet
+ device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility
+ Support for IPv4" section 4.6) when interface is "up" with netif_set_up().
+
+ 2007-03-26 Frédéric Bernon, Jonathan Larmour
+ * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build
+ time if you only use PPP or SLIP. The default is enable. Note we don't have to call
+ etharp_init in your port's initilization sequence if you use tcpip.c, because this call
+ is done in tcpip_init function.
+
+ 2007-03-22 Frédéric Bernon
+ * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the
+ new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in
+ your lwipopts.h. More, unused counters are not defined in the stats structs, and not
+ display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined
+ but never used. Fix msg_in.c with the correct #if test for a stat display.
+
+ 2007-03-21 Kieran Mansley
+ * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com).
+ Provides callback on netif up/down state change.
+
+ 2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds
+ * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c,
+ ip.c, netif.h, tcpip.c, opt.h:
+ New configuration option LWIP_IGMP to enable IGMP processing. Based on only one
+ filter per all network interfaces. Declare a new function in netif to enable to
+ control the MAC filter (to reduce lwIP traffic processing).
+
+ 2007-03-11 Frédéric Bernon
+ * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can
+ be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this
+ unless you know what you're doing (default are RFC1122 compliant). Note
+ that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set in seconds.
+
+ 2007-03-08 Frédéric Bernon
+ * tcp.h: Keepalive values can be configured at compile time, but don't change
+ this unless you know what you're doing (default are RFC1122 compliant).
+
+ 2007-03-08 Frédéric Bernon
+ * sockets.c, api.h, api_lib.c, tcpip.c, sys.h, sys.c, err.c, opt.h:
+ Implement LWIP_SO_RCVTIMEO configuration option to enable/disable SO_RCVTIMEO
+ on UDP sockets/netconn.
+
+ 2007-03-08 Simon Goldschmidt
+ * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time.
+
+ 2007-03-06 Frédéric Bernon
+ * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h:
+ Implement SO_RCVTIMEO on UDP sockets/netconn.
+
+ 2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt)
+ * api_lib.c, tcpip.c, memp.c, memp.h: make API msg structs allocated
+ on the stack and remove the API msg type from memp
+
+ 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt)
+ * sockets.h, sockets.c: Move socket initialization to new
+ lwip_socket_init() function.
+ NOTE: this changes the API with ports. Ports will have to be
+ updated to call lwip_socket_init() now.
+
+ 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt)
+ * api_lib.c: Use memcpy in netbuf_copy_partial.
+
+
+ ++ Bug fixes:
+
+ 2008-03-17 Frédéric Bernon, Ed Kerekes
+ * igmp.h, igmp.c: Fix bug #22613 "IGMP iphdr problem" (could have
+ some problems to fill the IP header on some targets, use now the
+ ip.h macros to do it).
+
+ 2008-03-13 Frédéric Bernon
+ * sockets.c: Fix bug #22435 "lwip_recvfrom with TCP break;". Using
+ (lwip_)recvfrom with valid "from" and "fromlen" parameters, on a
+ TCP connection caused a crash. Note that using (lwip_)recvfrom
+ like this is a bit slow and that using (lwip)getpeername is the
+ good lwip way to do it (so, using recv is faster on tcp sockets).
+
+ 2008-03-12 Frédéric Bernon, Jonathan Larmour
+ * api_msg.c, contrib/apps/ping.c: Fix bug #22530 "api_msg.c's
+ recv_raw() does not consume data", and the ping sample (with
+ LWIP_SOCKET=1, the code did the wrong supposition that lwip_recvfrom
+ returned the IP payload, without the IP header).
+
+ 2008-03-04 Jonathan Larmour
+ * mem.c, stats.c, mem.h: apply patch #6414 to avoid compiler errors
+ and/or warnings on some systems where mem_size_t and size_t differ.
+ * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc.
+
+ 2008-03-04 Kieran Mansley (contributions by others)
+ * Numerous small compiler error/warning fixes from contributions to
+ mailing list after 1.3.0 release candidate made.
+
+ 2008-01-25 Cui hengbin (integrated by Frédéric Bernon)
+ * dns.c: Fix bug #22108 "DNS problem" caused by unaligned structures.
+
+ 2008-01-15 Kieran Mansley
+ * tcp_out.c: BUG20511. Modify persist timer to start when we are
+ prevented from sending by a small send window, not just a zero
+ send window.
+
+ 2008-01-09 Jonathan Larmour
+ * opt.h, ip.c: Rename IP_OPTIONS define to IP_OPTIONS_ALLOWED to avoid
+ conflict with Linux system headers.
+
+ 2008-01-06 Jonathan Larmour
+ * dhcp.c: fix bug #19927: "DHCP NACK problem" by clearing any existing set IP
+ address entirely on receiving a DHCPNAK, and restarting discovery.
+
+ 2007-12-21 Simon Goldschmidt
+ * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail
+ is not protected" by using new macros for interlocked access to modify/test
+ netconn->recv_avail.
+
+ 2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev)
+ * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state)
+
+ 2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm)
+ * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling
+ of silly window avoidance and prevent lwIP from shrinking the window)
+
+ 2007-12-04 Simon Goldschmidt
+ * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last
+ data packet was lost): add assert that all segment lists are empty in
+ tcp_pcb_remove before setting pcb to CLOSED state; don't directly set CLOSED
+ state from LAST_ACK in tcp_process
+
+ 2007-12-02 Simon Goldschmidt
+ * sockets.h: fix bug #21654: exclude definition of struct timeval from #ifndef FD_SET
+ If including <sys/time.h> for system-struct timeval, LWIP_TIMEVAL_PRIVATE now
+ has to be set to 0 in lwipopts.h
+
+ 2007-12-02 Simon Goldschmidt
+ * api_msg.c, api_lib.c: fix bug #21656 (recvmbox problem in netconn API): always
+ allocate a recvmbox in netconn_new_with_proto_and_callback. For a tcp-listen
+ netconn, this recvmbox is later freed and a new mbox is allocated for acceptmbox.
+ This is a fix for thread-safety and allocates all items needed for a netconn
+ when the netconn is created.
+
+ 2007-11-30 Simon Goldschmidt
+ * udp.c: first attempt to fix bug #21655 (DHCP doesn't work reliably with multiple
+ netifs): if LWIP_DHCP is enabled, UDP packets to DHCP_CLIENT_PORT are passed
+ to netif->dhcp->pcb only (if that exists) and not to any other pcb for the same
+ port (only solution to let UDP pcbs 'bind' to a netif instead of an IP address)
+
+ 2007-11-27 Simon Goldschmidt
+ * ip.c: fixed bug #21643 (udp_send/raw_send don't fail if netif is down) by
+ letting ip_route only use netifs that are up.
+
+ 2007-11-27 Simon Goldschmidt
+ * err.h, api_lib.c, api_msg.c, sockets.c: Changed error handling: ERR_MEM, ERR_BUF
+ and ERR_RTE are seen as non-fatal, all other errors are fatal. netconns and
+ sockets block most operations once they have seen a fatal error.
+
+ 2007-11-27 Simon Goldschmidt
+ * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the
+ netif to send as an argument (to be able to send on netifs that are down).
+
+ 2007-11-26 Simon Goldschmidt
+ * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs
+ arrive out-of-order
+
+ 2007-11-21 Simon Goldschmidt
+ * tcp.h, tcp_out.c, api_msg.c: Fixed bug #20287: tcp_output_nagle sends too early
+ Fixed the nagle algorithm; nagle now also works for all raw API applications
+ and has to be explicitly disabled with 'tcp_pcb->flags |= TF_NODELAY'
+
+ 2007-11-12 Frédéric Bernon
+ * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fixed bug #20900. Now, most
+ of the netconn_peer and netconn_addr processing is done inside tcpip_thread
+ context in do_getaddr.
+
+ 2007-11-10 Simon Goldschmidt
+ * etharp.c: Fixed bug: assert fired when MEMP_ARP_QUEUE was empty (which can
+ happen any time). Now the packet simply isn't enqueued when out of memory.
+
+ 2007-11-01 Simon Goldschmidt
+ * tcp.c, tcp_in.c: Fixed bug #21494: The send mss (pcb->mss) is set to 536 (or
+ TCP_MSS if that is smaller) as long as no MSS option is received from the
+ remote host.
+
+ 2007-11-01 Simon Goldschmidt
+ * tcp.h, tcp.c, tcp_in.c: Fixed bug #21491: The MSS option sent (with SYN)
+ is now based on TCP_MSS instead of pcb->mss (on passive open now effectively
+ sending our configured TCP_MSS instead of the one received).
+
+ 2007-11-01 Simon Goldschmidt
+ * tcp_in.c: Fixed bug #21181: On active open, the initial congestion window was
+ calculated based on the configured TCP_MSS, not on the MSS option received
+ with SYN+ACK.
+
+ 2007-10-09 Simon Goldschmidt
+ * udp.c, inet.c, inet.h: Fixed UDPLite: send: Checksum was always generated too
+ short and also was generated wrong if checksum coverage != tot_len;
+ receive: checksum was calculated wrong if checksum coverage != tot_len
+
+ 2007-10-08 Simon Goldschmidt
+ * mem.c: lfree was not updated in mem_realloc!
+
+ 2007-10-07 Frédéric Bernon
+ * sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential
+ crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT:
+ this change cause an API breakage for netconn_addr, since a parameter
+ type change. Any compiler should cause an error without any changes in
+ yours netconn_peer calls (so, it can't be a "silent change"). It also
+ reduce a little bit the footprint for socket layer (lwip_getpeername &
+ lwip_getsockname use now a common lwip_getaddrname function since
+ netconn_peer & netconn_addr have the same parameters).
+
+ 2007-09-20 Simon Goldschmidt
+ * tcp.c: Fixed bug #21080 (tcp_bind without check pcbs in TIME_WAIT state)
+ by checking tcp_tw_pcbs also
+
+ 2007-09-19 Simon Goldschmidt
+ * icmp.c: Fixed bug #21107 (didn't reset IP TTL in ICMP echo replies)
+
+ 2007-09-15 Mike Kleshov
+ * mem.c: Fixed bug #21077 (inaccuracy in calculation of lwip_stat.mem.used)
+
+ 2007-09-06 Frédéric Bernon
+ * several-files: replace some #include "arch/cc.h" by "lwip/arch.h", or simply remove
+ it as long as "lwip/opt.h" is included before (this one include "lwip/debug.h" which
+ already include "lwip/arch.h"). Like that, default defines are provided by "lwip/arch.h"
+ if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h.
+
+ 2007-08-30 Frédéric Bernon
+ * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces,
+ and fix some coding style.
+
+ 2007-08-28 Frédéric Bernon
+ * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any
+ kind of packets. These packets are considered like Ethernet packets (payload
+ pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets
+ are considered like IP packets (payload pointing to iphdr).
+
+ 2007-08-27 Frédéric Bernon
+ * api.h, api_lib.c, api_msg.c: First fix for "bug #20900 : Potential crash error
+ problem with netconn_peer & netconn_addr". Introduce NETCONN_LISTEN netconn_state
+ and remove obsolete ones (NETCONN_RECV & NETCONN_ACCEPT).
+
+ 2007-08-24 Kieran Mansley
+ * inet.c Modify (acc >> 16) test to ((acc >> 16) != 0) to help buggy
+ compiler (Paradigm C++)
+
+ 2007-08-09 Frédéric Bernon, Bill Florac
+ * stats.h, stats.c, igmp.h, igmp.c, opt.h: Fix for bug #20503 : IGMP Improvement.
+ Introduce IGMP_STATS to centralize statistics management.
+
+ 2007-08-09 Frédéric Bernon, Bill Florac
+ * udp.c: Fix for bug #20503 : IGMP Improvement. Enable to receive a multicast
+ packet on a udp pcb binded on an netif's IP address, and not on "any".
+
+ 2007-08-09 Frédéric Bernon, Bill Florac
+ * igmp.h, igmp.c, ip.c: Fix minor changes from bug #20503 : IGMP Improvement.
+ This is mainly on using lookup/lookfor, and some coding styles...
+
+ 2007-07-26 Frédéric Bernon (and "thedoctor")
+ * igmp.c: Fix bug #20595 to accept IGMPv3 "Query" messages.
+
+ 2007-07-25 Simon Goldschmidt
+ * api_msg.c, tcp.c: Another fix for bug #20021: by not returning an error if
+ tcp_output fails in tcp_close, the code in do_close_internal gets simpler
+ (tcp_output is called again later from tcp timers).
+
+ 2007-07-25 Simon Goldschmidt
+ * ip_frag.c: Fixed bug #20429: use the new pbuf_copy_partial instead of the old
+ copy_from_pbuf, which illegally modified the given pbuf.
+
+ 2007-07-25 Simon Goldschmidt
+ * tcp_out.c: tcp_enqueue: pcb->snd_queuelen didn't work for chaine PBUF_RAMs:
+ changed snd_queuelen++ to snd_queuelen += pbuf_clen(p).
+
+ 2007-07-24 Simon Goldschmidt
+ * api_msg.c, tcp.c: Fix bug #20480: Check the pcb passed to tcp_listen() for the
+ correct state (must be CLOSED).
+
+ 2007-07-13 Thomas Taranowski (commited by Jared Grubb)
+ * memp.c: Fix bug #20478: memp_malloc returned NULL+MEMP_SIZE on failed
+ allocation. It now returns NULL.
+
+ 2007-07-13 Frédéric Bernon
+ * api_msg.c: Fix bug #20318: api_msg "recv" callbacks don't call pbuf_free in
+ all error cases.
+
+ 2007-07-13 Frédéric Bernon
+ * api_msg.c: Fix bug #20315: possible memory leak problem if tcp_listen failed,
+ because current code doesn't follow rawapi.txt documentation.
+
+ 2007-07-13 Kieran Mansley
+ * src/core/tcp_in.c Apply patch#5741 from Oleg Tyshev to fix bug in
+ out of sequence processing of received packets
+
+ 2007-07-03 Simon Goldschmidt
+ * nearly-all-files: Added assertions where PBUF_RAM pbufs are used and an
+ assumption is made that this pbuf is in one piece (i.e. not chained). These
+ assumptions clash with the possibility of converting to fully pool-based
+ pbuf implementations, where PBUF_RAM pbufs might be chained.
+
+ 2007-07-03 Simon Goldschmidt
+ * api.h, api_lib.c, api_msg.c: Final fix for bug #20021 and some other problems
+ when closing tcp netconns: removed conn->sem, less context switches when
+ closing, both netconn_close and netconn_delete should safely close tcp
+ connections.
+
+ 2007-07-02 Simon Goldschmidt
+ * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c,
+ tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off)
+ to cache ARP table indices with each pcb instead of single-entry cache for
+ the complete stack.
+
+ 2007-07-02 Simon Goldschmidt
+ * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent
+ warnings when assigning to smaller types.
+
+ 2007-06-28 Simon Goldschmidt
+ * tcp_out.c: Added check to prevent tcp_pcb->snd_queuelen from overflowing.
+
+ 2007-06-28 Simon Goldschmidt
+ * tcp.h: Fixed bug #20287: Fixed nagle algorithm (sending was done too early if
+ a segment contained chained pbufs)
+
+ 2007-06-28 Frédéric Bernon
+ * autoip.c: replace most of rand() calls by a macro LWIP_AUTOIP_RAND which compute
+ a "pseudo-random" value based on netif's MAC and some autoip fields. It's always
+ possible to define this macro in your own lwipopts.h to always use C library's
+ rand(). Note that autoip_create_rand_addr doesn't use this macro.
+
+ 2007-06-28 Frédéric Bernon
+ * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option
+ LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications
+ in api_lib/api_msg (use pointers and not type with table, etc...)
+
+ 2007-06-26 Simon Goldschmidt
+ * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines.
+
+ 2007-06-25 Simon Goldschmidt
+ * udp.c: Fixed bug #20253: icmp_dest_unreach was called with a wrong p->payload
+ for udp packets with no matching pcb.
+
+ 2007-06-25 Simon Goldschmidt
+ * udp.c: Fixed bug #20220: UDP PCB search in udp_input(): a non-local match
+ could get udp input packets if the remote side matched.
+
+ 2007-06-13 Simon Goldschmidt
+ * netif.c: Fixed bug #20180 (TCP pcbs listening on IP_ADDR_ANY could get
+ changed in netif_set_ipaddr if previous netif->ip_addr.addr was 0.
+
+ 2007-06-13 Simon Goldschmidt
+ * api_msg.c: pcb_new sets conn->err if protocol is not implemented
+ -> netconn_new_..() does not allocate a new connection for unsupported
+ protocols.
+
+ 2007-06-13 Frédéric Bernon, Simon Goldschmidt
+ * api_lib.c: change return expression in netconn_addr and netconn_peer, because
+ conn->err was reset to ERR_OK without any reasons (and error was lost)...
+
+ 2007-06-13 Frédéric Bernon, Matthias Weisser
+ * opt.h, mem.h, mem.c, memp.c, pbuf.c, ip_frag.c, vj.c: Fix bug #20162. Rename
+ MEM_ALIGN in LWIP_MEM_ALIGN and MEM_ALIGN_SIZE in LWIP_MEM_ALIGN_SIZE to avoid
+ some macro names collision with some OS macros.
+
+ 2007-06-11 Simon Goldschmidt
+ * udp.c: UDP Lite: corrected the use of chksum_len (based on RFC3828: if it's 0,
+ create checksum over the complete packet. On RX, if it's < 8 (and not 0),
+ discard the packet. Also removed the duplicate 'udphdr->chksum = 0' for both
+ UDP & UDP Lite.
+
+ 2007-06-11 Srinivas Gollakota & Oleg Tyshev
+ * tcp_out.c: Fix for bug #20075 : "A problem with keep-alive timer and TCP flags"
+ where TCP flags wasn't initialized in tcp_keepalive.
+
+ 2007-06-03 Simon Goldschmidt
+ * udp.c: udp_input(): Input pbuf was not freed if pcb had no recv function
+ registered, p->payload was modified without modifying p->len if sending
+ icmp_dest_unreach() (had no negative effect but was definitively wrong).
+
+ 2007-06-03 Simon Goldschmidt
+ * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp
+ re-used the input pbuf even if that didn't have enough space to include the
+ link headers. Now the space is tested and a new pbuf is allocated for the
+ echo response packet if the echo request pbuf isn't big enough.
+
+ 2007-06-01 Simon Goldschmidt
+ * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread.
+
+ 2007-05-23 Frédéric Bernon
+ * api_lib.c, sockets.c: Fixed bug #5958 for netconn_listen (acceptmbox only
+ allocated by do_listen if success) and netconn_accept errors handling. In
+ most of api_lib functions, we replace some errors checkings like "if (conn==NULL)"
+ by ASSERT, except for netconn_delete.
+
+ 2007-05-23 Frédéric Bernon
+ * api_lib.c: Fixed bug #5957 "Safe-thread problem inside netconn_recv" to return
+ an error code if it's impossible to fetch a pbuf on a TCP connection (and not
+ directly close the recvmbox).
+
+ 2007-05-22 Simon Goldschmidt
+ * tcp.c: Fixed bug #1895 (tcp_bind not correct) by introducing a list of
+ bound but unconnected (and non-listening) tcp_pcbs.
+
+ 2007-05-22 Frédéric Bernon
+ * sys.h, sys.c, api_lib.c, tcpip.c: remove sys_mbox_fetch_timeout() (was only
+ used for LWIP_SO_RCVTIMEO option) and use sys_arch_mbox_fetch() instead of
+ sys_mbox_fetch() in api files. Now, users SHOULD NOT use internal lwIP features
+ like "sys_timeout" in their application threads.
+
+ 2007-05-22 Frédéric Bernon
+ * api.h, api_lib.c, api_msg.h, api_msg.c: change the struct api_msg_msg to see
+ which parameters are used by which do_xxx function, and to avoid "misusing"
+ parameters (patch #5938).
+
+ 2007-05-22 Simon Goldschmidt
+ * api_lib.c, api_msg.c, raw.c, api.h, api_msg.h, raw.h: Included patch #5938:
+ changed raw_pcb.protocol from u16_t to u8_t since for IPv4 and IPv6, proto
+ is only 8 bits wide. This affects the api, as there, the protocol was
+ u16_t, too.
+
+ 2007-05-18 Simon Goldschmidt
+ * memp.c: addition to patch #5913: smaller pointer was returned but
+ memp_memory was the same size -> did not save memory.
+
+ 2007-05-16 Simon Goldschmidt
+ * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns
+ != ERR_OK.
+
+ 2007-05-16 Simon Goldschmidt
+ * api_msg.c, udp.c: If a udp_pcb has a local_ip set, check if it is the same
+ as the one of the netif used for sending to prevent sending from old
+ addresses after a netif address gets changed (partly fixes bug #3168).
+
+ 2007-05-16 Frédéric Bernon
+ * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work
+ with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in
+ tcpip_init) because we have to be sure that network interfaces are already
+ added (mac filter is updated only in igmp_init for the moment).
+
+ 2007-05-16 Simon Goldschmidt
+ * mem.c, memp.c: Removed semaphores from memp, changed sys_sem_wait calls
+ into sys_arch_sem_wait calls to prevent timers from running while waiting
+ for the heap. This fixes bug #19167.
+
+ 2007-05-13 Simon Goldschmidt
+ * tcp.h, sockets.h, sockets.c: Fixed bug from patch #5865 by moving the defines
+ for socket options (lwip_set/-getsockopt) used with level IPPROTO_TCP from
+ tcp.h to sockets.h.
+
+ 2007-05-07 Simon Goldschmidt
+ * mem.c: Another attempt to fix bug #17922.
+
+ 2007-05-04 Simon Goldschmidt
+ * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy()
+ implementation so that it can be reused (don't allocate the target
+ pbuf inside pbuf_copy()).
+
+ 2007-05-04 Simon Goldschmidt
+ * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem
+ to save a little RAM (next pointer of memp is not used while not in pool).
+
+ 2007-05-03 "maq"
+ * sockets.c: Fix ioctl FIONREAD when some data remains from last recv.
+ (patch #3574).
+
+ 2007-04-23 Simon Goldschmidt
+ * loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results
+ in NULL reference for incoming TCP packets". Loopif has to be configured
+ (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input()
+ (multithreading environments, e.g. netif->input() = tcpip_input()) or
+ putting packets on a list that is fed to the stack by calling loopif_poll()
+ (single-thread / NO_SYS / polling environment where e.g.
+ netif->input() = ip_input).
+
+ 2007-04-17 Jonathan Larmour
+ * pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold
+ the difference between two u16_t's.
+ * sockets.h: FD_SETSIZE needs to match number of sockets, which is
+ MEMP_NUM_NETCONN in sockets.c right now.
+
+ 2007-04-12 Jonathan Larmour
+ * icmp.c: Reset IP header TTL in ICMP ECHO responses (bug #19580).
+
+ 2007-04-12 Kieran Mansley
+ * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission
+ timer is reset to fix bug#19434, with help from Oleg Tyshev.
+
+ 2007-04-11 Simon Goldschmidt
+ * etharp.c, pbuf.c, pbuf.h: 3rd fix for bug #11400 (arp-queuing): More pbufs than
+ previously thought need to be copied (everything but PBUF_ROM!). Cleaned up
+ pbuf.c: removed functions no needed any more (by etharp).
+
+ 2007-04-11 Kieran Mansley
+ * inet.c, ip_addr.h, sockets.h, sys.h, tcp.h: Apply patch #5745: Fix
+ "Constant is long" warnings with 16bit compilers. Contributed by
+ avatar@mmlab.cse.yzu.edu.tw
+
+ 2007-04-05 Frédéric Bernon, Jonathan Larmour
+ * api_msg.c: Fix bug #16830: "err_tcp() posts to connection mailbox when no pend on
+ the mailbox is active". Now, the post is only done during a connect, and do_send,
+ do_write and do_join_leave_group don't do anything if a previous error was signaled.
+
+ 2007-04-03 Frédéric Bernon
+ * ip.c: Don't set the IP_DF ("Don't fragment") flag in the IP header in IP output
+ packets. See patch #5834.
+
+ 2007-03-30 Frédéric Bernon
+ * api_msg.c: add a "pcb_new" helper function to avoid redundant code, and to add
+ missing pcb allocations checking (in do_bind, and for each raw_new). Fix style.
+
+ 2007-03-30 Frédéric Bernon
+ * most of files: prefix all debug.h define with "LWIP_" to avoid any conflict with
+ others environment defines (these were too "generic").
+
+ 2007-03-28 Frédéric Bernon
+ * api.h, api_lib.c, sockets.c: netbuf_ref doesn't check its internal pbuf_alloc call
+ result and can cause a crash. lwip_send now check netbuf_ref result.
+
+ 2007-03-28 Simon Goldschmidt
+ * sockets.c Remove "#include <errno.h>" from sockets.c to avoid multiple
+ definition of macros (in errno.h and lwip/arch.h) if LWIP_PROVIDE_ERRNO is
+ defined. This is the way it should have been already (looking at
+ doc/sys_arch.txt)
+
+ 2007-03-28 Kieran Mansley
+ * opt.h Change default PBUF_POOL_BUFSIZE (again) to accomodate default MSS +
+ IP and TCP headers *and* physical link headers
+
+ 2007-03-26 Frédéric Bernon (based on patch from Dmitry Potapov)
+ * api_lib.c: patch for netconn_write(), fixes a possible race condition which cause
+ to send some garbage. It is not a definitive solution, but the patch does solve
+ the problem for most cases.
+
+ 2007-03-22 Frédéric Bernon
+ * api_msg.h, api_msg.c: Remove obsolete API_MSG_ACCEPT and do_accept (never used).
+
+ 2007-03-22 Frédéric Bernon
+ * api_lib.c: somes resources couldn't be freed if there was errors during
+ netconn_new_with_proto_and_callback.
+
+ 2007-03-22 Frédéric Bernon
+ * ethernetif.c: update netif->input calls to check return value. In older ports,
+ it's a good idea to upgrade them, even if before, there could be another problem
+ (access to an uninitialized mailbox).
+
+ 2007-03-21 Simon Goldschmidt
+ * sockets.c: fixed bug #5067 (essentialy a signed/unsigned warning fixed
+ by casting to unsigned).
+
+ 2007-03-21 Frédéric Bernon
+ * api_lib.c, api_msg.c, tcpip.c: integrate sys_mbox_fetch(conn->mbox, NULL) calls from
+ api_lib.c to tcpip.c's tcpip_apimsg(). Now, use a local variable and not a
+ dynamic one from memp to send tcpip_msg to tcpip_thread in a synchrone call.
+ Free tcpip_msg from tcpip_apimsg is not done in tcpip_thread. This give a
+ faster and more reliable communication between api_lib and tcpip.
+
+ 2007-03-21 Frédéric Bernon
+ * opt.h: Add LWIP_NETIF_CALLBACK (to avoid compiler warning) and set it to 0.
+
+ 2007-03-21 Frédéric Bernon
+ * api_msg.c, igmp.c, igmp.h: Fix C++ style comments
+
+ 2007-03-21 Kieran Mansley
+ * opt.h Change default PBUF_POOL_BUFSIZE to accomodate default MSS +
+ IP and TCP headers
+
+ 2007-03-21 Kieran Mansley
+ * Fix all uses of pbuf_header to check the return value. In some
+ cases just assert if it fails as I'm not sure how to fix them, but
+ this is no worse than before when they would carry on regardless
+ of the failure.
+
+ 2007-03-21 Kieran Mansley
+ * sockets.c, igmp.c, igmp.h, memp.h: Fix C++ style comments and
+ comment out missing header include in icmp.c
+
+ 2007-03-20 Frédéric Bernon
+ * memp.h, stats.c: Fix stats_display function where memp_names table wasn't
+ synchronized with memp.h.
+
+ 2007-03-20 Frédéric Bernon
+ * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input,
+ tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with
+ network interfaces. Also fix a compiler warning.
+
+ 2007-03-20 Kieran Mansley
+ * udp.c: Only try and use pbuf_header() to make space for headers if
+ not a ROM or REF pbuf.
+
+ 2007-03-19 Frédéric Bernon
+ * api_msg.h, api_msg.c, tcpip.h, tcpip.c: Add return types to tcpip_apimsg()
+ and api_msg_post().
+
+ 2007-03-19 Frédéric Bernon
+ * Remove unimplemented "memp_realloc" function from memp.h.
+
+ 2007-03-11 Simon Goldschmidt
+ * pbuf.c: checked in patch #5796: pbuf_alloc: len field claculation caused
+ memory corruption.
+
+ 2007-03-11 Simon Goldschmidt (based on patch from Dmitry Potapov)
+ * api_lib.c, sockets.c, api.h, api_msg.h, sockets.h: Fixed bug #19251
+ (missing `const' qualifier in socket functions), to get more compatible to
+ standard POSIX sockets.
+
+ 2007-03-11 Frédéric Bernon (based on patch from Dmitry Potapov)
+ * sockets.c: Add asserts inside bind, connect and sendto to check input
+ parameters. Remove excessive set_errno() calls after get_socket(), because
+ errno is set inside of get_socket(). Move last sock_set_errno() inside
+ lwip_close.
+
+ 2007-03-09 Simon Goldschmidt
+ * memp.c: Fixed bug #11400: New etharp queueing introduced bug: memp_memory
+ was allocated too small.
+
+ 2007-03-06 Simon Goldschmidt
+ * tcpip.c: Initialize dhcp timers in tcpip_thread (if LWIP_DHCP) to protect
+ the stack from concurrent access.
+
+ 2007-03-06 Frédéric Bernon, Dmitry Potapov
+ * tcpip.c, ip_frag.c, ethernetif.c: Fix some build problems, and a redundancy
+ call to "lwip_stats.link.recv++;" in low_level_input() & ethernetif_input().
+
+ 2007-03-06 Simon Goldschmidt
+ * ip_frag.c, ip_frag.h: Reduce code size: don't include code in those files
+ if IP_FRAG == 0 and IP_REASSEMBLY == 0
+
+ 2007-03-06 Frédéric Bernon, Simon Goldschmidt
+ * opt.h, ip_frag.h, tcpip.h, tcpip.c, ethernetif.c: add new configuration
+ option named ETHARP_TCPIP_ETHINPUT, which enable the new tcpip_ethinput.
+ Allow to do ARP processing for incoming packets inside tcpip_thread
+ (protecting ARP layer against concurrent access). You can also disable
+ old code using tcp_input with new define ETHARP_TCPIP_INPUT set to 0.
+ Older ports have to use tcpip_ethinput.
+
+ 2007-03-06 Simon Goldschmidt (based on patch from Dmitry Potapov)
+ * err.h, err.c: fixed compiler warning "initialization dircards qualifiers
+ from pointer target type"
+
+ 2007-03-05 Frédéric Bernon
+ * opt.h, sockets.h: add new configuration options (LWIP_POSIX_SOCKETS_IO_NAMES,
+ ETHARP_TRUST_IP_MAC, review SO_REUSE)
+
+ 2007-03-04 Frédéric Bernon
+ * api_msg.c: Remove some compiler warnings : parameter "pcb" was never
+ referenced.
+
+ 2007-03-04 Frédéric Bernon
+ * api_lib.c: Fix "[patch #5764] api_lib.c cleanup: after patch #5687" (from
+ Dmitry Potapov).
+ The api_msg struct stay on the stack (not moved to netconn struct).
+
+ 2007-03-04 Simon Goldschmidt (based on patch from Dmitry Potapov)
+ * pbuf.c: Fix BUG#19168 - pbuf_free can cause deadlock (if
+ SYS_LIGHTWEIGHT_PROT=1 & freeing PBUF_RAM when mem_sem is not available)
+ Also fixed cast warning in pbuf_alloc()
+
+ 2007-03-04 Simon Goldschmidt
+ * etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt
+ existing pbuf chain when enqueuing multiple pbufs to a pending ARP request
+
+ 2007-03-03 Frédéric Bernon
+ * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;"
+ It is static, and never used in udp.c except udp_init().
+
+ 2007-03-02 Simon Goldschmidt
+ * tcpip.c: Moved call to ip_init(), udp_init() and tcp_init() from
+ tcpip_thread() to tcpip_init(). This way, raw API connections can be
+ initialized before tcpip_thread is running (e.g. before OS is started)
+
+ 2007-03-02 Frédéric Bernon
+ * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call
+ interval.
+
+ 2007-02-28 Kieran Mansley
+ * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved
+ outside the region of the pbuf by pbuf_header()
+
+ 2007-02-28 Kieran Mansley
+ * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero
+ when supplied timeout is also non-zero
+
+(STABLE-1.2.0)
+
+ 2006-12-05 Leon Woestenberg
+ * CHANGELOG: Mention STABLE-1.2.0 release.
+
+ ++ New features:
+
+ 2006-12-01 Christiaan Simons
+ * mem.h, opt.h: Added MEM_LIBC_MALLOC option.
+ Note this is a workaround. Currently I have no other options left.
+
+ 2006-10-26 Christiaan Simons (accepted patch by Jonathan Larmour)
+ * ipv4/ip_frag.c: rename MAX_MTU to IP_FRAG_MAX_MTU and move define
+ to include/lwip/opt.h.
+ * ipv4/lwip/ip_frag.h: Remove unused IP_REASS_INTERVAL.
+ Move IP_REASS_MAXAGE and IP_REASS_BUFSIZE to include/lwip/opt.h.
+ * opt.h: Add above new options.
+
+ 2006-08-18 Christiaan Simons
+ * tcp_{in,out}.c: added SNMP counters.
+ * ipv4/ip.c: added SNMP counters.
+ * ipv4/ip_frag.c: added SNMP counters.
+
+ 2006-08-08 Christiaan Simons
+ * etharp.{c,h}: added etharp_find_addr() to read
+ (stable) ethernet/IP address pair from ARP table
+
+ 2006-07-14 Christiaan Simons
+ * mib_structs.c: added
+ * include/lwip/snmp_structs.h: added
+ * netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct
+
+ 2006-07-06 Christiaan Simons
+ * snmp/asn1_{enc,dec}.c added
+ * snmp/mib2.c added
+ * snmp/msg_{in,out}.c added
+ * include/lwip/snmp_asn1.h added
+ * include/lwip/snmp_msg.h added
+ * doc/snmp_agent.txt added
+
+ 2006-03-29 Christiaan Simons
+ * inet.c, inet.h: Added platform byteswap support.
+ Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and
+ optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros.
+
+ ++ Bug fixes:
+
+ 2006-11-30 Christiaan Simons
+ * dhcp.c: Fixed false triggers of request_timeout.
+
+ 2006-11-28 Christiaan Simons
+ * netif.c: In netif_add() fixed missing clear of ip_addr, netmask, gw and flags.
+
+ 2006-10-11 Christiaan Simons
+ * api_lib.c etharp.c, ip.c, memp.c, stats.c, sys.{c,h} tcp.h:
+ Partially accepted patch #5449 for ANSI C compatibility / build fixes.
+ * ipv4/lwip/ip.h ipv6/lwip/ip.h: Corrected UDP-Lite protocol
+ identifier from 170 to 136 (bug #17574).
+
+ 2006-10-10 Christiaan Simons
+ * api_msg.c: Fixed Nagle algorithm as reported by Bob Grice.
+
+ 2006-08-17 Christiaan Simons
+ * udp.c: Fixed bug #17200, added check for broadcast
+ destinations for PCBs bound to a unicast address.
+
+ 2006-08-07 Christiaan Simons
+ * api_msg.c: Flushing TCP output in do_close() (bug #15926).
+
+ 2006-06-27 Christiaan Simons
+ * api_msg.c: Applied patch for cold case (bug #11135).
+ In accept_function() ensure newconn->callback is always initialized.
+
+ 2006-06-15 Christiaan Simons
+ * mem.h: added MEM_SIZE_F alias to fix an ancient cold case (bug #1748),
+ facilitate printing of mem_size_t and u16_t statistics.
+
+ 2006-06-14 Christiaan Simons
+ * api_msg.c: Applied patch #5146 to handle allocation failures
+ in accept() by Kevin Lawson.
+
+ 2006-05-26 Christiaan Simons
+ * api_lib.c: Removed conn->sem creation and destruction
+ from netconn_write() and added sys_sem_new to netconn_new_*.
+
+(STABLE-1_1_1)
+
+ 2006-03-03 Christiaan Simons
+ * ipv4/ip_frag.c: Added bound-checking assertions on ip_reassbitmap
+ access and added pbuf_alloc() return value checks.
+
+ 2006-01-01 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * tcp_{in,out}.c, tcp_out.c: Removed 'even sndbuf' fix in TCP, which is
+ now handled by the checksum routine properly.
+
+ 2006-02-27 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * pbuf.c: Fix alignment; pbuf_init() would not work unless
+ pbuf_pool_memory[] was properly aligned. (Patch by Curt McDowell.)
+
+ 2005-12-20 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * tcp.c: Remove PCBs which stay in LAST_ACK state too long. Patch
+ submitted by Mitrani Hiroshi.
+
+ 2005-12-15 Christiaan Simons
+ * inet.c: Disabled the added summing routine to preserve code space.
+
+ 2005-12-14 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * tcp_in.c: Duplicate FIN ACK race condition fix by Kelvin Lawson.
+ Added Curt McDowell's optimized checksumming routine for future
+ inclusion. Need to create test case for unaliged, aligned, odd,
+ even length combination of cases on various endianess machines.
+
+ 2005-12-09 Christiaan Simons
+ * inet.c: Rewrote standard checksum routine in proper portable C.
+
+ 2005-11-25 Christiaan Simons
+ * udp.c tcp.c: Removed SO_REUSE hack. Should reside in socket code only.
+ * *.c: introduced cc.h LWIP_DEBUG formatters matching the u16_t, s16_t,
+ u32_t, s32_t typedefs. This solves most debug word-length assumes.
+
+ 2005-07-17 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * inet.c: Fixed unaligned 16-bit access in the standard checksum
+ routine by Peter Jolasson.
+ * slipif.c: Fixed implementation assumption of single-pbuf datagrams.
+
+ 2005-02-04 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * tcp_out.c: Fixed uninitialized 'queue' referenced in memerr branch.
+ * tcp_{out|in}.c: Applied patch fixing unaligned access.
+
+ 2005-01-04 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * pbuf.c: Fixed missing semicolon after LWIP_DEBUG statement.
+
+ 2005-01-03 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * udp.c: UDP pcb->recv() was called even when it was NULL.
+
+(STABLE-1_1_0)
+
+ 2004-12-28 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * etharp.*: Disabled multiple packets on the ARP queue.
+ This clashes with TCP queueing.
+
+ 2004-11-28 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * etharp.*: Fixed race condition from ARP request to ARP timeout.
+ Halved the ARP period, doubled the period counts.
+ ETHARP_MAX_PENDING now should be at least 2. This prevents
+ the counter from reaching 0 right away (which would allow
+ too little time for ARP responses to be received).
+
+ 2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * dhcp.c: Decline messages were not multicast but unicast.
+ * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD.
+ Do not try hard to insert arbitrary packet's source address,
+ etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD.
+ etharp_query() now always DOES call ETHARP_TRY_HARD so that users
+ querying an address will see it appear in the cache (DHCP could
+ suffer from this when a server invalidly gave an in-use address.)
+ * ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are
+ comparing network addresses (identifiers), not the network masks
+ themselves.
+ * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given
+ IP address actually belongs to the network of the given interface.
+
+ 2004-11-24 Kieran Mansley <kjm25@cam.ac.uk>
+ * tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state.
+
+(STABLE-1_1_0-RC1)
+
+ 2004-10-16 Kieran Mansley <kjm25@cam.ac.uk>
+ * tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately,
+ even if one is already pending, if the rcv_wnd is above a threshold
+ (currently TCP_WND/2). This avoids waiting for a timer to expire to send a
+ delayed ACK in order to open the window if the stack is only receiving data.
+
+ 2004-09-12 Kieran Mansley <kjm25@cam.ac.uk>
+ * tcp*.*: Retransmit time-out handling improvement by Sam Jansen.
+
+ 2004-08-20 Tony Mountifield <tony@softins.co.uk>
+ * etharp.c: Make sure the first pbuf queued on an ARP entry
+ is properly ref counted.
+
+ 2004-07-27 Tony Mountifield <tony@softins.co.uk>
+ * debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler
+ warnings about comparison.
+ * pbuf.c: Stopped compiler complaining of empty if statement
+ when LWIP_DEBUGF() empty. Closed an unclosed comment.
+ * tcp.c: Stopped compiler complaining of empty if statement
+ when LWIP_DEBUGF() empty.
+ * ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons().
+ * inet.c: Added a couple of casts to quiet the compiler.
+ No need to test isascii(c) before isdigit(c) or isxdigit(c).
+
+ 2004-07-22 Tony Mountifield <tony@softins.co.uk>
+ * inet.c: Made data types consistent in inet_ntoa().
+ Added casts for return values of checksum routines, to pacify compiler.
+ * ip_frag.c, tcp_out.c, sockets.c, pbuf.c
+ Small corrections to some debugging statements, to pacify compiler.
+
+ 2004-07-21 Tony Mountifield <tony@softins.co.uk>
+ * etharp.c: Removed spurious semicolon and added missing end-of-comment.
+ * ethernetif.c Updated low_level_output() to match prototype for
+ netif->linkoutput and changed low_level_input() similarly for consistency.
+ * api_msg.c: Changed recv_raw() from int to u8_t, to match prototype
+ of raw_recv() in raw.h and so avoid compiler error.
+ * sockets.c: Added trivial (int) cast to keep compiler happier.
+ * ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros.
+
+(STABLE-1_0_0)
+
+ ++ Changes:
+
+ 2004-07-05 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure
+ your cc.h file defines this either 1 or 0. If non-defined,
+ defaults to 1.
+ * .c: Added <string.h> and <errno.h> includes where used.
+ * etharp.c: Made some array indices unsigned.
+
+ 2004-06-27 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * netif.*: Added netif_set_up()/down().
+ * dhcp.c: Changes to restart program flow.
+
+ 2004-05-07 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * etharp.c: In find_entry(), instead of a list traversal per candidate, do a
+ single-pass lookup for different candidates. Should exploit locality.
+
+ 2004-04-29 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * tcp*.c: Cleaned up source comment documentation for Doxygen processing.
+ * opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC.
+ * etharp.c: update_arp_entry() only adds new ARP entries when adviced to by
+ the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option.
+
+ ++ Bug fixes:
+
+ 2004-04-27 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution
+ suggested by Timmy Brolin. Fix for 32-bit processors that cannot access
+ non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix
+ is to prefix the 14-bit Ethernet headers with two padding bytes.
+
+ 2004-04-23 Leon Woestenberg <leon.woestenberg@gmx.net>
+ * ip_addr.c: Fix in the ip_addr_isbroadcast() check.
+ * etharp.c: Fixed the case where the packet that initiates the ARP request
+ is not queued, and gets lost. Fixed the case where the packets destination
+ address is already known; we now always queue the packet and perform an ARP
+ request.
+
+(STABLE-0_7_0)
+
+ ++ Bug fixes:
+
+ * Fixed TCP bug for SYN_SENT to ESTABLISHED state transition.
+ * Fixed TCP bug in dequeueing of FIN from out of order segment queue.
+ * Fixed two possible NULL references in rare cases.
+
+(STABLE-0_6_6)
+
+ ++ Bug fixes:
+
+ * Fixed DHCP which did not include the IP address in DECLINE messages.
+
+ ++ Changes:
+
+ * etharp.c has been hauled over a bit.
+
+(STABLE-0_6_5)
+
+ ++ Bug fixes:
+
+ * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic.
+ * Packets sent from ARP queue had invalid source hardware address.
+
+ ++ Changes:
+
+ * Pass-by ARP requests do now update the cache.
+
+ ++ New features:
+
+ * No longer dependent on ctype.h.
+ * New socket options.
+ * Raw IP pcb support.
+
+(STABLE-0_6_4)
+
+ ++ Bug fixes:
+
+ * Some debug formatters and casts fixed.
+ * Numereous fixes in PPP.
+
+ ++ Changes:
+
+ * DEBUGF now is LWIP_DEBUGF
+ * pbuf_dechain() has been re-enabled.
+ * Mentioned the changed use of CVS branches in README.
+
+(STABLE-0_6_3)
+
+ ++ Bug fixes:
+
+ * Fixed pool pbuf memory leak in pbuf_alloc().
+ Occured if not enough PBUF_POOL pbufs for a packet pbuf chain.
+ Reported by Savin Zlobec.
+
+ * PBUF_POOL chains had their tot_len field not set for non-first
+ pbufs. Fixed in pbuf_alloc().
+
+ ++ New features:
+
+ * Added PPP stack contributed by Marc Boucher
+
+ ++ Changes:
+
+ * Now drops short packets for ICMP/UDP/TCP protocols. More robust.
+
+ * ARP queueuing now queues the latest packet instead of the first.
+ This is the RFC recommended behaviour, but can be overridden in
+ lwipopts.h.
+
+(0.6.2)
+
+ ++ Bugfixes:
+
+ * TCP has been fixed to deal with the new use of the pbuf->ref
+ counter.
+
+ * DHCP dhcp_inform() crash bug fixed.
+
+ ++ Changes:
+
+ * Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed
+ pbuf_refresh(). This has sped up pbuf pool operations considerably.
+ Implemented by David Haas.
+
+(0.6.1)
+
+ ++ New features:
+
+ * The packet buffer implementation has been enhanced to support
+ zero-copy and copy-on-demand for packet buffers which have their
+ payloads in application-managed memory.
+ Implemented by David Haas.
+
+ Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy
+ if an outgoing packet can be directly sent on the link, or perform
+ a copy-on-demand when necessary.
+
+ The application can safely assume the packet is sent, and the RAM
+ is available to the application directly after calling udp_send()
+ or similar function.
+
+ ++ Bugfixes:
+
+ * ARP_QUEUEING should now correctly work for all cases, including
+ PBUF_REF.
+ Implemented by Leon Woestenberg.
+
+ ++ Changes:
+
+ * IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer
+ to a '0.0.0.0' IP address.
+
+ * The packet buffer implementation is changed. The pbuf->ref counter
+ meaning has changed, and several pbuf functions have been
+ adapted accordingly.
+
+ * netif drivers have to be changed to set the hardware address length field
+ that must be initialized correctly by the driver (hint: 6 for Ethernet MAC).
+ See the contrib/ports/c16x cs8900 driver as a driver example.
+
+ * netif's have a dhcp field that must be initialized to NULL by the driver.
+ See the contrib/ports/c16x cs8900 driver as a driver example.
+
+(0.5.x) This file has been unmaintained up to 0.6.1. All changes are
+ logged in CVS but have not been explained here.
+
+(0.5.3) Changes since version 0.5.2
+
+ ++ Bugfixes:
+
+ * memp_malloc(MEMP_API_MSG) could fail with multiple application
+ threads because it wasn't protected by semaphores.
+
+ ++ Other changes:
+
+ * struct ip_addr now packed.
+
+ * The name of the time variable in arp.c has been changed to ctime
+ to avoid conflicts with the time() function.
+
+(0.5.2) Changes since version 0.5.1
+
+ ++ New features:
+
+ * A new TCP function, tcp_tmr(), now handles both TCP timers.
+
+ ++ Bugfixes:
+
+ * A bug in tcp_parseopt() could cause the stack to hang because of a
+ malformed TCP option.
+
+ * The address of new connections in the accept() function in the BSD
+ socket library was not handled correctly.
+
+ * pbuf_dechain() did not update the ->tot_len field of the tail.
+
+ * Aborted TCP connections were not handled correctly in all
+ situations.
+
+ ++ Other changes:
+
+ * All protocol header structs are now packed.
+
+ * The ->len field in the tcp_seg structure now counts the actual
+ amount of data, and does not add one for SYN and FIN segments.
+
+(0.5.1) Changes since version 0.5.0
+
+ ++ New features:
+
+ * Possible to run as a user process under Linux.
+
+ * Preliminary support for cross platform packed structs.
+
+ * ARP timer now implemented.
+
+ ++ Bugfixes:
+
+ * TCP output queue length was badly initialized when opening
+ connections.
+
+ * TCP delayed ACKs were not sent correctly.
+
+ * Explicit initialization of BSS segment variables.
+
+ * read() in BSD socket library could drop data.
+
+ * Problems with memory alignment.
+
+ * Situations when all TCP buffers were used could lead to
+ starvation.
+
+ * TCP MSS option wasn't parsed correctly.
+
+ * Problems with UDP checksum calculation.
+
+ * IP multicast address tests had endianess problems.
+
+ * ARP requests had wrong destination hardware address.
+
+ ++ Other changes:
+
+ * struct eth_addr changed from u16_t[3] array to u8_t[6].
+
+ * A ->linkoutput() member was added to struct netif.
+
+ * TCP and UDP ->dest_* struct members where changed to ->remote_*.
+
+ * ntoh* macros are now null definitions for big endian CPUs.
+
+(0.5.0) Changes since version 0.4.2
+
+ ++ New features:
+
+ * Redesigned operating system emulation layer to make porting easier.
+
+ * Better control over TCP output buffers.
+
+ * Documenation added.
+
+ ++ Bugfixes:
+
+ * Locking issues in buffer management.
+
+ * Bugfixes in the sequential API.
+
+ * IP forwarding could cause memory leakage. This has been fixed.
+
+ ++ Other changes:
+
+ * Directory structure somewhat changed; the core/ tree has been
+ collapsed.
+
+(0.4.2) Changes since version 0.4.1
+
+ ++ New features:
+
+ * Experimental ARP implementation added.
+
+ * Skeleton Ethernet driver added.
+
+ * Experimental BSD socket API library added.
+
+ ++ Bugfixes:
+
+ * In very intense situations, memory leakage could occur. This has
+ been fixed.
+
+ ++ Other changes:
+
+ * Variables named "data" and "code" have been renamed in order to
+ avoid name conflicts in certain compilers.
+
+ * Variable++ have in appliciable cases been translated to ++variable
+ since some compilers generate better code in the latter case.
+
+(0.4.1) Changes since version 0.4
+
+ ++ New features:
+
+ * TCP: Connection attempts time out earlier than data
+ transmissions. Nagle algorithm implemented. Push flag set on the
+ last segment in a burst.
+
+ * UDP: experimental support for UDP-Lite extensions.
+
+ ++ Bugfixes:
+
+ * TCP: out of order segments were in some cases handled incorrectly,
+ and this has now been fixed. Delayed acknowledgements was broken
+ in 0.4, has now been fixed. Binding to an address that is in use
+ now results in an error. Reset connections sometimes hung an
+ application; this has been fixed.
+
+ * Checksum calculation sometimes failed for chained pbufs with odd
+ lengths. This has been fixed.
+
+ * API: a lot of bug fixes in the API. The UDP API has been improved
+ and tested. Error reporting and handling has been
+ improved. Logical flaws and race conditions for incoming TCP
+ connections has been found and removed.
+
+ * Memory manager: alignment issues. Reallocating memory sometimes
+ failed, this has been fixed.
+
+ * Generic library: bcopy was flawed and has been fixed.
+
+ ++ Other changes:
+
+ * API: all datatypes has been changed from generic ones such as
+ ints, to specified ones such as u16_t. Functions that return
+ errors now have the correct type (err_t).
+
+ * General: A lot of code cleaned up and debugging code removed. Many
+ portability issues have been fixed.
+
+ * The license was changed; the advertising clause was removed.
+
+ * C64 port added.
+
+ * Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri
+ Kosunen, Mikael Caleres, and Frits Wilmink for reporting and
+ fixing bugs!
+
+(0.4) Changes since version 0.3.1
+
+ * Memory management has been radically changed; instead of
+ allocating memory from a shared heap, memory for objects that are
+ rapidly allocated and deallocated is now kept in pools. Allocation
+ and deallocation from those memory pools is very fast. The shared
+ heap is still present but is used less frequently.
+
+ * The memory, memory pool, and packet buffer subsystems now support
+ 4-, 2-, or 1-byte alignment.
+
+ * "Out of memory" situations are handled in a more robust way.
+
+ * Stack usage has been reduced.
+
+ * Easier configuration of lwIP parameters such as memory usage,
+ TTLs, statistics gathering, etc. All configuration parameters are
+ now kept in a single header file "lwipopts.h".
+
+ * The directory structure has been changed slightly so that all
+ architecture specific files are kept under the src/arch
+ hierarchy.
+
+ * Error propagation has been improved, both in the protocol modules
+ and in the API.
+
+ * The code for the RTXC architecture has been implemented, tested
+ and put to use.
+
+ * Bugs have been found and corrected in the TCP, UDP, IP, API, and
+ the Internet checksum modules.
+
+ * Bugs related to porting between a 32-bit and a 16-bit architecture
+ have been found and corrected.
+
+ * The license has been changed slightly to conform more with the
+ original BSD license, including the advertisement clause.
+
+(0.3.1) Changes since version 0.3
+
+ * Fix of a fatal bug in the buffer management. Pbufs with allocated
+ RAM never returned the RAM when the pbuf was deallocated.
+
+ * TCP congestion control, window updates and retransmissions did not
+ work correctly. This has now been fixed.
+
+ * Bugfixes in the API.
+
+(0.3) Changes since version 0.2
+
+ * New and improved directory structure. All include files are now
+ kept in a dedicated include/ directory.
+
+ * The API now has proper error handling. A new function,
+ netconn_err(), now returns an error code for the connection in
+ case of errors.
+
+ * Improvements in the memory management subsystem. The system now
+ keeps a pointer to the lowest free memory block. A new function,
+ mem_malloc2() tries to allocate memory once, and if it fails tries
+ to free some memory and retry the allocation.
+
+ * Much testing has been done with limited memory
+ configurations. lwIP now does a better job when overloaded.
+
+ * Some bugfixes and improvements to the buffer (pbuf) subsystem.
+
+ * Many bugfixes in the TCP code:
+
+ - Fixed a bug in tcp_close().
+
+ - The TCP receive window was incorrectly closed when out of
+ sequence segments was received. This has been fixed.
+
+ - Connections are now timed-out of the FIN-WAIT-2 state.
+
+ - The initial congestion window could in some cases be too
+ large. This has been fixed.
+
+ - The retransmission queue could in some cases be screwed up. This
+ has been fixed.
+
+ - TCP RST flag now handled correctly.
+
+ - Out of sequence data was in some cases never delivered to the
+ application. This has been fixed.
+
+ - Retransmitted segments now contain the correct acknowledgment
+ number and advertised window.
+
+ - TCP retransmission timeout backoffs are not correctly computed
+ (ala BSD). After a number of retransmissions, TCP now gives up
+ the connection.
+
+ * TCP connections now are kept on three lists, one for active
+ connections, one for listening connections, and one for
+ connections that are in TIME-WAIT. This greatly speeds up the fast
+ timeout processing for sending delayed ACKs.
+
+ * TCP now provides proper feedback to the application when a
+ connection has been successfully set up.
+
+ * More comments have been added to the code. The code has also been
+ somewhat cleaned up.
+
+(0.2) Initial public release.
diff --git a/core/lwip/COPYING b/core/lwip/COPYING
new file mode 100644
index 00000000..e23898b5
--- /dev/null
+++ b/core/lwip/COPYING
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+
diff --git a/core/lwip/FILES b/core/lwip/FILES
new file mode 100644
index 00000000..66253196
--- /dev/null
+++ b/core/lwip/FILES
@@ -0,0 +1,4 @@
+src/ - The source code for the lwIP TCP/IP stack.
+doc/ - The documentation for lwIP.
+
+See also the FILES file in each subdirectory.
diff --git a/core/lwip/README b/core/lwip/README
new file mode 100644
index 00000000..a62cc4f3
--- /dev/null
+++ b/core/lwip/README
@@ -0,0 +1,89 @@
+INTRODUCTION
+
+lwIP is a small independent implementation of the TCP/IP protocol
+suite that has been developed by Adam Dunkels at the Computer and
+Networks Architectures (CNA) lab at the Swedish Institute of Computer
+Science (SICS).
+
+The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
+while still having a full scale TCP. This making lwIP suitable for use
+in embedded systems with tens of kilobytes of free RAM and room for
+around 40 kilobytes of code ROM.
+
+FEATURES
+
+ * IP (Internet Protocol) including packet forwarding over multiple network
+ interfaces
+ * ICMP (Internet Control Message Protocol) for network maintenance and debugging
+ * IGMP (Internet Group Management Protocol) for multicast traffic management
+ * UDP (User Datagram Protocol) including experimental UDP-lite extensions
+ * TCP (Transmission Control Protocol) with congestion control, RTT estimation
+ and fast recovery/fast retransmit
+ * Specialized raw/native API for enhanced performance
+ * Optional Berkeley-like socket API
+ * DNS (Domain names resolver)
+ * SNMP (Simple Network Management Protocol)
+ * DHCP (Dynamic Host Configuration Protocol)
+ * AUTOIP (for IPv4, conform with RFC 3927)
+ * PPP (Point-to-Point Protocol)
+ * ARP (Address Resolution Protocol) for Ethernet
+
+LICENSE
+
+lwIP is freely available under a BSD license.
+
+DEVELOPMENT
+
+lwIP has grown into an excellent TCP/IP stack for embedded devices,
+and developers using the stack often submit bug fixes, improvements,
+and additions to the stack to further increase its usefulness.
+
+Development of lwIP is hosted on Savannah, a central point for
+software development, maintenance and distribution. Everyone can
+help improve lwIP by use of Savannah's interface, CVS and the
+mailing list. A core team of developers will commit changes to the
+CVS source tree.
+
+The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
+contributions (such as platform ports) are in the 'contrib' module.
+
+See doc/savannah.txt for details on CVS server access for users and
+developers.
+
+Last night's CVS tar ball can be downloaded from:
+ http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]
+
+The current CVS trees are web-browsable:
+ http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
+ http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
+
+Submit patches and bugs via the lwIP project page:
+ http://savannah.nongnu.org/projects/lwip/
+
+
+DOCUMENTATION
+
+The original out-dated homepage of lwIP and Adam Dunkels' papers on
+lwIP are at the official lwIP home page:
+ http://www.sics.se/~adam/lwip/
+
+Self documentation of the source code is regularly extracted from the
+current CVS sources and is available from this web page:
+ http://www.nongnu.org/lwip/
+
+There is now a constantly growin wiki about lwIP at
+ http://lwip.wikia.com/wiki/LwIP_Wiki
+
+Also, there are mailing lists you can subscribe at
+ http://savannah.nongnu.org/mail/?group=lwip
+plus searchable archives:
+ http://lists.nongnu.org/archive/html/lwip-users/
+ http://lists.nongnu.org/archive/html/lwip-devel/
+
+Reading Adam's papers, the files in docs/, browsing the source code
+documentation and browsing the mailing list archives is a good way to
+become familiar with the design of lwIP.
+
+Adam Dunkels <adam@sics.se>
+Leon Woestenberg <leon.woestenberg@gmx.net>
+
diff --git a/core/lwip/UPGRADING b/core/lwip/UPGRADING
new file mode 100644
index 00000000..6501107a
--- /dev/null
+++ b/core/lwip/UPGRADING
@@ -0,0 +1,144 @@
+This file lists major changes between release versions that require
+ports or applications to be changed. Use it to update a port or an
+application written for an older version of lwIP to correctly work
+with newer versions.
+
+
+(CVS HEAD)
+
+ * [Enter new changes just after this line - do not remove this line]
+
+ ++ Application changes:
+
+ * Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
+ compatibility to old applications, but will be removed in the future).
+
+ * Renamed mem_realloc() to mem_trim() to prevent confusion with realloc()
+
+ +++ Raw API:
+ * Changed the semantics of tcp_close() (since it was rather a
+ shutdown before): Now the application does *NOT* get any calls to the recv
+ callback (aside from NULL/closed) after calling tcp_close()
+
+ * When calling tcp_abort() from a raw API TCP callback function,
+ make sure you return ERR_ABRT to prevent accessing unallocated memory.
+ (ERR_ABRT now means the applicaiton has called tcp_abort!)
+
+ +++ Netconn API:
+ * Changed netconn_receive() and netconn_accept() to return
+ err_t, not a pointer to new data/netconn.
+
+ +++ Socket API:
+ * LWIP_SO_RCVTIMEO: when accept() or recv() time out, they
+ now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT.
+
+ * Added a minimal version of posix fctl() to have a
+ standardised way to set O_NONBLOCK for nonblocking sockets.
+
+ +++ all APIs:
+ * correctly implemented SO(F)_REUSEADDR
+
+ ++ Port changes
+
+ +++ new files:
+
+ * Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h:
+
+ * Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains
+ the actual application programmer's API
+
+ * Separated timer implementation from sys.h/.c, moved to timers.h/.c;
+ Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you
+ still want to use your own timer implementation for NO_SYS==0 (as before).
+
+ +++ sys layer:
+
+ * Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/
+ sys_sem_t;
+
+ * Converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
+
+ * Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use
+ binary semaphores instead of mutexes - as before)
+
+ +++ new options:
+
+ * Don't waste memory when chaining segments, added option TCP_OVERSIZE to
+ prevent creating many small pbufs when calling tcp_write with many small
+ blocks of data. Instead, pbufs are allocated larger than needed and the
+ space is used for later calls to tcp_write.
+
+ * Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs
+ in tcp_write/udp_send.
+
+ * Added an additional option LWIP_ETHERNET to support ethernet without ARP
+ (necessary for pure PPPoE)
+
+ * Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may
+ be used to place these pools into user-defined memory by using external
+ declaration.
+
+ * Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT
+
+ +++ new pools:
+
+ * Netdb uses a memp pool for allocating memory when getaddrinfo() is called,
+ so MEMP_NUM_NETDB has to be set accordingly.
+
+ * DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so
+ MEMP_NUM_LOCALHOSTLIST has to be set accordingly.
+
+ * Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have
+ to be set accordingly.
+
+ * PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES
+ has to be set accordingly
+
+ * Integrated loopif into netif.c - loopif does not have to be created by the
+ port any more, just define LWIP_HAVE_LOOPIF to 1.
+
+ * Added define LWIP_RAND() for lwip-wide randomization (needs to be defined
+ in cc.h, e.g. used by igmp)
+
+ * Added printf-formatter X8_F to printf u8_t as hex
+
+ * The heap now may be moved to user-defined memory by defining
+ LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
+
+ * added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work
+ with user-allocated structs instead of calling mem_malloc
+
+ * Added const char* name to mem- and memp-stats for easier debugging.
+
+ * Calculate the TCP/UDP checksum while copying to only fetch data once:
+ Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum
+
+ * Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to
+ more than one pcb.
+
+ * Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned
+ off any more, if this is set to 0, only one packet (the most recent one) is
+ queued (like demanded by RFC 1122).
+
+
+ ++ Major bugfixes/improvements
+
+ * Implemented tcp_shutdown() to only shut down one end of a connection
+ * Implemented shutdown() at socket- and netconn-level
+ * Added errorset support to select() + improved select speed overhead
+ * Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x)
+ * Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1
+ * Use macros defined in ip_addr.h to work with IP addresses
+ * Implemented many nonblocking socket/netconn functions
+ * Fixed ARP input processing: only add a new entry if a request was directed as us
+ * mem_realloc() to mem_trim() to prevent confusion with realloc()
+ * Some improvements for AutoIP (don't route/forward link-local addresses, don't break
+ existing connections when assigning a routable address)
+ * Correctly handle remote side overrunning our rcv_wnd in ooseq case
+ * Removed packing from ip_addr_t, the packed version is now only used in protocol headers
+ * Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0
+ * Added support for static ARP table entries
+
+(STABLE-1.3.2)
+
+ * initial version of this file
diff --git a/core/lwip/doc/FILES b/core/lwip/doc/FILES
new file mode 100644
index 00000000..05d356f4
--- /dev/null
+++ b/core/lwip/doc/FILES
@@ -0,0 +1,6 @@
+savannah.txt - How to obtain the current development source code.
+contrib.txt - How to contribute to lwIP as a developer.
+rawapi.txt - The documentation for the core API of lwIP.
+ Also provides an overview about the other APIs and multithreading.
+snmp_agent.txt - The documentation for the lwIP SNMP agent.
+sys_arch.txt - The documentation for a system abstraction layer of lwIP.
diff --git a/core/lwip/doc/contrib.txt b/core/lwip/doc/contrib.txt
new file mode 100644
index 00000000..39596fca
--- /dev/null
+++ b/core/lwip/doc/contrib.txt
@@ -0,0 +1,63 @@
+1 Introduction
+
+This document describes some guidelines for people participating
+in lwIP development.
+
+2 How to contribute to lwIP
+
+Here is a short list of suggestions to anybody working with lwIP and
+trying to contribute bug reports, fixes, enhancements, platform ports etc.
+First of all as you may already know lwIP is a volunteer project so feedback
+to fixes or questions might often come late. Hopefully the bug and patch tracking
+features of Savannah help us not lose users' input.
+
+2.1 Source code style:
+
+1. do not use tabs.
+2. indentation is two spaces per level (i.e. per tab).
+3. end debug messages with a trailing newline (\n).
+4. one space between keyword and opening bracket.
+5. no space between function and opening bracket.
+6. one space and no newline before opening curly braces of a block.
+7. closing curly brace on a single line.
+8. spaces surrounding assignment and comparisons.
+9. don't initialize static and/or global variables to zero, the compiler takes care of that.
+10. use current source code style as further reference.
+
+2.2 Source code documentation style:
+
+1. JavaDoc compliant and Doxygen compatible.
+2. Function documentation above functions in .c files, not .h files.
+ (This forces you to synchronize documentation and implementation.)
+3. Use current documentation style as further reference.
+
+2.3 Bug reports and patches:
+
+1. Make sure you are reporting bugs or send patches against the latest
+ sources. (From the latest release and/or the current CVS sources.)
+2. If you think you found a bug make sure it's not already filed in the
+ bugtracker at Savannah.
+3. If you have a fix put the patch on Savannah. If it is a patch that affects
+ both core and arch specific stuff please separate them so that the core can
+ be applied separately while leaving the other patch 'open'. The prefered way
+ is to NOT touch archs you can't test and let maintainers take care of them.
+ This is a good way to see if they are used at all - the same goes for unix
+ netifs except tapif.
+4. Do not file a bug and post a fix to it to the patch area. Either a bug report
+ or a patch will be enough.
+ If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
+5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
+ can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
+ as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
+ for reporting a compiler warning fix.
+6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other
+ trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you
+ change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than
+ if it's not to the point and long :) so the chances for it to be applied are greater.
+
+2.4 Platform porters:
+
+1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
+ you think it could benefit others[1] you might want discuss this on the mailing list. You
+ can also ask for CVS access to submit and maintain your port in the contrib CVS module.
+ \ No newline at end of file
diff --git a/core/lwip/doc/rawapi.txt b/core/lwip/doc/rawapi.txt
new file mode 100644
index 00000000..c727da99
--- /dev/null
+++ b/core/lwip/doc/rawapi.txt
@@ -0,0 +1,505 @@
+Raw TCP/IP interface for lwIP
+
+Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
+
+lwIP provides three Application Program's Interfaces (APIs) for programs
+to use for communication with the TCP/IP code:
+* low-level "core" / "callback" or "raw" API.
+* higher-level "sequential" API.
+* BSD-style socket API.
+
+The sequential API provides a way for ordinary, sequential, programs
+to use the lwIP stack. It is quite similar to the BSD socket API. The
+model of execution is based on the blocking open-read-write-close
+paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
+code and the application program must reside in different execution
+contexts (threads).
+
+The socket API is a compatibility API for existing applications,
+currently it is built on top of the sequential API. It is meant to
+provide all functions needed to run socket API applications running
+on other platforms (e.g. unix / windows etc.). However, due to limitations
+in the specification of this API, there might be incompatibilities
+that require small modifications of existing programs.
+
+** Threading
+
+lwIP started targeting single-threaded environments. When adding multi-
+threading support, instead of making the core thread-safe, another
+approach was chosen: there is one main thread running the lwIP core
+(also known as the "tcpip_thread"). The raw API may only be used from
+this thread! Application threads using the sequential- or socket API
+communicate with this main thread through message passing.
+
+ As such, the list of functions that may be called from
+ other threads or an ISR is very limited! Only functions
+ from these API header files are thread-safe:
+ - api.h
+ - netbuf.h
+ - netdb.h
+ - netifapi.h
+ - sockets.h
+ - sys.h
+
+ Additionaly, memory (de-)allocation functions may be
+ called from multiple threads (not ISR!) with NO_SYS=0
+ since they are protected by SYS_LIGHTWEIGHT_PROT and/or
+ semaphores.
+
+ Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
+ and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
+ pbuf_free() may also be called from another thread or
+ an ISR (since only then, mem_free - for PBUF_RAM - may
+ be called from an ISR: otherwise, the HEAP is only
+ protected by semaphores).
+
+
+** The remainder of this document discusses the "raw" API. **
+
+The raw TCP/IP interface allows the application program to integrate
+better with the TCP/IP code. Program execution is event based by
+having callback functions being called from within the TCP/IP
+code. The TCP/IP code and the application program both run in the same
+thread. The sequential API has a much higher overhead and is not very
+well suited for small systems since it forces a multithreaded paradigm
+on the application.
+
+The raw TCP/IP interface is not only faster in terms of code execution
+time but is also less memory intensive. The drawback is that program
+development is somewhat harder and application programs written for
+the raw TCP/IP interface are more difficult to understand. Still, this
+is the preferred way of writing applications that should be small in
+code size and memory usage.
+
+Both APIs can be used simultaneously by different application
+programs. In fact, the sequential API is implemented as an application
+program using the raw TCP/IP interface.
+
+--- Callbacks
+
+Program execution is driven by callbacks. Each callback is an ordinary
+C function that is called from within the TCP/IP code. Every callback
+function is passed the current TCP or UDP connection state as an
+argument. Also, in order to be able to keep program specific state,
+the callback functions are called with a program specified argument
+that is independent of the TCP/IP state.
+
+The function for setting the application connection state is:
+
+- void tcp_arg(struct tcp_pcb *pcb, void *arg)
+
+ Specifies the program specific state that should be passed to all
+ other callback functions. The "pcb" argument is the current TCP
+ connection control block, and the "arg" argument is the argument
+ that will be passed to the callbacks.
+
+
+--- TCP connection setup
+
+The functions used for setting up connections is similar to that of
+the sequential API and of the BSD socket API. A new TCP connection
+identifier (i.e., a protocol control block - PCB) is created with the
+tcp_new() function. This PCB can then be either set to listen for new
+incoming connections or be explicitly connected to another host.
+
+- struct tcp_pcb *tcp_new(void)
+
+ Creates a new connection identifier (PCB). If memory is not
+ available for creating the new pcb, NULL is returned.
+
+- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
+ u16_t port)
+
+ Binds the pcb to a local IP address and port number. The IP address
+ can be specified as IP_ADDR_ANY in order to bind the connection to
+ all local IP addresses.
+
+ If another connection is bound to the same port, the function will
+ return ERR_USE, otherwise ERR_OK is returned.
+
+- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
+
+ Commands a pcb to start listening for incoming connections. When an
+ incoming connection is accepted, the function specified with the
+ tcp_accept() function will be called. The pcb will have to be bound
+ to a local port with the tcp_bind() function.
+
+ The tcp_listen() function returns a new connection identifier, and
+ the one passed as an argument to the function will be
+ deallocated. The reason for this behavior is that less memory is
+ needed for a connection that is listening, so tcp_listen() will
+ reclaim the memory needed for the original connection and allocate a
+ new smaller memory block for the listening connection.
+
+ tcp_listen() may return NULL if no memory was available for the
+ listening connection. If so, the memory associated with the pcb
+ passed as an argument to tcp_listen() will not be deallocated.
+
+- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
+
+ Same as tcp_listen, but limits the number of outstanding connections
+ in the listen queue to the value specified by the backlog argument.
+ To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
+
+- void tcp_accepted(struct tcp_pcb *pcb)
+
+ Inform lwIP that an incoming connection has been accepted. This would
+ usually be called from the accept callback. This allows lwIP to perform
+ housekeeping tasks, such as allowing further incoming connections to be
+ queued in the listen backlog.
+
+- void tcp_accept(struct tcp_pcb *pcb,
+ err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
+ err_t err))
+
+ Specified the callback function that should be called when a new
+ connection arrives on a listening connection.
+
+- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
+ u16_t port, err_t (* connected)(void *arg,
+ struct tcp_pcb *tpcb,
+ err_t err));
+
+ Sets up the pcb to connect to the remote host and sends the
+ initial SYN segment which opens the connection.
+
+ The tcp_connect() function returns immediately; it does not wait for
+ the connection to be properly setup. Instead, it will call the
+ function specified as the fourth argument (the "connected" argument)
+ when the connection is established. If the connection could not be
+ properly established, either because the other host refused the
+ connection or because the other host didn't answer, the "err"
+ callback function of this pcb (registered with tcp_err, see below)
+ will be called.
+
+ The tcp_connect() function can return ERR_MEM if no memory is
+ available for enqueueing the SYN segment. If the SYN indeed was
+ enqueued successfully, the tcp_connect() function returns ERR_OK.
+
+
+--- Sending TCP data
+
+TCP data is sent by enqueueing the data with a call to
+tcp_write(). When the data is successfully transmitted to the remote
+host, the application will be notified with a call to a specified
+callback function.
+
+- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,
+ u8_t copy)
+
+ Enqueues the data pointed to by the argument dataptr. The length of
+ the data is passed as the len parameter. The copy argument is either
+ 0 or 1 and indicates whether the new memory should be allocated for
+ the data to be copied into. If the argument is 0, no new memory
+ should be allocated and the data should only be referenced by
+ pointer.
+
+ The tcp_write() function will fail and return ERR_MEM if the length
+ of the data exceeds the current send buffer size or if the length of
+ the queue of outgoing segment is larger than the upper limit defined
+ in lwipopts.h. The number of bytes available in the output queue can
+ be retrieved with the tcp_sndbuf() function.
+
+ The proper way to use this function is to call the function with at
+ most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
+ the application should wait until some of the currently enqueued
+ data has been successfully received by the other host and try again.
+
+- void tcp_sent(struct tcp_pcb *pcb,
+ err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
+ u16_t len))
+
+ Specifies the callback function that should be called when data has
+ successfully been received (i.e., acknowledged) by the remote
+ host. The len argument passed to the callback function gives the
+ amount bytes that was acknowledged by the last acknowledgment.
+
+
+--- Receiving TCP data
+
+TCP data reception is callback based - an application specified
+callback function is called when new data arrives. When the
+application has taken the data, it has to call the tcp_recved()
+function to indicate that TCP can advertise increase the receive
+window.
+
+- void tcp_recv(struct tcp_pcb *pcb,
+ err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
+ struct pbuf *p, err_t err))
+
+ Sets the callback function that will be called when new data
+ arrives. The callback function will be passed a NULL pbuf to
+ indicate that the remote host has closed the connection. If
+ there are no errors and the callback function is to return
+ ERR_OK, then it must free the pbuf. Otherwise, it must not
+ free the pbuf so that lwIP core code can store it.
+
+- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
+
+ Must be called when the application has received the data. The len
+ argument indicates the length of the received data.
+
+
+--- Application polling
+
+When a connection is idle (i.e., no data is either transmitted or
+received), lwIP will repeatedly poll the application by calling a
+specified callback function. This can be used either as a watchdog
+timer for killing connections that have stayed idle for too long, or
+as a method of waiting for memory to become available. For instance,
+if a call to tcp_write() has failed because memory wasn't available,
+the application may use the polling functionality to call tcp_write()
+again when the connection has been idle for a while.
+
+- void tcp_poll(struct tcp_pcb *pcb,
+ err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
+ u8_t interval)
+
+ Specifies the polling interval and the callback function that should
+ be called to poll the application. The interval is specified in
+ number of TCP coarse grained timer shots, which typically occurs
+ twice a second. An interval of 10 means that the application would
+ be polled every 5 seconds.
+
+
+--- Closing and aborting connections
+
+- err_t tcp_close(struct tcp_pcb *pcb)
+
+ Closes the connection. The function may return ERR_MEM if no memory
+ was available for closing the connection. If so, the application
+ should wait and try again either by using the acknowledgment
+ callback or the polling functionality. If the close succeeds, the
+ function returns ERR_OK.
+
+ The pcb is deallocated by the TCP code after a call to tcp_close().
+
+- void tcp_abort(struct tcp_pcb *pcb)
+
+ Aborts the connection by sending a RST (reset) segment to the remote
+ host. The pcb is deallocated. This function never fails.
+
+ ATTENTION: When calling this from one of the TCP callbacks, make
+ sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
+ or you will risk accessing deallocated memory or memory leaks!
+
+
+If a connection is aborted because of an error, the application is
+alerted of this event by the err callback. Errors that might abort a
+connection are when there is a shortage of memory. The callback
+function to be called is set using the tcp_err() function.
+
+- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
+ err_t err))
+
+ The error callback function does not get the pcb passed to it as a
+ parameter since the pcb may already have been deallocated.
+
+
+--- Lower layer TCP interface
+
+TCP provides a simple interface to the lower layers of the
+system. During system initialization, the function tcp_init() has
+to be called before any other TCP function is called. When the system
+is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
+must be called with regular intervals. The tcp_fasttmr() should be
+called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
+tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
+
+
+--- UDP interface
+
+The UDP interface is similar to that of TCP, but due to the lower
+level of complexity of UDP, the interface is significantly simpler.
+
+- struct udp_pcb *udp_new(void)
+
+ Creates a new UDP pcb which can be used for UDP communication. The
+ pcb is not active until it has either been bound to a local address
+ or connected to a remote address.
+
+- void udp_remove(struct udp_pcb *pcb)
+
+ Removes and deallocates the pcb.
+
+- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
+ u16_t port)
+
+ Binds the pcb to a local address. The IP-address argument "ipaddr"
+ can be IP_ADDR_ANY to indicate that it should listen to any local IP
+ address. The function currently always return ERR_OK.
+
+- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
+ u16_t port)
+
+ Sets the remote end of the pcb. This function does not generate any
+ network traffic, but only set the remote address of the pcb.
+
+- err_t udp_disconnect(struct udp_pcb *pcb)
+
+ Remove the remote end of the pcb. This function does not generate
+ any network traffic, but only removes the remote address of the pcb.
+
+- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
+
+ Sends the pbuf p. The pbuf is not deallocated.
+
+- void udp_recv(struct udp_pcb *pcb,
+ void (* recv)(void *arg, struct udp_pcb *upcb,
+ struct pbuf *p,
+ struct ip_addr *addr,
+ u16_t port),
+ void *recv_arg)
+
+ Specifies a callback function that should be called when a UDP
+ datagram is received.
+
+
+--- System initalization
+
+A truly complete and generic sequence for initializing the lwip stack
+cannot be given because it depends on the build configuration (lwipopts.h)
+and additional initializations for your runtime environment (e.g. timers).
+
+We can give you some idea on how to proceed when using the raw API.
+We assume a configuration using a single Ethernet netif and the
+UDP and TCP transport layers, IPv4 and the DHCP client.
+
+Call these functions in the order of appearance:
+
+- stats_init()
+
+ Clears the structure where runtime statistics are gathered.
+
+- sys_init()
+
+ Not of much use since we set the NO_SYS 1 option in lwipopts.h,
+ to be called for easy configuration changes.
+
+- lwip_mem_init()
+
+ Initializes the dynamic memory heap defined by MEM_SIZE.
+
+- memp_init()
+
+ Initializes the memory pools defined by MEMP_NUM_x.
+
+- pbuf_init()
+
+ Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.
+
+- etharp_init()
+
+ Initializes the ARP table and queue.
+ Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval
+ after this initialization.
+
+- ip_init()
+
+ Doesn't do much, it should be called to handle future changes.
+
+- udp_init()
+
+ Clears the UDP PCB list.
+
+- tcp_init()
+
+ Clears the TCP PCB list and clears some internal TCP timers.
+ Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
+ predefined regular intervals after this initialization.
+
+- netif_add(struct netif *netif, struct ip_addr *ipaddr,
+ struct ip_addr *netmask, struct ip_addr *gw,
+ void *state, err_t (* init)(struct netif *netif),
+ err_t (* input)(struct pbuf *p, struct netif *netif))
+
+ Adds your network interface to the netif_list. Allocate a struct
+ netif and pass a pointer to this structure as the first argument.
+ Give pointers to cleared ip_addr structures when using DHCP,
+ or fill them with sane numbers otherwise. The state pointer may be NULL.
+
+ The init function pointer must point to a initialization function for
+ your ethernet netif interface. The following code illustrates it's use.
+
+ err_t netif_if_init(struct netif *netif)
+ {
+ u8_t i;
+
+ for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];
+ init_my_eth_device();
+ return ERR_OK;
+ }
+
+ For ethernet drivers, the input function pointer must point to the lwip
+ function ethernet_input() declared in "netif/etharp.h". Other drivers
+ must use ip_input() declared in "lwip/ip.h".
+
+- netif_set_default(struct netif *netif)
+
+ Registers the default network interface.
+
+- netif_set_up(struct netif *netif)
+
+ When the netif is fully configured this function must be called.
+
+- dhcp_start(struct netif *netif)
+
+ Creates a new DHCP client for this interface on the first call.
+ Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
+ the predefined regular intervals after starting the client.
+
+ You can peek in the netif->dhcp struct for the actual DHCP status.
+
+
+--- Optimalization hints
+
+The first thing you want to optimize is the lwip_standard_checksum()
+routine from src/core/inet.c. You can override this standard
+function with the #define LWIP_CHKSUM <your_checksum_routine>.
+
+There are C examples given in inet.c or you might want to
+craft an assembly function for this. RFC1071 is a good
+introduction to this subject.
+
+Other significant improvements can be made by supplying
+assembly or inline replacements for htons() and htonl()
+if you're using a little-endian architecture.
+#define LWIP_PLATFORM_BYTESWAP 1
+#define LWIP_PLATFORM_HTONS(x) <your_htons>
+#define LWIP_PLATFORM_HTONL(x) <your_htonl>
+
+Check your network interface driver if it reads at
+a higher speed than the maximum wire-speed. If the
+hardware isn't serviced frequently and fast enough
+buffer overflows are likely to occur.
+
+E.g. when using the cs8900 driver, call cs8900if_service(ethif)
+as frequently as possible. When using an RTOS let the cs8900 interrupt
+wake a high priority task that services your driver using a binary
+semaphore or event flag. Some drivers might allow additional tuning
+to match your application and network.
+
+For a production release it is recommended to set LWIP_STATS to 0.
+Note that speed performance isn't influenced much by simply setting
+high values to the memory options.
+
+For more optimization hints take a look at the lwIP wiki.
+
+--- Zero-copy MACs
+
+To achieve zero-copy on transmit, the data passed to the raw API must
+remain unchanged until sent. Because the send- (or write-)functions return
+when the packets have been enqueued for sending, data must be kept stable
+after that, too.
+
+This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions
+must *not* be reused by the application unless their ref-count is 1.
+
+For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too,
+but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while
+PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).
+
+Also, data passed to tcp_write without the copy-flag must not be changed!
+
+Therefore, be careful which type of PBUF you use and if you copy TCP data
+or not!
diff --git a/core/lwip/doc/savannah.txt b/core/lwip/doc/savannah.txt
new file mode 100644
index 00000000..409905b1
--- /dev/null
+++ b/core/lwip/doc/savannah.txt
@@ -0,0 +1,135 @@
+Daily Use Guide for using Savannah for lwIP
+
+Table of Contents:
+
+1 - Obtaining lwIP from the CVS repository
+2 - Committers/developers CVS access using SSH (to be written)
+3 - Merging from DEVEL branch to main trunk (stable branch)
+4 - How to release lwIP
+
+
+
+1 Obtaining lwIP from the CVS repository
+----------------------------------------
+
+To perform an anonymous CVS checkout of the main trunk (this is where
+bug fixes and incremental enhancements occur), do this:
+
+cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip
+
+Or, obtain a stable branch (updated with bug fixes only) as follows:
+cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
+ -r STABLE-0_7 -d lwip-0.7 lwip
+
+Or, obtain a specific (fixed) release as follows:
+cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
+ -r STABLE-0_7_0 -d lwip-0.7.0 lwip
+
+3 Committers/developers CVS access using SSH
+--------------------------------------------
+
+The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
+As such, CVS commits to the server occur through a SSH tunnel for project members.
+To create a SSH2 key pair in UNIX-like environments, do this:
+
+ssh-keygen -t dsa
+
+Under Windows, a recommended SSH client is "PuTTY", freely available with good
+documentation and a graphic user interface. Use its key generator.
+
+Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
+a while so that Savannah can update its configuration (This can take minutes).
+
+Try to login using SSH:
+
+ssh -v your_login@cvs.sv.gnu.org
+
+If it tells you:
+
+Authenticating with public key "your_key_name"...
+Server refused to allocate pty
+
+then you could login; Savannah refuses to give you a shell - which is OK, as we
+are allowed to use SSH for CVS only. Now, you should be able to do this:
+
+export CVS_RSH=ssh
+cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip
+
+after which you can edit your local files with bug fixes or new features and
+commit them. Make sure you know what you are doing when using CVS to make
+changes on the repository. If in doubt, ask on the lwip-members mailing list.
+
+(If SSH asks about authenticity of the host, you can check the key
+ fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
+
+
+3 Merging from DEVEL branch to main trunk (stable)
+--------------------------------------------------
+
+Merging is a delicate process in CVS and requires the
+following disciplined steps in order to prevent conflicts
+in the future. Conflicts can be hard to solve!
+
+Merging from branch A to branch B requires that the A branch
+has a tag indicating the previous merger. This tag is called
+'merged_from_A_to_B'. After merging, the tag is moved in the
+A branch to remember this merger for future merge actions.
+
+IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
+REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
+MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
+
+Merge all changes in DEVEL since our last merge to main:
+
+In the working copy of the main trunk:
+cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
+
+(This will apply the changes between 'merged_from_DEVEL_to_main'
+and 'DEVEL' to your work set of files)
+
+We can now commit the merge result.
+cvs commit -R -m "Merged from DEVEL to main."
+
+If this worked out OK, we now move the tag in the DEVEL branch
+to this merge point, so we can use this point for future merges:
+
+cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
+
+4 How to release lwIP
+---------------------
+
+First, checkout a clean copy of the branch to be released. Tag this set with
+tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
+
+Login CVS using pserver authentication, then export a clean copy of the
+tagged tree. Export is similar to a checkout, except that the CVS metadata
+is not created locally.
+
+export CVS_RSH=ssh
+cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
+ -r STABLE-0_6_3 -d lwip-0.6.3 lwip
+
+Archive this directory using tar, gzip'd, bzip2'd and zip'd.
+
+tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
+tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
+zip -r lwip-0.6.3.zip lwip-0.6.3
+
+Now, sign the archives with a detached GPG binary signature as follows:
+
+gpg -b lwip-0.6.3.tar.gz
+gpg -b lwip-0.6.3.tar.bz2
+gpg -b lwip-0.6.3.zip
+
+Upload these files using anonymous FTP:
+ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
+
+ncftp>mput *0.6.3.*
+
+Additionally, you may post a news item on Savannah, like this:
+
+A new 0.6.3 release is now available here:
+http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
+
+You will have to submit this via the user News interface, then approve
+this via the Administrator News interface. \ No newline at end of file
diff --git a/core/lwip/doc/snmp_agent.txt b/core/lwip/doc/snmp_agent.txt
new file mode 100644
index 00000000..2653230f
--- /dev/null
+++ b/core/lwip/doc/snmp_agent.txt
@@ -0,0 +1,181 @@
+SNMPv1 agent for lwIP
+
+Author: Christiaan Simons
+
+This is a brief introduction how to use and configure the SNMP agent.
+Note the agent uses the raw-API UDP interface so you may also want to
+read rawapi.txt to gain a better understanding of the SNMP message handling.
+
+0 Agent Capabilities
+====================
+
+SNMPv1 per RFC1157
+ This is an old(er) standard but is still widely supported.
+ For SNMPv2c and v3 have a greater complexity and need many
+ more lines of code. IMHO this breaks the idea of "lightweight IP".
+
+ Note the S in SNMP stands for "Simple". Note that "Simple" is
+ relative. SNMP is simple compared to the complex ISO network
+ management protocols CMIP (Common Management Information Protocol)
+ and CMOT (CMip Over Tcp).
+
+MIB II per RFC1213
+ The standard lwIP stack management information base.
+ This is a required MIB, so this is always enabled.
+ When builing lwIP without TCP, the mib-2.tcp group is omitted.
+ The groups EGP, CMOT and transmission are disabled by default.
+
+ Most mib-2 objects are not writable except:
+ sysName, sysLocation, sysContact, snmpEnableAuthenTraps.
+ Writing to or changing the ARP and IP address and route
+ tables is not possible.
+
+ Note lwIP has a very limited notion of IP routing. It currently
+ doen't have a route table and doesn't have a notion of the U,G,H flags.
+ Instead lwIP uses the interface list with only one default interface
+ acting as a single gateway interface (G) for the default route.
+
+ The agent returns a "virtual table" with the default route 0.0.0.0
+ for the default interface and network routes (no H) for each
+ network interface in the netif_list.
+ All routes are considered to be up (U).
+
+Loading additional MIBs
+ MIBs can only be added in compile-time, not in run-time.
+ There is no MIB compiler thus additional MIBs must be hand coded.
+
+Large SNMP message support
+ The packet decoding and encoding routines are designed
+ to use pbuf-chains. Larger payloads than the minimum
+ SNMP requirement of 484 octets are supported if the
+ PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your
+ local requirement.
+
+1 Building the Agent
+====================
+
+First of all you'll need to add the following define
+to your local lwipopts.h:
+
+#define LWIP_SNMP 1
+
+and add the source files in lwip/src/core/snmp
+and some snmp headers in lwip/src/include/lwip to your makefile.
+
+Note you'll might need to adapt you network driver to update
+the mib2 variables for your interface.
+
+2 Running the Agent
+===================
+
+The following function calls must be made in your program to
+actually get the SNMP agent running.
+
+Before starting the agent you should supply pointers
+to non-volatile memory for sysContact, sysLocation,
+and snmpEnableAuthenTraps. You can do this by calling
+
+snmp_set_syscontact()
+snmp_set_syslocation()
+snmp_set_snmpenableauthentraps()
+
+Additionally you may want to set
+
+snmp_set_sysdescr()
+snmp_set_sysobjid() (if you have a private MIB)
+snmp_set_sysname()
+
+Also before starting the agent you need to setup
+one or more trap destinations using these calls:
+
+snmp_trap_dst_enable();
+snmp_trap_dst_ip_set();
+
+In the lwIP initialisation sequence call snmp_init() just after
+the call to udp_init().
+
+Exactly every 10 msec the SNMP uptime timestamp must be updated with
+snmp_inc_sysuptime(). You should call this from a timer interrupt
+or a timer signal handler depending on your runtime environment.
+
+An alternative way to update the SNMP uptime timestamp is to do a call like
+snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to
+a lower frequency). Another one is to not call snmp_inc_sysuptime() or
+snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
+This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
+snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
+when it's queried (any function which need "sysuptime" have to call
+snmp_get_sysuptime).
+
+
+3 Private MIBs
+==============
+
+If want to extend the agent with your own private MIB you'll need to
+add the following define to your local lwipopts.h:
+
+#define SNMP_PRIVATE_MIB 1
+
+You must provide the private_mib.h and associated files yourself.
+Note we don't have a "MIB compiler" that generates C source from a MIB,
+so you're required to do some serious coding if you enable this!
+
+Note the lwIP enterprise ID (26381) is assigned to the lwIP project,
+ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP
+MAINTAINERS!
+
+If you need to create your own private MIB you'll need
+to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html
+
+You can set it by passing a struct snmp_obj_id to the agent
+using snmp_set_sysobjid(&my_object_id), just before snmp_init().
+
+Note the object identifiers for thes MIB-2 and your private MIB
+tree must be kept in sorted ascending (lexicographical) order.
+This to ensure correct getnext operation.
+
+An example for a private MIB is part of the "minimal Unix" project:
+contrib/ports/unix/proj/minimal/lwip_prvmib.c
+
+The next chapter gives a more detailed description of the
+MIB-2 tree and the optional private MIB.
+
+4 The Gory Details
+==================
+
+4.0 Object identifiers and the MIB tree.
+
+We have three distinct parts for all object identifiers:
+
+The prefix
+ .iso.org.dod.internet
+
+the middle part
+ .mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress
+
+and the index part
+ .1.192.168.0.1
+
+Objects located above the .internet hierarchy aren't supported.
+Currently only the .mgmt sub-tree is available and
+when the SNMP_PRIVATE_MIB is enabled the .private tree
+becomes available too.
+
+Object identifiers from incoming requests are checked
+for a matching prefix, middle part and index part
+or are expanded(*) for GetNext requests with short
+or inexisting names in the request.
+(* we call this "expansion" but this also
+resembles the "auto-completion" operation)
+
+The middle part is usually located in ROM (const)
+to preserve precious RAM on small microcontrollers.
+However RAM location is possible for a dynamically
+changing private tree.
+
+The index part is handled by functions which in
+turn use dynamically allocated index trees from RAM.
+These trees are updated by e.g. the etharp code
+when new entries are made or removed form the ARP cache.
+
+/** @todo more gory details */
diff --git a/core/lwip/doc/sys_arch.txt b/core/lwip/doc/sys_arch.txt
new file mode 100644
index 00000000..4eb93078
--- /dev/null
+++ b/core/lwip/doc/sys_arch.txt
@@ -0,0 +1,216 @@
+sys_arch interface for lwIP 0.6++
+
+Author: Adam Dunkels
+
+The operating system emulation layer provides a common interface
+between the lwIP code and the underlying operating system kernel. The
+general idea is that porting lwIP to new architectures requires only
+small changes to a few header files and a new sys_arch
+implementation. It is also possible to do a sys_arch implementation
+that does not rely on any underlying operating system.
+
+The sys_arch provides semaphores and mailboxes to lwIP. For the full
+lwIP functionality, multiple threads support can be implemented in the
+sys_arch, but this is not required for the basic lwIP
+functionality. Previous versions of lwIP required the sys_arch to
+implement timer scheduling as well but as of lwIP 0.5 this is
+implemented in a higher layer.
+
+In addition to the source file providing the functionality of sys_arch,
+the OS emulation layer must provide several header files defining
+macros used throughout lwip. The files required and the macros they
+must define are listed below the sys_arch description.
+
+Semaphores can be either counting or binary - lwIP works with both
+kinds. Mailboxes are used for message passing and can be implemented
+either as a queue which allows multiple messages to be posted to a
+mailbox, or as a rendez-vous point where only one message can be
+posted at a time. lwIP works with both kinds, but the former type will
+be more efficient. A message in a mailbox is just a pointer, nothing
+more.
+
+Semaphores are represented by the type "sys_sem_t" which is typedef'd
+in the sys_arch.h file. Mailboxes are equivalently represented by the
+type "sys_mbox_t". lwIP does not place any restrictions on how
+sys_sem_t or sys_mbox_t are represented internally.
+
+The following functions must be implemented by the sys_arch:
+
+- void sys_init(void)
+
+ Is called to initialize the sys_arch layer.
+
+- sys_sem_t sys_sem_new(u8_t count)
+
+ Creates and returns a new semaphore. The "count" argument specifies
+ the initial state of the semaphore.
+
+- void sys_sem_free(sys_sem_t sem)
+
+ Deallocates a semaphore.
+
+- void sys_sem_signal(sys_sem_t sem)
+
+ Signals a semaphore.
+
+- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
+
+ Blocks the thread while waiting for the semaphore to be
+ signaled. If the "timeout" argument is non-zero, the thread should
+ only be blocked for the specified time (measured in
+ milliseconds). If the "timeout" argument is zero, the thread should be
+ blocked until the semaphore is signalled.
+
+ If the timeout argument is non-zero, the return value is the number of
+ milliseconds spent waiting for the semaphore to be signaled. If the
+ semaphore wasn't signaled within the specified time, the return value is
+ SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
+ (i.e., it was already signaled), the function may return zero.
+
+ Notice that lwIP implements a function with a similar name,
+ sys_sem_wait(), that uses the sys_arch_sem_wait() function.
+
+- sys_mbox_t sys_mbox_new(int size)
+
+ Creates an empty mailbox for maximum "size" elements. Elements stored
+ in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
+ in your lwipopts.h, or ignore this parameter in your implementation
+ and use a default size.
+
+- void sys_mbox_free(sys_mbox_t mbox)
+
+ Deallocates a mailbox. If there are messages still present in the
+ mailbox when the mailbox is deallocated, it is an indication of a
+ programming error in lwIP and the developer should be notified.
+
+- void sys_mbox_post(sys_mbox_t mbox, void *msg)
+
+ Posts the "msg" to the mailbox. This function have to block until
+ the "msg" is really posted.
+
+- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
+
+ Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
+ is full, else, ERR_OK if the "msg" is posted.
+
+- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
+
+ Blocks the thread until a message arrives in the mailbox, but does
+ not block the thread longer than "timeout" milliseconds (similar to
+ the sys_arch_sem_wait() function). If "timeout" is 0, the thread should
+ be blocked until a message arrives. The "msg" argument is a result
+ parameter that is set by the function (i.e., by doing "*msg =
+ ptr"). The "msg" parameter maybe NULL to indicate that the message
+ should be dropped.
+
+ The return values are the same as for the sys_arch_sem_wait() function:
+ Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
+ timeout.
+
+ Note that a function with a similar name, sys_mbox_fetch(), is
+ implemented by lwIP.
+
+- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
+
+ This is similar to sys_arch_mbox_fetch, however if a message is not
+ present in the mailbox, it immediately returns with the code
+ SYS_MBOX_EMPTY. On success 0 is returned.
+
+ To allow for efficient implementations, this can be defined as a
+ function-like macro in sys_arch.h instead of a normal function. For
+ example, a naive implementation could be:
+ #define sys_arch_mbox_tryfetch(mbox,msg) \
+ sys_arch_mbox_fetch(mbox,msg,1)
+ although this would introduce unnecessary delays.
+
+If threads are supported by the underlying operating system and if
+such functionality is needed in lwIP, the following function will have
+to be implemented as well:
+
+- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
+
+ Starts a new thread named "name" with priority "prio" that will begin its
+ execution in the function "thread()". The "arg" argument will be passed as an
+ argument to the thread() function. The stack size to used for this thread is
+ the "stacksize" parameter. The id of the new thread is returned. Both the id
+ and the priority are system dependent.
+
+- sys_prot_t sys_arch_protect(void)
+
+ This optional function does a "fast" critical region protection and returns
+ the previous protection level. This function is only called during very short
+ critical regions. An embedded system which supports ISR-based drivers might
+ want to implement this function by disabling interrupts. Task-based systems
+ might want to implement this by using a mutex or disabling tasking. This
+ function should support recursive calls from the same task or interrupt. In
+ other words, sys_arch_protect() could be called while already protected. In
+ that case the return value indicates that it is already protected.
+
+ sys_arch_protect() is only required if your port is supporting an operating
+ system.
+
+- void sys_arch_unprotect(sys_prot_t pval)
+
+ This optional function does a "fast" set of critical region protection to the
+ value specified by pval. See the documentation for sys_arch_protect() for
+ more information. This function is only required if your port is supporting
+ an operating system.
+
+Note:
+
+Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
+mem_malloc() you can run into a circular function call problem. In mem.c
+lwip_mem_init() tries to allcate a semaphore using mem_malloc, which of course
+can't be performed when sys_arch uses mem_malloc.
+
+-------------------------------------------------------------------------------
+Additional files required for the "OS support" emulation layer:
+-------------------------------------------------------------------------------
+
+cc.h - Architecture environment, some compiler specific, some
+ environment specific (probably should move env stuff
+ to sys_arch.h.)
+
+ Typedefs for the types used by lwip -
+ u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
+
+ Compiler hints for packing lwip's structures -
+ PACK_STRUCT_FIELD(x)
+ PACK_STRUCT_STRUCT
+ PACK_STRUCT_BEGIN
+ PACK_STRUCT_END
+
+ Platform specific diagnostic output -
+ LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
+ LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
+ Portability defines for printf formatters:
+ U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
+
+ "lightweight" synchronization mechanisms -
+ SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
+ SYS_ARCH_PROTECT(x) - enter protection mode.
+ SYS_ARCH_UNPROTECT(x) - leave protection mode.
+
+ If the compiler does not provide memset() this file must include a
+ definition of it, or include a file which defines it.
+
+ This file must either include a system-local <errno.h> which defines
+ the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
+ to make lwip/arch.h define the codes which are used throughout.
+
+
+perf.h - Architecture specific performance measurement.
+ Measurement calls made throughout lwip, these can be defined to nothing.
+ PERF_START - start measuring something.
+ PERF_STOP(x) - stop measuring something, and record the result.
+
+sys_arch.h - Tied to sys_arch.c
+
+ Arch dependent types for the following objects:
+ sys_sem_t, sys_mbox_t, sys_thread_t,
+ And, optionally:
+ sys_prot_t
+
+ Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
+ SYS_MBOX_NULL NULL
+ SYS_SEM_NULL NULL
diff --git a/core/lwip/src/FILES b/core/lwip/src/FILES
new file mode 100644
index 00000000..952aeabb
--- /dev/null
+++ b/core/lwip/src/FILES
@@ -0,0 +1,13 @@
+api/ - The code for the high-level wrapper API. Not needed if
+ you use the lowel-level call-back/raw API.
+
+core/ - The core of the TPC/IP stack; protocol implementations,
+ memory and buffer management, and the low-level raw API.
+
+include/ - lwIP include files.
+
+netif/ - Generic network interface device drivers are kept here,
+ as well as the ARP module.
+
+For more information on the various subdirectories, check the FILES
+file in each directory.
diff --git a/core/lwip/src/api/api_lib.c b/core/lwip/src/api/api_lib.c
new file mode 100644
index 00000000..b1a9e525
--- /dev/null
+++ b/core/lwip/src/api/api_lib.c
@@ -0,0 +1,740 @@
+/**
+ * @file
+ * Sequential API External module
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/* This is the part of the API that is linked with
+ the application */
+
+#include "lwip/opt.h"
+
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/api.h"
+#include "lwip/tcpip.h"
+#include "lwip/memp.h"
+
+#include "lwip/ip.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+
+#include <string.h>
+
+/**
+ * Create a new netconn (of a specific type) that has a callback function.
+ * The corresponding pcb is also created.
+ *
+ * @param t the type of 'connection' to create (@see enum netconn_type)
+ * @param proto the IP protocol for RAW IP pcbs
+ * @param callback a function to call on status changes (RX available, TX'ed)
+ * @return a newly allocated struct netconn or
+ * NULL on memory error
+ */
+struct netconn*
+netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
+{
+ struct netconn *conn;
+ struct api_msg msg;
+
+ conn = netconn_alloc(t, callback);
+ if (conn != NULL) {
+ msg.function = do_newconn;
+ msg.msg.msg.n.proto = proto;
+ msg.msg.conn = conn;
+ if (TCPIP_APIMSG(&msg) != ERR_OK) {
+ LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
+ LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
+ LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
+#if LWIP_TCP
+ LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
+#endif /* LWIP_TCP */
+ sys_sem_free(&conn->op_completed);
+ sys_mbox_free(&conn->recvmbox);
+ memp_free(MEMP_NETCONN, conn);
+ return NULL;
+ }
+ }
+ return conn;
+}
+
+/**
+ * Close a netconn 'connection' and free its resources.
+ * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
+ * after this returns.
+ *
+ * @param conn the netconn to delete
+ * @return ERR_OK if the connection was deleted
+ */
+err_t
+netconn_delete(struct netconn *conn)
+{
+ struct api_msg msg;
+
+ /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
+ if (conn == NULL) {
+ return ERR_OK;
+ }
+
+ msg.function = do_delconn;
+ msg.msg.conn = conn;
+ tcpip_apimsg(&msg);
+
+ netconn_free(conn);
+
+ /* don't care for return value of do_delconn since it only calls void functions */
+
+ return ERR_OK;
+}
+
+/**
+ * Get the local or remote IP address and port of a netconn.
+ * For RAW netconns, this returns the protocol instead of a port!
+ *
+ * @param conn the netconn to query
+ * @param addr a pointer to which to save the IP address
+ * @param port a pointer to which to save the port (or protocol for RAW)
+ * @param local 1 to get the local IP address, 0 to get the remote one
+ * @return ERR_CONN for invalid connections
+ * ERR_OK if the information was retrieved
+ */
+err_t
+netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
+
+ msg.function = do_getaddr;
+ msg.msg.conn = conn;
+ msg.msg.msg.ad.ipaddr = addr;
+ msg.msg.msg.ad.port = port;
+ msg.msg.msg.ad.local = local;
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Bind a netconn to a specific local IP address and port.
+ * Binding one netconn twice might not always be checked correctly!
+ *
+ * @param conn the netconn to bind
+ * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
+ * to bind to all addresses)
+ * @param port the local port to bind the netconn to (not used for RAW)
+ * @return ERR_OK if bound, any other err_t on failure
+ */
+err_t
+netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_bind;
+ msg.msg.conn = conn;
+ msg.msg.msg.bc.ipaddr = addr;
+ msg.msg.msg.bc.port = port;
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Connect a netconn to a specific remote IP address and port.
+ *
+ * @param conn the netconn to connect
+ * @param addr the remote IP address to connect to
+ * @param port the remote port to connect to (no used for RAW)
+ * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
+ */
+err_t
+netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_connect;
+ msg.msg.conn = conn;
+ msg.msg.msg.bc.ipaddr = addr;
+ msg.msg.msg.bc.port = port;
+ /* This is the only function which need to not block tcpip_thread */
+ err = tcpip_apimsg(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Disconnect a netconn from its current peer (only valid for UDP netconns).
+ *
+ * @param conn the netconn to disconnect
+ * @return TODO: return value is not set here...
+ */
+err_t
+netconn_disconnect(struct netconn *conn)
+{
+ struct api_msg msg;
+ err_t err;
+
+ LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_disconnect;
+ msg.msg.conn = conn;
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+}
+
+/**
+ * Set a TCP netconn into listen mode
+ *
+ * @param conn the tcp netconn to set to listen mode
+ * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
+ * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
+ * don't return any error (yet?))
+ */
+err_t
+netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
+{
+#if LWIP_TCP
+ struct api_msg msg;
+ err_t err;
+
+ /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
+ LWIP_UNUSED_ARG(backlog);
+
+ LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
+
+ msg.function = do_listen;
+ msg.msg.conn = conn;
+#if TCP_LISTEN_BACKLOG
+ msg.msg.msg.lb.backlog = backlog;
+#endif /* TCP_LISTEN_BACKLOG */
+ err = TCPIP_APIMSG(&msg);
+
+ NETCONN_SET_SAFE_ERR(conn, err);
+ return err;
+#else /* LWIP_TCP */
+ LWIP_UNUSED_ARG(conn);
+ LWIP_UNUSED_ARG(backlog);
+ return ERR_ARG;
+#endif /* LWIP_TCP */
+}
+
+/**
+ * Accept a new connection on a TCP listening netconn.
+ *
+ * @param conn the TCP listen netconn
+ * @param new_conn pointer where the new connection is stored
+ * @return ERR_OK if a new connection has been received or an error
+ * code otherwise
+ */
+err_t
+netconn_accept(struct netconn *conn, struct netconn **new_conn)
+{
+#if LWIP_TCP
+ struct netconn *newconn;
+ err_t err;
+#if TCP_LISTEN_BACKLOG
+ struct api_msg msg;
+#endif /* TCP_LISTEN_BACKLOG */
+
+ LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
+ *new_conn = NULL;
+ LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
+ LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
+
+ err = conn->last_err;
+ if (ERR_IS_FATAL(err)) {
+ /* don't recv on fatal errors: this might block the application task
+ waiting on acceptmbox forever! */
+ return err;
+ }
+
+#if LWIP_SO_RCVTIMEO
+ if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
+ NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
+ return ERR_TIMEOUT;
+ }
+#else
+ sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
+#endif /* LWIP_SO_RCVTIMEO*/
+ /* Register event with callback */
+ API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
+
+ if (newconn == NULL) {
+ /* connection has been aborted */
+ NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
+ return ERR_ABRT;
+ }
+#if TCP_LISTEN_BACKLOG
+ /* Let the stack know that we have accepted the connection. */
+ msg.function = do_recv;
+ msg.msg.conn = conn;
+ /* don't care for the return value of do_recv */
+ TCPIP_APIMSG(&msg);
+#endif /* TCP_LISTEN_BACKLOG */
+
+ *new_conn = newconn;
+ /* don't set conn->last_err: it's only ERR_OK, anyway */
+ return ERR_OK;
+#else /* LWIP_TCP */
+ LWIP_UNUSED_ARG(co