svn commit: r245486 - in user/sbruno/pxestuff/sys/boot/i386: . btx/btx btx/lib libi386 pxehttp

Sean Bruno sbruno at FreeBSD.org
Wed Jan 16 01:49:09 UTC 2013


Author: sbruno
Date: Wed Jan 16 01:49:07 2013
New Revision: 245486
URL: http://svnweb.freebsd.org/changeset/base/245486

Log:
  First day of work on pxe_http restoral, merge in some janky assembly that
  better get some serious reviews from people whom are way smarter than I.

Added:
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/Makefile
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/README
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/httpfs.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/httpfs.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_arp.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_arp.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_await.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_await.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_buffer.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_buffer.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_connection.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_connection.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_core.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_core.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_dhcp.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_dhcp.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_dns.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_dns.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_filter.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_filter.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_http.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_http.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_httpls.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_httpls.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_icmp.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_icmp.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_ip.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_ip.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_ip6.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_isr.S
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_isr.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_mem.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_mem.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_segment.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_segment.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_sock.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_sock.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_tcp.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_tcp.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_udp.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/pxe_udp.h
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/socketfs.c
  user/sbruno/pxestuff/sys/boot/i386/pxehttp/socketfs.h
Modified:
  user/sbruno/pxestuff/sys/boot/i386/Makefile
  user/sbruno/pxestuff/sys/boot/i386/btx/btx/btx.S
  user/sbruno/pxestuff/sys/boot/i386/btx/lib/btxsys.s
  user/sbruno/pxestuff/sys/boot/i386/btx/lib/btxv86.h
  user/sbruno/pxestuff/sys/boot/i386/libi386/Makefile

Modified: user/sbruno/pxestuff/sys/boot/i386/Makefile
==============================================================================
--- user/sbruno/pxestuff/sys/boot/i386/Makefile	Wed Jan 16 01:30:46 2013	(r245485)
+++ user/sbruno/pxestuff/sys/boot/i386/Makefile	Wed Jan 16 01:49:07 2013	(r245486)
@@ -3,7 +3,7 @@
 .include <bsd.own.mk>
 
 SUBDIR=		mbr pmbr boot0 boot0sio btx boot2 cdboot gptboot kgzldr \
-		libi386 libfirewire loader
+		libi386 libfirewire pxehttp loader
 
 # special boot programs, 'self-extracting boot2+loader'
 SUBDIR+=	pxeldr

Modified: user/sbruno/pxestuff/sys/boot/i386/btx/btx/btx.S
==============================================================================
--- user/sbruno/pxestuff/sys/boot/i386/btx/btx/btx.S	Wed Jan 16 01:30:46 2013	(r245485)
+++ user/sbruno/pxestuff/sys/boot/i386/btx/btx/btx.S	Wed Jan 16 01:49:07 2013	(r245486)
@@ -52,7 +52,8 @@
 		.set SEL_RDATA,0x20		# Real mode data
 		.set SEL_UCODE,0x28|3		# User code
 		.set SEL_UDATA,0x30|3		# User data
-		.set SEL_TSS,0x38		# TSS
+		.set SEL_TSS,0x38				# TSS
+		.set SEL_CALLGATE,0x40	# super2user callgate
 /*
  * Task state segment fields.
  */
@@ -62,8 +63,9 @@
 /*
  * System calls.
  */
-		.set SYS_EXIT,0x0		# Exit
-		.set SYS_EXEC,0x1		# Exec
+		.set SYS_EXIT,0x0					# Exit
+		.set SYS_EXEC,0x1					# Exec
+		.set SYS_ISR_INSTALL,0x2	# ISR_install
 /*
  * Fields in V86 interface structure.
  */
@@ -366,7 +368,6 @@ except.2:	pushl 0x50(%esp,1)		# Set ESP
 		popl %es			#  data
 		movl %esp,%ebx			# Stack frame
 		movl $dmpfmt,%esi		# Dump format string
-		movl $MEM_BUF,%edi		# Buffer
 		pushl %edi			# Dump to
 		call dump			#  buffer
 		popl %esi			#  and
@@ -690,7 +691,9 @@ rret_tramp.3:	popl %es			# Restore
 /*
  * System Call.
  */
-intx30: 	cmpl $SYS_EXEC,%eax		# Exec system call?
+intx30:     cmpl $SYS_ISR_INSTALL, %eax # is isr_install?
+		je intx30.2         #  yes
+		cmpl $SYS_EXEC,%eax     # Exec system call?
 		jne intx30.1			# No
 		pushl %ss			# Set up
 		popl %es			#  all
@@ -708,6 +711,74 @@ intx30: 	cmpl $SYS_EXEC,%eax		# Exec sys
 intx30.1:	orb $0x1,%ss:btx_hdr+0x7	# Flag reboot
 		jmp exit			# Exit
 /*
+ *	Here we need to modify IDT in such way, that at interrupt handle
+ *  will be run isr_trump, which role is to run provided function
+ *  in user space.
+ */
+intx30.2:
+		cli
+		pushl %edi
+		pushl %ebx
+		pushw %ds
+		pushw %dx
+
+		pushl %ss			# Set up
+		popl %ds			#  registers
+		
+
+ 		movl $MEM_USR,%ebx		# User base address
+		addl 0x18(%esp,1),%ebx		# getting user stack head
+		addl $0x04, %ebx		#  first parameter
+
+		movl (%ebx), %eax
+		movw 0x2(%ebx), %dx
+		xchgw %dx, %bx
+
+/*
+ * updating call gate
+ */
+		movl $callgate, %edi
+		movw %ax, (%edi)		# +0: store offset 00..15
+		shr $0x10 ,%eax			# getting high word
+		movw %ax, 0x06(%edi)		# +6: handler offset 16..31
+/*
+ * installing handler
+ */
+/*
+ *  NOTE: it seems nothing else must be done
+ */
+		popw %dx
+		popw %ds
+		popl %ebx		
+		popl %edi
+		sti	
+		iret				# return from syscall
+
+user_isr_call:
+/*
+ * NOTE: isr must use lret to return and restore SS, ESP, CS, EIP.
+*/
+		pushl %ds			# saving ds
+		pushl %edi
+		movl $SEL_SDATA, %eax		#
+		movl %eax, %ds			
+						
+		movl $callgate, %edi
+		movw (%edi), %ax
+		popl %edi		
+
+		cmpw $0x0000, %ax
+		je isr_ret
+		
+		lcall $SEL_CALLGATE,$0x00000000 # far call via callgate selector
+			# offset is ignored
+isr_ret:
+		
+
+		popl %ds
+
+		iret				# return from interrupt handler
+/*
  * Dump structure [EBX] to [EDI], using format string [ESI].
  */
 dump.0: 	stosb				# Save char
@@ -1000,6 +1071,7 @@ gdt:		.word 0x0,0x0,0x0,0x0		# Null entr
 		.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
 		.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
 tss_desc:	.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
+callgate:	.word 0x0, SEL_UCODE,0xec00,0x0 # SEL_CALLGATE
 gdt.1:
 /*
  * Pseudo-descriptors.

Modified: user/sbruno/pxestuff/sys/boot/i386/btx/lib/btxsys.s
==============================================================================
--- user/sbruno/pxestuff/sys/boot/i386/btx/lib/btxsys.s	Wed Jan 16 01:30:46 2013	(r245485)
+++ user/sbruno/pxestuff/sys/boot/i386/btx/lib/btxsys.s	Wed Jan 16 01:49:07 2013	(r245486)
@@ -24,6 +24,7 @@
 #
 		.global __exit
 		.global __exec
+		.global __isr_install
 #
 # Constants.
 #
@@ -38,3 +39,8 @@ __exit: 	xorl %eax,%eax			# BTX system
 #
 __exec: 	movl $0x1,%eax			# BTX system
 		int $INT_SYS			#  call 0x1
+#
+# System call: isr_install
+#
+__isr_install: 	movl $0x2,%eax			# BTX system
+		int $INT_SYS			#  call 0x2

Modified: user/sbruno/pxestuff/sys/boot/i386/btx/lib/btxv86.h
==============================================================================
--- user/sbruno/pxestuff/sys/boot/i386/btx/lib/btxv86.h	Wed Jan 16 01:30:46 2013	(r245485)
+++ user/sbruno/pxestuff/sys/boot/i386/btx/lib/btxv86.h	Wed Jan 16 01:49:07 2013	(r245486)
@@ -64,4 +64,9 @@ extern u_int32_t	__args;
 void __exit(int) __attribute__((__noreturn__));
 void __exec(caddr_t, ...);
 
+/*
+ *  Installs interrupt handler function for interrupt int_num.
+ *  caddr_t - in userspace.
+ */
+void __isr_install(caddr_t isr, uint16_t int_num);
 #endif /* !_BTXV86_H_ */

Modified: user/sbruno/pxestuff/sys/boot/i386/libi386/Makefile
==============================================================================
--- user/sbruno/pxestuff/sys/boot/i386/libi386/Makefile	Wed Jan 16 01:30:46 2013	(r245485)
+++ user/sbruno/pxestuff/sys/boot/i386/libi386/Makefile	Wed Jan 16 01:49:07 2013	(r245486)
@@ -48,7 +48,7 @@ CFLAGS+= -Dalloca=__builtin_alloca
 CFLAGS+=	-I${.CURDIR}/../../common -I${.CURDIR}/../common \
 		-I${.CURDIR}/../btx/lib \
 		-I${.CURDIR}/../../../contrib/dev/acpica/include \
-		-I${.CURDIR}/../../.. -I.
+		-I${.CURDIR}/../../.. -I. -I${.CURDIR}/../pxe_http/
 # the location of libstand
 CFLAGS+=	-I${.CURDIR}/../../../../lib/libstand/
 

Added: user/sbruno/pxestuff/sys/boot/i386/pxehttp/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/sbruno/pxestuff/sys/boot/i386/pxehttp/Makefile	Wed Jan 16 01:49:07 2013	(r245486)
@@ -0,0 +1,50 @@
+# pxe_http project
+#
+LIB=		pxe_http
+INTERNALLIB=
+
+SRCS=	pxe_isr.S pxe_mem.c pxe_buffer.c pxe_await.c pxe_arp.c pxe_ip.c \
+	pxe_core.c pxe_icmp.c pxe_udp.c pxe_filter.c pxe_dns.c		\
+	pxe_dhcp.c pxe_segment.c pxe_tcp.c pxe_sock.c 			\
+	pxe_connection.c pxe_http.c pxe_httpls.c httpfs.c
+
+CFLAGS+=	-I${.CURDIR}/../../common -I${.CURDIR}/../btx/lib \
+		-I${.CURDIR}/../../../contrib/dev/acpica \
+		-I${.CURDIR}/../../.. -I. -I$(.CURDIR)/.. -I${.CURDIR}/../libi386/
+# the location of libstand
+CFLAGS+=	-I${.CURDIR}/../../../../lib/libstand/
+
+#debug flag
+#CFLAGS+=	-DPXE_DEBUG
+#CFLAGS+=	-DPXE_DEBUG_HELL
+
+# core module debug
+#CFLAGS+=	-DPXE_CORE_DEBUG_HELL
+#CFLAGS+=	-DPXE_CORE_DEBUG
+# TCP module debug 
+#CFLAGS+=	-DPXE_TCP_DEBUG
+#CFLAGS+=	-DPXE_TCP_DEBUG_HELL
+# IP module debug
+#CFLAGS+=	-DPXE_IP_DEBUG
+#CFLAGS+=	-DPXE_IP_DEBUG_HELL
+# ARP module debug
+#CFLAGS+=	-DPXE_ARP_DEBUG
+#CFLAGS+=	-DPXE_ARP_DEBUG_HELL
+# httpfs module
+#CFLAGS+=	-DPXE_HTTP_DEBUG
+#CFLAGS+=	-DPXE_HTTP_DEBUG_HELL
+
+# define to get more PXE related code and testing functions
+#CFLAGS+=	-DPXE_MORE
+
+# define to get some speed up by bigger requests
+CFLAGS+=	-DPXE_HTTPFS_CACHING
+
+# define to send packets freqently to speed up connection
+#CFLAGS+=	-DPXE_TCP_AGRESSIVE
+
+# define to automatically choose non keep-alive method of
+# working, if keep-alive is not supported by server
+CFLAGS+=	-DPXE_HTTP_AUTO_KEEPALIVE
+
+.include <bsd.lib.mk>

Added: user/sbruno/pxestuff/sys/boot/i386/pxehttp/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/sbruno/pxestuff/sys/boot/i386/pxehttp/README	Wed Jan 16 01:49:07 2013	(r245486)
@@ -0,0 +1,1256 @@
+Contents
+----------
+
+1. Introduction
+
+	1.2. Setting up
+
+		1.2.1. DHCP configuration
+		1.2.2. TFTP configuration
+		1.2.3. Web-server configuration
+		1.2.4. loader.rc configuratuion
+
+2. Project organisation
+
+	2.1. Code modules
+	2.2. Naming conventions
+	2.3. Understanding logical structure of code
+
+3. API usage
+
+	3.1. Base information
+	3.2. PXE sockets API overview
+
+		3.2.1. PXE API socket details
+
+	3.3. Quick Reference to API, available for user code
+
+		3.3.1. pxe_arp module
+		3.3.2. pxe_await module
+		3.3.3. pxe_buffer module
+		3.3.4. pxe_connection module
+		3.3.5. pxe_core module
+		3.3.6. pxe_dhcp module
+		3.3.7. pxe_dns module
+		3.3.8. pxe_filter module
+		3.3.9. pxe_http module
+		3.3.10. httpfs module
+		3.3.11. pxe_icmp module
+		3.3.12. pxe_ip module
+		3.3.13. pxe_isr module
+		3.3.14. pxe_mem module
+		3.3.15. pxe_sock module
+		3.3.16. pxe_segment module
+		3.3.17. pxe_tcp module
+		3.3.18. pxe_udp module
+
+4. Debugging, testing and tuning pxe_http library.
+
+	4.1. Using 'pxe' loader's command
+	4.2. Defining debug macroses
+	4.3. Tuning
+	4.4. NFS loading with pxe_http
+
+1. Introduction 
+----------------
+
+		pxe_http library is user space implementation of simplified
+	TCP/IP4 stack with support of sockets. Socket implementation is similar
+	to common sockets, but differs, so I call this variant of sockets -
+	"PXE sockets"
+
+		features (read: simpliest ever implementation of):
+			* supports TCP/UDP PXE sockets
+			* DHCP client
+			* DNS client
+			* http based filesystem
+			* ICMP echo
+
+1.1. Requirements
+------------------
+
+			To use pxeboot with extensions from pxe_http library
+		you need:
+		* DHCP server
+			- any DHCP server with support of some options
+			  (see below).  In example of configuration files
+			  ISC DHCP v.3.0.5 was used.
+		* TFTP server
+		* Web server - I've used Apache 1.3.34
+
+
+1.2. Setting it up
+-------------------
+
+		In most cases, it's the same as for usual pxeboot. Main
+	difference is in configuration file of DHCP server and in usage of
+	Web-server.
+
+
+1.2.1. DHCP configuration
+-------------------------
+
+		Here is example of configuration:
+
+		# /etc/dhcpd.conf example
+		#
+		ddns-update-style none;
+		server-name "DHCPserver";
+		server-identifier 192.168.0.4;
+		default-lease-time 7200;
+		max-lease-time 7200;
+	
+		#
+		# significant options for correct working of pxeboot
+		#
+
+		# your LAN subnet mask
+		option subnet-mask 255.255.255.0;
+
+		# default gateway to use
+		option routers 192.168.0.1;
+
+		# name of file to download via TFTP
+		filename "pxeboot";
+
+		# name server, used for resolving of domain names
+		option domain-name-servers 192.168.0.1;
+
+		# ip address of web server
+		option www-server 192.168.0.2;
+
+		# path, where nessesary files are stored on web server
+		option root-path "th.lan:/path/to/root";
+
+		subnet 192.168.0.0 netmask 255.255.255.0 {
+        		next-server 192.168.0.4;
+	        	range 192.168.0.10 192.168.0.20;
+		}
+        	
+		/*  end of example */
+
+	NOTES:
+		1. www-server option is used only if root-path is absent in
+		   DHCP reply. In that case assumed, that /boot directory is
+		   placed in DocumentRoot of web-server.
+		2. format of root-path has such format: "server:/path". It's
+		   possible use both IP's and domain names for server. /path is
+		   relative to DocumentRoot of web-server. In example above
+		   files are stored at /usr/local/www/data/path/to/root,
+		   assuming that /usr/local/www/data - is DocumentRoot.
+		3. DHCP options are not greater then 255 bytes. So, root-path
+		   must satisfy this requirement.
+
+
+1.2.2. TFTP configuration
+--------------------------
+
+		Same as usually. pxe_http doesn't directly use this protocol.
+
+
+1.2.3. Web-server configuration
+--------------------------------
+
+		Just copy all from "/boot" directory to
+	/DocumentRoot/path/to/root.
+	
+	NOTES:
+		1. Need to be sure, that partial downloading and keep-alive
+		   connections are supported by server. e.g. for Apache 1.x,
+		   check this options:
+
+			KeepAlive On
+			MaxKeepAliveRequests 10		# well, choose best for
+							# server
+			KeepAliveTimeout 15		# more then 2 seconds
+							# is good enough
+							
+		1.1 Non keep-alive connections supported if macro 
+		    PXE_HTTP_AUTO_KEEPALIVE defined. In this case, non keep-alive
+		    connections will be used if keep-alive are unavailable. 
+
+		2. loader checks gzipped versions of files first, it's good
+		   idea to compress every needed file. e.g.
+				beastie.4th.gz
+				device.hints
+				frames.4th.gz
+				loader.4th.gz
+				loader.conf
+				loader.help.gz
+				loader.rc
+				mfsroot.gz
+				screen.4th.gz
+				support.4th.gz
+				/kernel/kernel.gz
+
+1.2.4. loader.rc configuratuion
+--------------------------------
+
+		HTTP downloading of kernel is not all need to startup system
+	correctly. The main question is where will be root filesystem after
+	booting of kernel. The simpliest way - is to use RAM drive with
+	installation tools or ready to work system.
+		Here is example of changes to loader.rc, that instructs loader
+	to download RAM-drive image (in this example, common mfsroot.gz found
+	in boot.flp floppy image file)
+
+
+	\ Includes additional commands
+	include /boot/loader.4th
+
+	\ Reads and processes loader.conf variables
+	start
+
+	\ Tests for password -- executes autoboot first if a password was defined
+	check-password
+
+	\ Load in the boot menu
+	include /boot/beastie.4th
+
+	\ pxe_http changes:
+	echo "loading RAM-drive image"
+	load -t mfs_root /boot/mfsroot
+	set vfs.root.mountfrom="ufs:/dev/md0c"
+	\
+
+	\ Start the boot menu
+	beastie-start
+
+	/* end of example */
+
+		Of course, it's possible to set any other filesystem to work
+	as root, e,g, NFS and not use RAM drive.
+		
+2. Project organisation
+------------------------
+
+2.1. Code modules
+------------------
+
+	All project code is divided into following modules:
+		pxe_arp        - ARP protocol				(3.3.1)
+		pxe_await      - provides functions for awaiting	(3.3.2)
+		pxe_buffer     - implements cyclic buffers		(3.3.3)
+		pxe_connection - TCP connection related functions	(3.3.4)
+		pxe_core       - provides calls to PXE API		(3.3.5)
+		pxe_dhcp       - DHCP client				(3.3.6)
+		pxe_dns        - DNS client				(3.3.7)
+		pxe_filter     - incoming packet filters		(3.3.8)
+		pxe_http       - HTTP related functions			(3.3.9)
+		httpfs         - http based file system			(3.3.10)
+		pxe_icmp       - ICMP protocol				(3.3.11)
+		pxe_ip         - IP protocol				(3.3.12)
+		pxe_isr        - assembler side support for PXE API
+				 calling				(3.3.13)
+		pxe_mem        - memory work routines			(3.3.14)
+		pxe_sock       - simple sockets				(3.3.15)
+		pxe_segment    - TCP segments				(3.3.16)
+		pxe_tcp        - TCP protocol				(3.3.17)
+		pxe_udp        - UDP protocol				(3.3.18)
+
+2.2. Naming conventions
+------------------------
+
+		Most of functions, that may be called directly by user API uses
+	pxe_ prefix.
+		Functions related to some module have subprefix of this module,
+	e.g. pxe_dhcp_query() - function related to DHCP module.
+		All structures, that are used have typedef equivalent with
+	naming in upper case. e.g. struct pxe_ipaddr has equivalent PXE_IPADDR.
+	This is done to have similar to existing pxe.h declarations from libi386.
+
+
+2.3. Understanding logical structure of code
+---------------------------------------------
+
+		Logicallly all modules may be divided to parts.
+
+	        Part 1: PXE API related modules (pxe_isr, pxe_core)
+		Part 2: base protocols related (pxe_ip, pxe_udp)
+		Part 3: sockets related (pxe_sock)
+		Part 4: other protocols (pxe_dns, pxe_dhcp)
+		Part 5: utility (pxe_mem, pxe_buffer)
+
+		Some modules may be used independently, other depend on some
+	lower level modules.
+
+		In run-time, many calls to sockets functions start packet
+	recieving or packet sending functions. Sending is more simplier and may
+	be assumed in many cases just as wrappers to PXE API. But receiving is
+	a little bit more complicated. Receiving functions start
+	pxe_core_recv_packets()	function in cycle to get packets.
+		After receiving of packet, it's handling depends on it's type:
+	ARP, IP or other. ARP packets directly provided to handler
+	pxe_arp_protocol(), IP packets are provided to registered handler of IP
+	stack protocol, other packets are ignored.
+		Registration of handler (except ARP) is performed during
+	initialisation time of module with usage of pxe_core_register() function,
+	which register handler for IP stack protocol number.
+		So, packet is provided to handler, but it may be fragmented,
+	thus before processing it must be recieved completely. But in some cases
+	packet may be not interesting for protocol (unexpected packet, dublicated
+	or something else) and it's possible to determiny if this packet useful
+	just by examining of packet header.
+		If packet is fragmented - it firstly provided to handler with
+	flag PXE_CORE_FRAG. Handler returns appropriate value if is interested in
+	whole packet, packet is read completely from input queue of fragments and
+	provided again with flag PXE_CORE_HANDLE. Otherwise packet is dropped
+	in core by reading of all it's fragments from incoming queue.
+		Packet structure provides just buffer with received packet and
+	size of packet. All pxe_core module send/recieve functions work with
+	PXE_PACKET structure.
+		TCP and UDP protocols are checking filters in theirs handlers.
+	This helps to filter out packets that are not interesting for protocol
+	(e.g. to port that is not listening)
+		Socket and filter structures are separated. Socket provides
+	buffers for incoming and outcoming data. Filters may be used without
+	sockets, e.g. for TCP connections in TIME_WAIT state. For active
+	connection filter is used to determiny in which receiving buffer (in
+	which socket) must be placed incoming data.
+
+
+3. API usage
+-------------
+
+		Here much attention paid to sockets, other pxe_http API
+	may be used less frequently.
+
+3.1. Base information
+-----------------------
+
+		User code must perform initialisation of pxe_core module (which
+	is performed currently in loader during pxe_enable() call). After this
+	sockets related functions become available.
+
+	pxe_core_init() performs initialisation of pxe_core module and starts
+	initialisation routines of other modules. It inits TCP, UDP, ARP and
+	etc modules, however in most of cases it's possible skip theirs
+	initialisation if module's functions are unused.
+		Work is finished by pxe_core_shutdown() function.
+
+
+3.2. PXE sockets API overview
+-------------------------------
+
+		PXE sockets API differs from common sockets. It's more simplier
+	and has some limitations due user space implementations. All socket
+	related functions are declared in pxe_sock.h header
+
+		Socket is created by pxe_socket() call. After usage socket must
+	be closed by pxe_close() call. Result of pxe_socket() is integer
+	descriptor associated with socket. After creating socket is unbinded
+	and not connected.
+		pxe_sendto(), pxe_connect(), pxe_bind() functions performs
+	binding and connecting. After successful calling of one of them - socket
+	is in active state. It's possible to perform reading and sending from/to
+	socket. Cause socket API may use buffers to optimize packet sending
+	process, user code must call pxe_flush() functions to be sure, that
+	data is really processed to sending module.
+		While receiving need to keep in memory, that if UDP datagram is
+	not readed completely by one call of pxe_recv() in this implementation
+	rest of datagram is omited and lost for user code.
+		All incoming and outcoming data is written to socket buffers,
+	that have default sizes 16Kb and 4Kb. If buffers are full, next calls
+	related to writing or reading data will fail.
+
+
+3.2.1. PXE API socket details
+------------------------------
+
+	/* Here is simple example of API usage. */
+
+	int socket = pxe_socket();
+	/* if result is not -1, then socket variable contains value,
+	 * assosiated with socket structure. Call differs from common sockets,
+	 * there are no domain, type and protocol parameters.
+	 * Cause domain is always AF_INET now. others are use in pxe_connect()
+	 * call.
+	 */
+	
+	int result = pxe_connect(socket, &hh->addr, 80, PXE_TCP_PROTOCOL);
+	/*  This call creates filter, associates it with socket and establishes
+	 * communication if needed.
+	 * Parameters are socket, remote ip address (PXE_IPADDR), remote port
+	 * and one of PXE_UDP_PROTOCOL and PXE_TCP_PROTOCOL protocols.
+	 */
+	
+	if (result == -1) {
+		pxe_close(socket);
+		/* any socket must be closed, even if it was not really used
+		 * or conencted. pxe_close() call releases used internal
+		 * structures. After this call any other operations with
+		 * 'socket' descriptor are invalid. 
+		 */
+		return (0);
+	}
+
+	/* pxe_send() function sends data to socket. As usual, there is no
+	 * guarantee, that whole buffer is transmited. And actually for TCP
+	 * protocol, this call just places data to buffer. User code have no
+	 * knowledge if data is really sent to network. if current segment is
+	 * not fullly used, data may stay in buffer infinitely.
+	 */	
+	if (len != pxe_send(socket, hh->buf, len)) {
+		/* failed to send data, at least whole buffer */
+		pxe_close(socket);
+		return (0);
+	}
+
+	/* if user code need guarantee, that data is sent to remote host, it
+	 * must call pxe_flush(). It forces sending of any data, that must be
+	 * sent.
+	 */
+	if (pxe_flush(socket) == -1) {
+		/* failed to flush socket */
+		pxe_close(socket);
+		return (0);
+	}
+
+	/* perform reading cycle */
+
+	while (count < maxsize) {
+		/* pxe_recv() is similar to recv() call for common sockets,
+		 * but have no flags parameter
+		 */
+		result = pxe_recv(socket, &data[count], maxsize - count);
+		
+		if (result == -1) {	/* failed to recv */
+			break;
+		}
+		
+		if (result == 0)	/* nothing received yet */
+			continue;       
+
+		count += result;
+	}
+
+	pxe_close(socket);
+
+
+	/* End of example */
+
+
+3.3 Quick Reference to API, available for user code
+----------------------------------------------------
+
+		This overview covers functions and macro definitions that
+	may be usefull for user code.
+
+
+3.3.1 pxe_arp module
+---------------------
+
+		This module is used mainly by internal code while sending IP
+	packets.
+
+macro definitions:
+
+MAX_ARP_ENTRIES		- how much may be ARP table in size. If ARP table full
+			and new	MAC must be placed, then one of older entry is
+			replaced by new. Default number is 4.
+
+PXE_MAX_ARP_TRY		- how much trys will be peformed when sending ARP
+			requests, before say MAC search failed. Default: 3
+
+PXE_TIME_TO_DIE		- how much time to wait ARP reply in milliseconds.
+			Default: 5000 ms.
+
+PXE_ARP_SNIFF		- sometimes it's usefull to get senders MACs from
+			incoming requests (this may save time, MAC may be found
+			in table without requesting it by ARP module itself).
+			But if network is big enough - ARP table will be
+			updated too often. By default this option is defined.
+
+
+functions:
+
+void pxe_arp_init()
+	- inits pxe_arp module. Usually this call is performed from
+	pxe_core_init()
+
+const MAC_ADDR *pxe_arp_ip4mac(const PXE_IPADDR *addr)
+	- returns MAC address for requested IP address
+
+void pxe_arp_stats()
+	- shows ARP table. Available if defined PXE_MORE macro.
+
+
+3.3.2 pxe_await module
+-----------------------
+
+		Implements awaiting mechanism. Many operations are performed
+	similar	in protocol implementations. Usually, packet is sended and
+	application awaits for reply. pxe_await() function helps to simplify
+	code in such case.
+		It starts await callback function with some flags and counts
+	timeouts, try count. 
+
+		Here is example of awaiting:
+
+	/* we start awaiting, with dns_await() calllback function, maximum 4
+	 * trys, each try 20 seconds and waiting data static_wait_data.
+	 * Waiting data - is some data associated with current awaiting, it's
+	 * used by await callback function.
+	 */
+	if (!pxe_await(dns_await, 4, 20000, &static_wait_data))
+		return (NULL);
+
+	/*  pxe_await() returns 1 if awaiting was successfull (await function
+	 * returned PXE_AWAIT_COMPLETED flag)
+	 */
+
+	/* it's an awaiting function. pxe_await() provides current function,
+	 * current try number, time exceeded from start of try, pointer to
+	 * associated wait data.
+	 */
+	int
+	dns_await(uint8_t function, uint16_t try_number, uint32_t timeout,
+		  void *data)
+	{
+		/* cast to our type of wait data */
+		PXE_DNS_WAIT_DATA	*wait_data = (PXE_DNS_WAIT_DATA *)data;
+
+		switch(function) {
+
+		case PXE_AWAIT_STARTTRY:
+			/* is called at start of each try 
+			 * Here must be performed any await initialisation
+			 * (e.g. request packet sending )
+			 */
+			if (!dns_request(wait_data)) {
+				/* if initialisation of try failed, try more */
+				return (PXE_AWAIT_NEXTTRY); 
+			}
+			/* otherwise return success result of await function */
+			break;
+		
+		case PXE_AWAIT_FINISHTRY: 
+			/* this function is called at the end of any try (even
+			 * if try was successful). Here cleanup must be
+			 * performed.
+			 */
+			if (wait_data->socket != -1)
+				pxe_close(wait_data->socket);
+			
+			wait_data->id += 1;
+			break;
+
+		case PXE_AWAIT_NEWPACKETS:
+			/* while waiting this function called if new packets
+			 * were received by pxe_core_recv_packets(). Actually
+			 * it may be not packets we are waiting for, may be
+			 * even not packets with out protocol. Here we must
+			 * check for new usefull for us packets, receive 
+			 * new data if any.
+			 */
+			size = pxe_recv(wait_data->socket, wait_data->data,
+				    wait_data->size);
+
+			parse_dns_reply(wait_data);
+			
+			if (wait_data->result.ip != 0) {
+				/* return success of awaiting. This may be
+				 * returned from any function
+				 */
+			        return (PXE_AWAIT_COMPLETED);
+			}
+			
+			/* if await was not completed, continue waiting */
+			return (PXE_AWAIT_CONTINUE);
+			break;
+	
+			case PXE_AWAIT_END:
+			/* this called if await is ended without any result */
+			default:
+				break;
+		}
+	
+		return (PXE_AWAIT_OK);
+	}
+
+	/* end of example */
+
+		So, wait data used for providing and receiving data while
+	awaiting. pxe_await() performs unified working with code, needed for
+	waiting of incoming packets.
+
+macro definitions:
+
+TIME_DELTA_MS		- delay between iterations during awaitng. At each
+			iteration are checked:
+			* receiving of new packet. If received - awaiting
+			 function with PXE_AWAIT_NEWPACKETS function is called.
+			* try timeout. if timeout exceeds maximum timeout -
+			 awaiting  function with PXE_AWAIT_FINISHTRY and
+			 PXE_AWAIT_STARTTRY flags sequentially are called.
+			* try count. if try count exceeds maximum - awaiting
+			 function with PXE_AWAIT_ENDED flag is called. This
+			 means that await failed.
+			 Default: 1
+
+TIME_DELTA		- default: 1000, same as TIME_DELTA_MS, but in ticks
+			 for delay.
+
+
+3.3.3 pxe_buffer module
+------------------------
+	
+		This module provides reading and writing of cyclic buffers.
+	It's not used directly by user code.
+
+macro definitions:
+
+PXE_POOL_SLOTS 		- if defined, then statical allocation of buffers is
+			used. Otherwise buffers are allocated at run-time from
+			heap with pxe_alloc() function. Current statical
+			allocation algorithm is simple and square, there are
+			two big buffers data storages divided in slots (by
+			default 2).
+				Each slot has size equal to
+			PXE_DEFAULT_RECV_BUFSIZE or PXE_DEFAULT_SEND_BUFSIZE.
+			Depending on requested size in pxe_buffer_alloc()
+			function data allocated from one of stoarge and
+			related	slot marked busy. When pxe_buffer_free() called,
+			slot marked as free.
+				Default: undefined
+
+PXE_DEFAULT_RECV_BUFSIZE - size of receiving buffer. Default: 16392
+
+PXE_DEFAULT_SEND_BUFSIZE - size of sending buffer. Default: 4096
+
+
+3.3.4 pxe_connection module
+----------------------------
+
+		This module is one of TCP related modules. It implements
+	connection entity. TCP connection is logical structure, that have
+	needed by TCP protocol counters and states.
+		User code is not directly works with this module.
+
+macro definitions:
+
+PXE_MAX_TCP_CONNECTIONS		- how much simultaneous connections may be.
+
+
+functions:
+
+void pxe_connection_stats()
+	- returns connections statistics. Available if PXE_MORE macro is
+	defined.
+
+
+3.3.5 pxe_core module
+----------------------
+
+		This module performs lowlevel work with PXE API: initialisation,
+	receiving/sending of packets, provides information functions.
+		In most cases, user code doesn't uses this module directly.
+
+macro definitions:
+
+PXE_BUFFER_SIZE 	- size of core buffers, used in PXE API calling,
+			  Default: 4096
+
+PXE_CORE_STATIC_BUFFERS	- if defined, core buffers are allocated statically.
+			Otherwise they are allocated in heap. Default: defined
+
+functions:
+
+int pxe_core_recv_packets()
+	- recieves all packets waiting in incoming queue of NIC, and calls
+	appropriate protocols if needed
+
+
+void pxe_core_register(uint8_t ip_proto, pxe_protocol_call proc)
+	- registers IP stack protocol, associates protocol number and handler.
+
+const MAC_ADDR *pxe_get_mymac()
+	- returns MAC of NIC, for which PXE API is used.
+
+const PXE_IPADDR *pxe_get_ip(uint8_t id)
+	- returns of stored IP, for provided id.
+	id may be:
+		PXE_IP_MY		- NIC IP address
+		PXE_IP_NET		- network adrress
+		PXE_IP_NETMASK		- network mask
+		PXE_IP_NAMESERVER	- nameserver to use in name resolving
+		PXE_IP_GATEWAY		- default gateway
+		PXE_IP_BROADCAST	- broadcast address
+		PXE_IP_SERVER		- server from which loading of pxeboot
+					  was performed
+		PXE_IP_WWW		- IP address of http-server
+		PXE_IP_ROOT		- IP adddress of server, where root
+					  file system is situated.
+
+void pxe_set_ip(uint8_t id, const PXE_IPADDR *ip)
+	- sets value by it's id.
+
+time_t	pxe_get_secs()
+	- returns time in seconds. Used in timeout and resend checking.
+
+types:
+
+typedef int (*pxe_protocol_call)(PXE_PACKET *pack, uint8_t function)
+	- protocol callback function type
+
+
+3.3.6. pxe_dhcp module
+-----------------------
+
+		This module implements simple DHCP client, used to obtain
+	gateway, nameserver and other information.
+
+
+macro definitions:
+
+PXE_BOOTP_USE_LIBSTAND	- use bootp() function provided by libstand instead
+	of own DHCP client. NOTE: bootp() doesn't set nameip (nameserver ip
+	structure), thus DNS resolving will be impossible. Default: undefined
+	
+	NOTE: to use bootp(), also UDP_DEFAULT_SOCKET macro must be defined.
+
+
+functions:
+
+void pxe_dhcp_query(uint32_t xid)
+	- sends DHCPDISCOVER packet and sets core_ips, if gets reply.
+
+
+3.3.6. pxe_dns module
+----------------------
+
+		This module provides domain name resolving. Actually
+	A and CNAME resource records are supported.
+
+macro definitions:
+
+PXE_MAX_DNS_TIMEOUT	- max time to wait DNS reply in milliseconds.
+			Default: 10 seconds
+
+PXE_MAX_DNS_TRYS	- how many times to try to resend request,
+			if there is no reply. Default: 3
+
+PXE_DNS_MAX_PACKET_SIZE	- maximum UDP packet size in bytes. Default: 512.
+			This DNS client doesn't support TCP for resolving.
+
+functions:
+
+const PXE_IPADDR *pxe_gethostbyname(char *name)
+	- returns IP, if resolved, for provided domain name. 
+
+uint32_t pxe_convert_ipstr(char *str)
+	- converts string value of ipv4 to uint32_t value.
+
+
+3.3.8. pxe_filter module
+-------------------------
+
+		This module is not supposed to be used by user code directly.
+	It implements filtering of incoming IP packets. It's used by UDP and
+	TCP modules for sorting packets in appropriate socket.
+		Module provides functions for adding and removing filters.
+	Each filter contains source/destination ip:port definition and masks
+	for all of them. Usage of masks gives opportunity to recieve data
+	from subnet, or subset of ports.
+
+functions:
+
+void pxe_filter_init()
+	- inits filter module structures such as list of free filter entries.
+
+void pxe_filter_stats()
+	- show active filters information. Used for debugging. Available if
+	PXE_MORE macro defined.
+
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list