Index: user/sbruno/pxe_http/Makefile =================================================================== --- user/sbruno/pxe_http/Makefile (nonexistent) +++ user/sbruno/pxe_http/Makefile (revision 245442) @@ -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 Index: user/sbruno/pxe_http/README =================================================================== --- user/sbruno/pxe_http/README (nonexistent) +++ user/sbruno/pxe_http/README (revision 245442) @@ -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. + + +3.3.9. pxe_http module +----------------------- + + pxe_http implements functions for getting files via HTTP. + Most of it's functions are used only by httpfs module. + At opening file pxe_exists() function is called, which + gets filesize (if possible) by HEAD method of request and opens + connection to file. Result of pxe_exists() call is keep-alive + connection to file. + pxe_get() function gets needed data and reestablishes + connection if needed. + if PXE_MORE defined - pxe_get_close() function becomes + available. It opens connection, gets portion of data and closes + connection. It's rather not optimal usage of http connections, + but some times it may be needed (e.g. for servers, where keep + alive connections are prohibited). + +macro definitions: + +PXE_MAX_HTTP_HDRLEN - buffer size for generating/getting http header. + Default: 1024 bytes. + +functions: + +int pxe_fetch(char *server, char *filename, off_t from, size_t size) + - testing function, gets file from server ()may be partially) and + outputs received data to screen. Available if PXE_MORE defined. + + +3.3.10. httpfs module +---------------------- + + httpfs is filesystem, available via HTTP. It is read-only + filesystem, mainly with sequential access to files. It exports + file operations structure and is not used directly by user code. + httpfs module may support some kind of caching: it requests + more data per request then it's needed at http_read() call and + reads this data later. Such approach speed ups connections speed + and reduces server load. + This opportunity is available if PXE_HTTPFS_CACHING macro + is defined. + + +3.3.11. pxe_icmp module +------------------------ + + pxe_icmp module provides some basic functionality of ICMP + protocol: echo requesting/replying. + Module is unavailable, if PXE_MORE undefined. + + +macro definitions: + +PXE_ICMP_TIMEOUT - timeout in milliseconds when waiting echo reply. + Default: 5000 ms. + + +functions: + +int pxe_ping(const PXE_IPADDR *ip, int count, int flags) + - works similar to usual ping, sends echo request and shows timeout + before echo reply. + +int pxe_icmp_init() + - inits module + + +3.3.12. pxe_ip module +---------------------- + + This module implemets IP protocol functions, also it works + with routing table. It also declares PXE_IPADDR, that is used widely. + +macro definitions: + +PXE_MAX_ROUTES - route table size. Default: 4, usually used 2 entries. + + +functions: + +uint16_t pxe_ip_checksum(const void *data, size_t size) + - calculates checksum for provided block of data. + + +void pxe_ip_route_init(const PXE_IPADDR *def_gw) + - inits routing table, sets default gateway + + +int pxe_ip_route_add(const PXE_IPADDR *net, uint32_t mask, + const PXE_IPADDR *gw) + - adds route to routing table + +int pxe_ip_route_del(const PXE_IPADDR *net, uint32_t mask, + const PXE_IPADDR *gw) + - dels route from routing table + +uint32_t pxe_ip_get_netmask(const PXE_IPADDR *ip) + - returns class based netmask for ip. + +int pxe_ip_route_default(const PXE_IPADDR *gw) + - adds default gateway + +int pxe_ip_send(void *data, const PXE_IPADDR *dst, uint8_t protocol, + uint16_t size) + - sends ip packet with provided data. There must be space for + IP header in buffer, pointed by data. + +void pxe_ip_route_stat() + - show route table. Available if PXE_MORE defined + + +3.3.13. pxe_isr module +----------------------- + + Contains assembler side functions, used in pxe_core. + User code has no direct access to them. + There supported: installation/removing of interrupt handler, + interrupt handler and wrapper for PXE API calls. + + +3.3.14. pxe_mem module +----------------------- + + Actually this module just a wrapper to bcopy(), alloc() and free() + functions. That's done to make pxe_http library more portable. + But in fact, pxe_http depends much on other libstand functions, + such as printf(), strcpy() and etc. So this module is not very usefull and + will be probably removed in future. + + +3.3.15. pxe_sock module +------------------------ + + Most used by user code module. Contains implementation of + pxe_http sockets API. + + +macro definitions: + +PXE_DEFAULT_SOCKETS - count of sockets used at the same time. If all + socket structures are used, next socket creating calls + and API that depends on it, will fail. Default: 4 + + +PXE_SOCKET_TIMEOUT - how long pxe_recv() will be wiating incoming data per + call before return error. Default: 30000 ms + +PXE_SOCKET_CHECK_TIMEOUT - If pxe_recv() waits incoming data and have big free + space in buffer, and in case of TCP protocol it may notice + remote server about this by sending empty packet (with + no data) acking current state, so remote host updates + knowledge about receiving window of client and sends new + data. + That option specifies how long pxe_recv() will + be waiting before checking TCP connection. In fast + environments like LAN it speed ups connection when huge + amount of data is transmitted, in WAN it's not very + useful. + Default: 100 ms. This option works only if + PXE_TCP_AGRESSIVE macro is defined. + +PXE_SOCKET_ACCURATE - adds extra socket validating at head of every + socket related function, available to user. + By default: defined. + +functions: + +void pxe_sock_init() + - inits socket API module. + +void pxe_sock_stats() + - prints out to screen socket usage statistics. Available if PXE_MORE + macro defined. + +int pxe_sock_state(int socket) + - return current socket state. May be one of this states: + PXE_SOCKET_BINDED, PXE_SOCKET_CONNECTED, PXE_SOCKET_ESTABLISHED. + It may be used for checking, if connection was breaked. + + +int pxe_sendto(int socket, const PXE_IPADDR *dst, uint16_t port, + void *data, uint16_t size) + - sends to provided ip/port, updating filter for socket. If + socket is not connected, connects it. Blocking operation. + +int pxe_connect(int socket, const PXE_IPADDR *ip, uint16_t port, + uint8_t proto) + - establishes connection to remote host and updates needed filter + structures. + +int pxe_send(int socket, void *buf, uint16_t buflen) + - sends data to socket, blocking operation till successfull sending + or error. + +int pxe_recv(int socket, void *buf, uint16_t buflen) + - receives data from socket. Blocks till timeout, error or + successfull result. + +int pxe_socket() + - creates new socket. Every socket must be closed after usage by + pxe_close() call. + +int pxe_bind(int socket, const PXE_IPADDR *ip, uint16_t port, + uint8_t proto) + - binds local ip, port for socket. Used e,g, by DHCP. + +int pxe_flush(int socket) + - flushes sending buffer. After this call user code may be sure that + data was transmitted to network, but may be not received by remote + host yet. + +int pxe_close(int socket) + - closes socket. + +uint16_t pxe_next_port() + - returns next available local port. It just increments at each call. + + +3.3.16. pxe_segment module +--------------------------- + + Part of TCP related modules. Contains functions used internally + for creating and sending TCP segments. + pxe_segment module uses memory space of sending buffer manually + without buffer writing functions. + Buffer is divided to PXE_TCP_BLOCK_COUNT blocks, each block + is divided to PXE_TCP_CHUNK_COUNT chunks, by default 64 chunks at all + with size 64 bytes for each (for default buffer size 4096). + Packets may be "small" (e.g. system packets ACK, RST and etc) + and contain no user data. In such case usualy will be enough one chunk + for packet. Also packets may be "big", but not bigger than one block + size minus segment descriptor structure. If packet exclusevely uses + all chunks in block it gives about 460 user data per segment. + For client-side usage this must be enough. + +macro definitions: + +PXE_RESEND_TIME - if during this time segment was not acked, it will be + resent. At every resend try this value will be increased. + Default: 1 second + +PXE_RESEND_TRYS - how much resend trys to do. Default: 3 + +PXE_TCP_BLOCK_COUNT - how much blocks in memory buffer for segments. + +PXE_TCP_CHUNK_COUNT - how much chhunks in buffer for segments. + + +3.3.17. pxe_tcp module +----------------------- + + TCP related module. Implements handling of incoming packets, + it's functions are used internally. + +macro definitions: + +PXE_TCP_MSL - maximum segment life time in milliseconds. + Used only in TINE_WAIT state. Default: 60000 ms. + +PXE_TCP_SYSBUF_SIZE - buffer size used for system messages for packets + without real connection. It may be for closed or + unxexisting connections. In such case there is no + bufer for outcoming segments, but module needs to send + at least RST. Default: 64 bytes. + +PXE_TCP_MSS - maximum segment size. For Ethernet LAN it's 1460, + but for internet connections it may be useful to + use smaller segment size, e.g. 1260. Default: 1260 + +functions: + +void pxe_tcp_init() + - inits TCP module. Usually started automatically from pxe_core_init() + + +3.3.18. pxe_udp module +----------------------- + + Implements UDP protocol. May be used without sockets API. + +macro definitions: + +UDP_DEFAULT_SOCKET - if defined, "default UDP socket" is created. All + filtered out data goes to this socket. It was added + to support udpread() and udpsend() functions, used + by libstand itself. Also it may be used for working + with UDP module, skipping direct work with sockets API. + Default: undefined. + +functions: + +void pxe_udp_init() + - UDP module init + +void pxe_udp_shutdown() + - UDP module shutdown routine + +int pxe_udp_send(void *data, const PXE_IPADDR *dst, uint16_t dst_port, + uint16_t src_port, uint16_t size) + - sends udp packet. + + +int pxe_udp_read(PXE_SOCKET *sock, void *tobuf, uint16_t buflen, + PXE_UDP_DGRAM *dgram_out) + - reads data from udp socket. if sock == NULL, "default" + socket is assumed. + + +4. Debugging, testing and tuning pxe_http library. +-------------------------------------------------- + + pxe_http library has built-in testing functions, that may be + started from loader's console. For this PXE_MORE macro must be defined + while compiling loader and pxe_http itself. + After this 'pxe' command appears in list of available commands. + + +4.1. Using 'pxe' loader's command +---------------------------------- + + This commands helps to test working od pxe_http library and + contains one really usefull function ping. + While loading pxe_http gets gateway, nameserver & etc + information from DHCP server. In case if there is any error (e.g. + DHCP packet contains no information about nameserver) this must be + set manually for correct working of code. + + command 'arp': + - this command test ARP protocol related functions. + + Example: pxe arp stats + - shows current arp table. It contains same + values as usual. + pxe arp ip4.addres + - trys to get MAC address of provided ip using + ARP protocol. + + command 'await': + - used to test how implemented ICMP echo request and ARP + request replying. + + Example: pxe await + - starts infinte loop, in which will be + processed received packets. It's usefull for + testing ARP and ICMP request/replies. "Infinte" + means there is no exit from it without resetting + of PC. + + command 'filters': + - shows current filters usage information. + + Example: pxe filters + - shows current filters usage. If all is ok, + sockets closed correctly, filters are free - + you will see something like "0/8 filters". + If there is connected socket, or there was + error somewhere in implementation - you will + see filters related info (source/destination + ip/ports, binded socket). + + command 'ns': + - used to see and modify default nameserver. + + Example: pxe ns + - shows nameserver + + pxe ns ip4.addr + - sets nameserver to specified ip address. + + + command 'ping': + - performs similar actions to well known ping command. It sends + echo requests and gets replies, calculating timeouts. + + Example: pxe ping ip4.addr + - performs sending five icmp echo requests to + specified ip address. + + command 'resolve': + - performs sending DNS requests and extracts A or CNAME answers + from nameserver replies. + + Example: pxe resolve domain.name + - performs domain name resolution, using default + nameserver. + + command 'route': + - works with routing table and used for ip based protocols. + IP packet routed to first found route, routes are searched + sequentially from start of table to end. + + Example: pxe route print + - shows current routing table. + + pxe route add default ip4.addr + - sets default gateway + + pxe route add net4.addr gw4.addr + - sets gateway for network. Mask for network is + generated automatically from net address, CIDR + is not supported. + + pxe route del net4.addf gw4.addr + - removes route from table. + + command 'socket': + - currently just shows statistics related to active sockets. + + Example: pxe socket stats + - show active sockets information. + + +4.2. Defining debug macroses +----------------------------- + + All debug macroses divided in groups to provide more flexible + debugging of exact module. There are two levels of debugging: + first just adds _DEBUG suffix to macro, next _DEBUG_HELL. Second one + as expected from it's naming - provides more information. + All this macro definitions are situated in project Makefile. + + +macro definitions: + +PXE_DEBUG +PXE_DEBUG_HELL - common modules debuging. This macroses adds debug + information output toi all modules, that are not + covered by macroses below. + + NOTE: defining PXE_DEBUG macro doesn't defines + e.g. PXE_CORE_DEBUG. It must be set manually. + +PXE_CORE_DEBUG +PXE_CORE_DEBUG_HELL - pxe_core module debuging + +PXE_TCP_DEBUG +PXE_TCP_DEBUG_HELL - related to TCP modules debuging + +PXE_IP_DEBUG +PXE_IP_DEBUG_HELL - IP module debug. Includes routing. + +PXE_ARP_DEBUG +PXE_ARP_DEBUG_HELL - ARP module debug + +PXE_HTTP_DEBUG +PXE_HTTP_DEBUG_HELL - httpfs and pxe_http module debugging + +PXE_MORE - adds functions, used to out to screen information + about filters, sockets and etc usage. + +4.3. Tuning +------------ + + Well, pxe_http library developed as library that implements + client sockets API. But, it may be used in different environments and + thus may have different behaviour e,g, in LAN and in WAN. + In most cases it works well in both cases, but if not - here is + some hints that may be usefull. + + In LAN usually packet loss is small and speed is fast, so + it may be good idea to define PXE_TCP_AGRESSIVE macro (see 3.3.15). + PXE_TCP_MSS may me set to 1460 without any doubts. + Buffer sizes may be set higher (3.3.3). 16K for incoming + traffic is good enough for WAN connections, but for LAN it may be set + higher. If big UDP datagrams are sended, send buffer must be set to + such space, in which it may fit. + Also all timeouts may be smaller. For example, first candidate + for it is TIME_DELTA (3.3.2) + + Next point - what buffers use: statically allocated or + dinamically. Default variant is best (at least, I think so) but + it may be not bad idea to play with PXE_CORE_STATIC_BUFFERS and + PXE_POOL_COUNT. + + It may be usefull to turn off httpfs caching. Using of + caching speed ups getting of file, but anyway undefining of + PXE_HTTPFS_CACHING still gives working code. + + +4.4. NFS loading with pxe_http +------------------------------- + + Original pxeboot has ability to load kernel, loader.rc and etc. + pke_http may provide udpread()/udpsend() functions needed for that. + + undefine: loader/Makefile: LOADER_HTTP_SUPPORT + define: pxe_http/pxe_udp.h: UDP_DEFAULT_SOCKET + pxe_http/pxe_dhcp.h: PXE_BOOTP_USE_LIBSTAND + libi386/Makefile: PXEHTTP_UDP_FOR_LIBSTAND + + After that - NFS loader must work, as well as TFTP. \ No newline at end of file Index: user/sbruno/pxe_http/acpi_sony/acpi_sony.c =================================================================== --- user/sbruno/pxe_http/acpi_sony/acpi_sony.c (nonexistent) +++ user/sbruno/pxe_http/acpi_sony/acpi_sony.c (revision 245442) @@ -0,0 +1,1158 @@ +/*- + * Copyright (c) 2004 Takanori Watanabe + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/acpi_support/acpi_sony.c,v 1.10 2006/11/01 03:45:24 kevlo Exp $"); + +#include "opt_acpi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "acpi_if.h" +#include + +#include +#include +#include + +#include +#include +#include + +#include "acpi_sony.h" + +/* + * Declarations + */ +#define _COMPONENT ACPI_OEM + +ACPI_MODULE_NAME("Sony") +ACPI_SERIAL_DECL(sony, "Sony extras"); + +static int acpi_sony_probe(device_t dev); +static int acpi_sony_attach(device_t dev); +static int acpi_sony_detach(device_t dev); +static int acpi_snc_sysctl(SYSCTL_HANDLER_ARGS); +static int acpi_spic_sysctl(SYSCTL_HANDLER_ARGS); +static void acpi_snc_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context); +static void acpi_spic_intr(void * arg); +/* +static d_open_t acpi_sony_spic_open; +static d_close_t acpi_sony_spic_close; +static d_read_t acpi_sony_spic_read; +static d_ioctl_t acpi_sony_spic_ioctl; +static d_poll_t acpi_sony_spic_poll; + +static struct cdevsw spic_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, + .d_open = acpi_sony_spic_open, + .d_close = acpi_sony_spic_close, + .d_read = acpi_sony_spic_read, + .d_ioctl = acpi_sony_spic_ioctl, + .d_poll = acpi_sony_spic_poll, + .d_name = "spic", +}; +*/ + +static device_method_t acpi_sony_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, acpi_sony_probe), + DEVMETHOD(device_attach, acpi_sony_attach), + DEVMETHOD(device_detach, acpi_sony_detach), + + {0, 0} +}; + +static driver_t acpi_sony_driver = { + "acpi_sony", + acpi_sony_methods, + sizeof(struct acpi_sony_softc), +}; + +static devclass_t acpi_sony_devclass; + +DRIVER_MODULE(acpi_sony, acpi, acpi_sony_driver, acpi_sony_devclass, 0, 0); +MODULE_DEPEND(acpi_sony, acpi, 1, 1, 1); + +static char *sony_snc_id[] = {"SNY5001", NULL}; +static char *sony_spic_id[] = {"SNY6001", NULL}; + +/* + * SPIC related functions + */ + +/* acpi_spic_type() - returns type of SPIC. + * in: + * dev - SPIC device_t structure + * out: + * one of SPIC_TYPE constants + */ +static enum SPIC_TYPE +acpi_spic_type(device_t dev) +{ + enum SPIC_TYPE model = SPIC_TYPE2; + const struct spic_pciid *p = spic_pciids; + device_t device; + + while (p->vid != 0) { + device = pci_find_device(p->vid, p->did); + + if (device != NULL) { + model = p->type; + break; + } + + ++p; + } + + device_printf(dev, "assuming type%d model\n", model + 1); + + return (model); +} + +/* acpi_spic_write_port1() - writes value to 1st SPIC port. + * in: + * sc - driver softc structure + * val - value to write + * out: + * none + */ +static void +acpi_spic_write_port1(struct acpi_sony_softc *sc, uint8_t val) +{ + + DELAY(10); + + outb(sc->port_addr, val); +} + +/* acpi_spic_write_port2() - writes value to 2nd SPIC port. + * in: + * sc - driver softc structure + * val - value to write + * out: + * none + */ +static void +acpi_spic_write_port2(struct acpi_sony_softc *sc, uint8_t val) +{ + + DELAY(10); + + outb(sc->port_addr + 4, val); +} + +/* acpi_spic_read_port1() - reads value from 1st SPIC port. + * in: + * sc - driver softc structure + * out: + * readed value + */ +static uint8_t +acpi_spic_read_port1(struct acpi_sony_softc *sc) +{ + + DELAY(10); + + return (inb(sc->port_addr)); +} + +/* acpi_spic_read_port2() - reads value from 2nd SPIC port. + * in: + * sc - driver softc structure + * out: + * readed value + */ +static uint8_t +acpi_spic_read_port2(struct acpi_sony_softc *sc) +{ + + DELAY(10); + + return (inb(sc->port_addr + 4)); +} + +/* acpi_spic_busy_wait() - synching with port + * in: + * sc - driver softc structure + * out: + * none + */ +static void +acpi_spic_busy_wait(struct acpi_sony_softc *sc) +{ + int i= 0; + + while (acpi_spic_read_port2(sc) & 2) { + DELAY(10); + + if (++i > 10000) { + printf("acpi_spic_busy_wait() abort\n"); + return; + } + } +} + +/* acpi_spic_call1() - first variant of call + * in: + * sc - driver softc structure + * dev - which device to query + * out: + * returned value + */ +static uint8_t +acpi_spic_call1(struct acpi_sony_softc *sc, uint8_t dev) +{ + + acpi_spic_busy_wait(sc); + acpi_spic_write_port2(sc, dev); + acpi_spic_read_port2(sc); + + return (acpi_spic_read_port1(sc)); +} + +/* acpi_spic_call1() - second variant of call + * in: + * sc - driver softc structure + * dev - which device to query + * fn - function to call + * out: + * returned value + */ +static uint8_t +acpi_spic_call2(struct acpi_sony_softc *sc, uint8_t dev, + uint8_t fn) +{ + + acpi_spic_busy_wait(sc); + acpi_spic_write_port2(sc, dev); + acpi_spic_busy_wait(sc); + acpi_spic_write_port1(sc, fn); + + return (acpi_spic_read_port1(sc)); +} + +#ifdef code_for_camera_works +static uint8_t +acpi_spic_call3(struct acpi_sony_softc *sc, uint8_t dev, uint8_t fn, + uint8_t v) +{ + acpi_spic_busy_wait(sc); + acpi_spic_write_port2(sc, dev); + acpi_spic_busy_wait(sc); + acpi_spic_write_port1(sc, fn); + acpi_spic_busy_wait(sc); + acpi_spic_write_port1(sc, v); + + return (acpi_spic_read_port1(sc)); +} +#endif + +/* acpi_spic_crs() - dumps currently used by device resources + * in: + * sc - driver softc structure + * out: + * none + */ +static void +acpi_spic_crs(struct acpi_sony_softc *sc) +{ + ACPI_STATUS status; + ACPI_BUFFER buffer; + + struct { + ACPI_RESOURCE io; + ACPI_RESOURCE intr; + ACPI_RESOURCE endtag; + } *resource; + + /* init acpi_buffer */ + resource = AcpiOsAllocate(sizeof(*resource) ); + + if (resource == NULL) /* failed to alllocate resource structure */ + return; + + buffer.Length = sizeof(*resource) ; + buffer.Pointer = resource; + + status = AcpiGetCurrentResources(sc->handle, &buffer); + + /* check for total failure */ + if (ACPI_FAILURE(status)) { + device_printf(sc->dev, "failed to get current resources.\n"); + return; + } + + device_printf(sc->dev, "Current resources = IO: 0x%x/%d, IRQ: 0x%x\n", + resource->io.Data.Io.Minimum, resource->io.Data.Io.AddressLength, + resource->intr.Data.Irq.Interrupts[0]); +} + +/* acpi_spic_dis() - disables SPIC by calling of _DIS method + * in: + * sc - driver softc structure + * out: + * none + */ +static void +acpi_spic_dis(struct acpi_sony_softc *sc) +{ + + if (ACPI_FAILURE(AcpiEvaluateObject(sc->handle, + "_DIS", NULL, NULL))) + { + device_printf(sc->dev, "failed to disable\n"); + return; + } + + device_printf(sc->dev, "device is disabled\n"); +} + +/* acpi_spic_srs() - calls _SRC method to set allocated resources + * in: + * sc - driver softc structure + * out: + * 0 - all is ok + * not 0 - some error occured + */ +static int +acpi_spic_srs(struct acpi_sony_softc *sc) +{ + ACPI_STATUS status; + ACPI_BUFFER buffer; + int result = 0; + + struct { + ACPI_RESOURCE io; + ACPI_RESOURCE intr; + ACPI_RESOURCE endtag; + } *resource; + + /* init acpi_buffer */ + resource = AcpiOsAllocate(sizeof(*resource)); + + if (resource == NULL) /* failed to alllocate resource structure */ + return (ENOMEM); + + buffer.Length = sizeof(*resource) ; + buffer.Pointer = resource; + + /* setup io resource */ + resource->io.Type = ACPI_RESOURCE_TYPE_IO; + resource->io.Length = sizeof(ACPI_RESOURCE); + memcpy(&(resource->io.Data.Io), &(sc->io), sizeof(ACPI_RESOURCE_IO)); + + /* setup irq resource */ + resource->intr.Type = ACPI_RESOURCE_TYPE_IRQ; + resource->intr.Length = sizeof(ACPI_RESOURCE); + memcpy(&resource->intr.Data.Irq, &(sc->interrupt), + sizeof(ACPI_RESOURCE_IRQ)); + + resource->endtag.Type = ACPI_RESOURCE_TYPE_END_TAG; + + /* Attempt to set the resource */ + status = AcpiSetCurrentResources(sc->handle, &buffer); + + /* check for total failure */ + if (ACPI_FAILURE(status)) { + device_printf(sc->dev, "failed to set resources.\n"); + result = ENODEV; + } + +end: + AcpiOsFree(resource); + + return (result); +} + +/* acpi_spic_try_irq() - trys to allocate irq, found while walking + * ACPI resources for SPIC + * in: + * sc - driver softc structure + * intn - irq index in provided resource + * resources - ACPI resource containing IRQ data + * out: + * 1 - all is ok + * 0 - some error occured + */ +static int +acpi_spic_try_irq(struct acpi_sony_softc *sc, uint8_t intn, + ACPI_RESOURCE *resource) +{ + + if (!(sc->intr_res = bus_alloc_resource(sc->dev, SYS_RES_IRQ, + &sc->intr_rid, + resource->Data.Irq.Interrupts[intn], + resource->Data.Irq.Interrupts[intn], 1, + RF_ACTIVE | RF_SHAREABLE))) + { + return (0); + } + + sc->intr = (uint16_t)rman_get_start(sc->intr_res); + + memcpy(&(sc->interrupt), &(resource->Data.Irq), + sizeof(ACPI_RESOURCE_IRQ)); + + sc->interrupt.Interrupts[0] = sc->intr; + sc->interrupt.InterruptCount = 1; + + device_printf(sc->dev,"using IRQ 0x%x\n", sc->intr); + + return (1); +} + +/* acpi_spic_try_io() - trys to allocate io resource, found while walking + * ACPI resources for SPIC + * in: + * sc - driver softc structure + * resources - ACPI resource containing IO data + * out: + * 1 - all is ok + * 0 - some error occured + */ +static int +acpi_spic_try_io(struct acpi_sony_softc *sc, ACPI_RESOURCE *resource) +{ + if (!(sc->port_res = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, + &sc->port_rid, + resource->Data.Io.Minimum, + resource->Data.Io.Maximum, + resource->Data.Io.AddressLength, + RF_ACTIVE | RF_SHAREABLE))) + { + return (0); + } + + device_printf(sc->dev, "using IO ports 0x%x-0x%x/%d\n", + resource->Data.Io.Minimum, + resource->Data.Io.Maximum, + resource->Data.Io.AddressLength); + + sc->port_addr = (uint16_t)rman_get_start(sc->port_res); + + memcpy(&(sc->io), &(resource->Data.Io), sizeof(ACPI_RESOURCE_IO)); + + return (1); +} + +/* acpi_spic_walk_prs() - callback function used in walking of + * ACPI resources for SPIC + * in: + * resource - found ACPI resource + * context - context (driver softc structure) + * out: + * AE_CTRL_TERMINATE - if found, or any error + * AE_OK - processed resource + */ +static ACPI_STATUS +acpi_spic_walk_prs(ACPI_RESOURCE *resource, void *context) +{ + struct acpi_sony_softc *sc = (struct acpi_sony_softc *)context; + + if (sc->port_res && sc->intr_res) + return (AE_CTRL_TERMINATE); + + switch (resource->Type) { + case ACPI_RESOURCE_TYPE_START_DEPENDENT: + case ACPI_RESOURCE_TYPE_END_DEPENDENT: + return AE_OK; + + case ACPI_RESOURCE_TYPE_IRQ: + + /* already allocated */ + if (sc->intr_res) + return AE_OK; + + for (int i = 0; i < resource->Data.Irq.InterruptCount; ++i) + if (acpi_spic_try_irq(sc, i, resource)) + break; + + return (AE_OK); + + case ACPI_RESOURCE_TYPE_IO: + + if (sc->port_res) + return (AE_OK); + + if (resource->Data.Io.AddressLength <= 0) + return (AE_OK); + + acpi_spic_try_io(sc, resource); + + return (AE_OK); + + case ACPI_RESOURCE_TYPE_END_TAG: + return (AE_OK); + } + + return (AE_CTRL_TERMINATE); +} + +/* acpi_spic_attach() - attaches driver for SPIC + * in: + * sc - driver softc structure +* out: + * 0 - all is ok + * not 0 - some error + */ +static int +acpi_spic_attach(struct acpi_sony_softc *sc) +{ + int result = 0; + int i = 0; + + ACPI_STATUS status; + + devclass_t ec_devclass; + + sc->model = acpi_spic_type(sc->dev); + sc->evport_offset = spic_types[sc->model].evport_offset; + sc->events = spic_types[sc->model].events; + + if (!(ec_devclass = devclass_find ("acpi_ec"))) { + device_printf(sc->dev, "Couldn't find acpi_ec devclass\n"); + return (EINVAL); + } + + if (!(sc->ec_dev = devclass_get_device(ec_devclass, 0))) { + device_printf(sc->dev, "Couldn't find acpi_ec device\n"); + return (EINVAL); + } + + sc->ec_handle = acpi_get_handle(sc->ec_dev); + + for (i = 0 ; acpi_spic_oids[i].name != NULL; i++){ + SYSCTL_ADD_PROC(&(sc->sysctl_ctx), + SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, acpi_spic_oids[i].name, + acpi_spic_oids[i].access, + sc, i, acpi_spic_sysctl, "I", + acpi_spic_oids[i].comment); + } + + acpi_spic_crs(sc); + + status = AcpiWalkResources(sc->handle, "_PRS", acpi_spic_walk_prs, sc); + + if ( (sc->port_res == NULL) || + (sc->intr_res == NULL)) + { + device_printf(sc->dev, "failed to allocate resources\n"); + return (ENXIO); + } + + if ( (result = acpi_spic_srs(sc)) == 0) { + + result = bus_setup_intr(sc->dev, sc->intr_res, INTR_TYPE_MISC, NULL, + acpi_spic_intr, sc, &sc->icookie); + + acpi_spic_call1(sc, 0x82); + acpi_spic_call2(sc, 0x81, 0xff); + acpi_spic_call1(sc, 0x82); + + //make_dev(&spic_cdevsw, 0, 0, 0, 0600, "jogdial"); + } + + return (result); +} + +/* acpi_spic_sysctl_get() - used to get values for SPIC oids + * in: + * sc - driver softc structure + * method - method code +* out: + * integer value of oid + */ +static int +acpi_spic_sysctl_get(struct acpi_sony_softc *sc, int method) +{ + ACPI_INTEGER val_ec; + int val = 0; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + switch (method) { + case ACPI_SONY_METHOD_BLUETOOTH_POWER: + val = sc->power_bluetooth; + break; + + case ACPI_SONY_METHOD_FAN: + ACPI_EC_READ(sc->ec_dev, SONY_EC_FANSPEED, &val_ec, 1); + val = val_ec; + break; + + default: + break; + } + + return (val); +} + +/* acpi_spic_sysctl_set() - used to set values for SPIC oids + * in: + * sc - driver softc structure + * method - method code + * arg - value to set +* out: + * 0 - all is ok + * not 0 - some error + */ +static int +acpi_spic_sysctl_set(struct acpi_sony_softc *sc, int method, int arg) +{ + ACPI_INTEGER val_ec; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + switch (method) { + case ACPI_SONY_METHOD_FAN: + val_ec = arg; + ACPI_EC_WRITE(sc->ec_dev, SONY_EC_FANSPEED, val_ec, 1); + break; + + case ACPI_SONY_METHOD_BLUETOOTH_POWER: + if (sc->power_bluetooth == arg) + return (0); + + acpi_spic_call2(sc, 0x96, arg); + acpi_spic_call1(sc, 0x82); + sc->power_bluetooth = arg; + + break; + + default: + break; + } + + return (0); +} + +/* acpi_spic_sysctl() - called when needed to set or get + * values for SPIC oids + * in: + * SYSCTL_HANDLER_ARGS +* out: + * 0 - success + * not 0 - some error + */ +static int +acpi_spic_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct acpi_sony_softc *sc; + int arg; + int error = 0; + int function; + int method; + + sc = (struct acpi_sony_softc *)oidp->oid_arg1; + function = oidp->oid_arg2; + method = acpi_spic_oids[function].method; + + arg = acpi_spic_sysctl_get(sc, method); + error = sysctl_handle_int(oidp, &arg, 0, req); + + if (error != 0 || req->newptr == NULL) + goto out; + + error = acpi_spic_sysctl_set(sc, method, arg); + +out: + return (error); +} + +/* acpi_spic_report_event() - used to report about occured SPIC event + * in: + * sc - driver softc structure + * event - SPIC event code + * mask - mask of event + * mapped_event- one of SPIC_EVENT_.. codes +* out: + * none + */ +static void +acpi_spic_report_event(struct acpi_sony_softc *sc, uint8_t event, + uint8_t mask, uint8_t mapped_event) +{ +#ifdef ACPI_SONY_VERBOSE + if (mapped_event != SPIC_EVENT_NONE) + device_printf(sc->dev, "event 0x%x/0x%x => 0x%x (%s)\n", + event, mask, mapped_event, event_descriptors[mapped_event - 1].name); +#endif + + /* notify devd, system "ACPI", subsystem "SPIC" */ + acpi_UserNotify("SPIC", sc->handle, mapped_event); + + /* clear event */ + acpi_spic_call2(sc, 0x81, 0xff); +} + +/* acpi_spic4_pkey_handler() - special programmable key handling for type4 + * cause of stamina/speed switch generates same event number as + * programmable key 2 in second turn + * in: + * sc - driver softc structure + * group - event group + * mask - mask of event + * event - SPIC event code +* out: + * 1 - event handled + * 0 - event not handled + */ +static int +acpi_spic4_pkey_handler(struct acpi_sony_softc *sc, + struct spic_event_group *group, uint8_t mask, uint8_t event) +{ + + switch (sc->prev_event) { + case 0: + case 0x5c: + break; + + case 0x61: + if (event == 0x02) + acpi_spic_report_event(sc, event, mask, + SPIC_EVENT_TOGGLE_SPEED); + + return (1); + + case 0x5f: + /* i have not received such mask on my laptop */ + + default: + device_printf(sc->dev, + "pkey_handler: unknown event 0x%x/0x%x " + "(prev: 0x%x)\n", + event, mask, sc->prev_event); + + return (0); + } + + return acpi_spic_default_handler(sc, group, mask, event); +} + +/* acpi_spic4_extra_handler() - special handling for type4 model + * in: + * sc - driver softc structure + * group - event group + * mask - mask of event + * event - SPIC event code +* out: +* 1 - event handled + * 0 - event not handled + */ +static int +acpi_spic4_extra_handler(struct acpi_sony_softc *sc, + struct spic_event_group *group, uint8_t mask, uint8_t event) +{ + switch (event) { + case 0x5c: + case 0x5f: + acpi_spic_call1(sc, 0xA0); + break; + + case 0x61: + acpi_spic_call1(sc, 0xB3); + break; + + default: /* event was unhandled */ + device_printf(sc->dev, "type4 unhandled 0x%x/0x%x\n", + event, mask); + return (0); + } + + if (sc->prev_event == 0) { + /*device_printf(sc->dev, "type4 special event 0x%x/0x%x\n", + event, mask); + */ + sc->prev_event = event; + } else { + sc->prev_event = 0; + } + + return (1); +} + +/* acpi_spic_default_handler() - default handler for all event groups + * in: + * sc - driver softc structure + * group - event group + * mask - mask of event + * event - SPIC event code + * out: + * 1 - event handled + * 0 - event not handled + */ +static int +acpi_spic_default_handler(struct acpi_sony_softc *sc, + struct spic_event_group *group, uint8_t mask, uint8_t event) +{ + struct spic_event *event_entry = group->events; + + while (event_entry->event != 0) { + + if (event_entry->code > event) + break; /* no event with needed code */ + + if (event_entry->code == event) { + /* found needed code */ + acpi_spic_report_event(sc, event, mask, event_entry->event); + + return (1); + } + + ++event_entry; + } + + return (0); +} + +/* acpi_spic_intr() - SPIC ISR + * in: + * arg - provided argument (driver softc structure) + * out: + * none + */ +static void +acpi_spic_intr(void * arg) +{ + struct acpi_sony_softc *sc = (struct acpi_sony_softc *)arg; + + if (sc == NULL) + return; + + uint8_t event = inb(sc->port_addr); + uint8_t mask = inb(sc->port_addr + sc->evport_offset); + + if ( (event == 0x00) || (event == 0xff)) + return; /* ignore */ + + struct spic_event_group *group = sc->events; + + /* searching needed group by mask */ + while (group->events != NULL) { + + if (group->mask > mask) { + break; /* no group with needed mask */ + } + + if (group->mask == mask) { /* processing */ + if ( (group->handler != NULL) && + (group->handler(sc, group, mask, event))) + return; /* handler processed event */ + + if (acpi_spic_default_handler(sc, group, mask, event)) + return; /* default handler processed event */ + } + + ++group; + } + + device_printf(sc->dev, "event 0x%x/0x%x unhandled\n", event, mask); + + /*clear event */ + acpi_spic_call2(sc, 0x81, 0xff); + + return; +} + +/* + * SNC related + */ + +/* acpi_snc_attach() - attaches driver for SNC + * in: + * sc - driver softc structure + * out: +* not 0 - failed + * 0 - success + */ +static int +acpi_snc_attach(struct acpi_sony_softc *sc) +{ + int i; + int tst; + ACPI_HANDLE tst_handle; + + /* adding oids */ + for (i = 0 ; acpi_snc_oids[i].nodename != NULL; i++){ + + /* skip if SNC not supports get method */ + if (ACPI_FAILURE(acpi_GetInteger(sc->handle, + acpi_snc_oids[i].getmethod, &tst))) + continue; + + /* skip if SNC not supports set method */ + if (acpi_snc_oids[i].setmethod && + ACPI_FAILURE(acpi_GetHandleInScope(sc->handle, + acpi_snc_oids[i].setmethod, &tst_handle))) + continue; + + SYSCTL_ADD_PROC(&(sc->sysctl_ctx), + SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, acpi_snc_oids[i].nodename, + CTLTYPE_INT | ((acpi_snc_oids[i].setmethod != NULL) ? + CTLFLAG_RW : CTLFLAG_RD), + sc->dev, i, acpi_snc_sysctl, "I", + acpi_snc_oids[i].comment); + } + + /* initialize special machine types (C, FZ, etc) */ + + if (ACPI_SUCCESS(acpi_GetHandleInScope(sc->handle, + "SN02", &tst_handle))) + { + /* seems model has needed methods */ + if ( ACPI_FAILED(acpi_SetInteger(sc->handle, "SN02", 0x4)) || + ACPI_FAILED(acpi_SetInteger(sc->handle, "SN07", 0x2))|| + ACPI_FAILED(acpi_SetInteger(sc->handle, "SN02", 0x10)) || + ACPI_FAILED(acpi_SetInteger(sc->handle, "SN07", 0x0)) || + ACPI_FAILED(acpi_SetInteger(sc->handle, "SN03", 0x2)) || + ACPI_FAILED(acpi_SetInteger(sc->handle, "SN07", 0x101))) + { + device_printf(sc->dev, "failed to perform additional initialization\n");; + } + } + + AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, + acpi_snc_notify_handler, sc); + + return (0); +} + +/* acpi_snc_sysctl() - called when needed to set or get + * values for SNC oids + * in: + * SYSCTL_HANDLER_ARGS +* out: + * 0 - success + * not 0 - some error + */ +static int +acpi_snc_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = arg1; + int function = oidp->oid_arg2; + int error = 0, val; + + acpi_GetInteger(acpi_get_handle(dev), + acpi_snc_oids[function].getmethod, &val); + + error = sysctl_handle_int(oidp, &val, 0, req); + + if (error || !req->newptr || !acpi_snc_oids[function].setmethod) + return (error); + + acpi_SetInteger(acpi_get_handle(dev), + acpi_snc_oids[function].setmethod, val); + + return (0); +} + +static int +acpi_snc_setinteger(acpi_sony_softc *sc, char* method, int32_t val, int32_t result) +{ + ACPI_OBJECT_LIST params; + ACPI_OBJECT in_obj; + ACPI_BUFFER output; + ACPI_OBJECT out_obj; + ACPI_STATUS status; + + params.Count = 1; + params.Pointer = &in_obj; + + in_obj.Type = ACPI_TYPE_INTEGER; + in_obj.Integer.Value = val; + + output.Length = sizeof(out_obj); + output.Pointer = &out_obj; + + status = AcpiEvaluateObject(handle, method, ¶ms, &output); + + if (status == AE_OK) { + if (result != NULL) { + if (out_obj.type != ACPI_TYPE_INTEGER) { + device_printf(sc->dev, "method returned gibberish\n"); + return (0); + } + + *result = out_obj.integer.value; + } + return (1); + } + + device_printf(sc->dev, "evaluation failed\n"); + + return (0); +} + +static void +acpi_snc_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context) +{ + ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); + + struct acpi_sony_softc *sc = context; + + if (notify == 0x92) { + if (ACPI_FAILURE(acpi_SetInteger(handle, "SN07", 0x0202))) + device_printf(sc->dev, "unable to decode event 0x%.2x\n", notify); + else {} + /* ev = result & 0xFF; */ + } + +} + +/* + * Common + */ + +/* acpi_sony_probe() - probing for device + * in: + * dev - probed device +* out: + * 0 - wanna attach + * <0 - some error + */ +static int +acpi_sony_probe(device_t dev) +{ + struct acpi_sony_softc *sc; + + sc = device_get_softc(dev); + + if (acpi_disabled("sony") || device_get_unit(dev) > 1) + return (ENXIO); + + if (ACPI_ID_PROBE(device_get_parent(dev), dev, sony_snc_id)) { + device_set_desc(dev, "Sony notebook controller"); + return (0); + } + + if (ACPI_ID_PROBE(device_get_parent(dev), dev, sony_spic_id)) { + device_set_desc(dev, "Sony Programable I/O controller"); + return (0); + } + + return (ENXIO); +} + +/* acpi_sony_attach() - attaches driver to device + * in: + * dev - device to attach to +* out: + * 0 - all is ok + * <0 - some error + */ +static int +acpi_sony_attach(device_t dev) +{ + struct acpi_sony_softc *sc; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + sc = device_get_softc(dev); + bzero(sc, sizeof(struct acpi_sony_softc)); + sc->dev = dev; + sc->handle = acpi_get_handle(sc->dev); + + if (ACPI_ID_PROBE(device_get_parent(dev), dev, sony_spic_id)) { + sc->is_spic = 1; + } + + ACPI_SERIAL_BEGIN(sony); + + /* sc->sysctl_ctx = device_get_sysctl_ctx(dev); */ + sysctl_ctx_init(&(sc->sysctl_ctx)); + sc->sysctl_tree = SYSCTL_ADD_NODE( &(sc->sysctl_ctx), SYSCTL_STATIC_CHILDREN(_hw), + OID_AUTO, "vaio", CTLFLAG_RW, 0, "VAIO notebook control"); + + //sc->sysctl_tree = device_get_sysctl_tree(dev); + + if (sc->is_spic == 0) { /* attaching SNC driver */ + acpi_snc_attach(sc); + } else { /* attaching SPIC driver */ + acpi_spic_attach(sc); + } + + ACPI_SERIAL_END(sony); + + return (0); +} + +/* acpi_sony_detach() - detaches from device + * in: + * dev - device to detach from +* out: + * 0 - wanna attach + * <0 - some error + */ +static int +acpi_sony_detach(device_t dev) +{ + struct acpi_sony_softc *sc; + + sc = device_get_softc(dev); + + if (sc->is_spic == 0) { + AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, acpi_snc_notify_handler); + } else { + + acpi_spic_call2(sc, 0x81, 0); /* disabling events */ + + acpi_spic_dis(sc); /* disabling device */ + +#ifdef ACPI_SONY_VERBOSE + acpi_spic_crs(sc); +#endif + + if (sc->intr_res != NULL) { + bus_teardown_intr(sc->dev, sc->intr_res, sc->icookie); + + bus_release_resource(dev, SYS_RES_IRQ, + sc->intr_rid, sc->intr_res); + } + + if (sc->port_res != NULL) + bus_release_resource(dev, SYS_RES_IOPORT, + sc->port_rid, sc->port_res); + + // destroy_dev(&spic_cdevsw); + } + + sysctl_ctx_free(&(sc->sysctl_ctx)); + + return (0); +} Index: user/sbruno/pxe_http/acpi_sony/acpi_sony.h =================================================================== --- user/sbruno/pxe_http/acpi_sony/acpi_sony.h (nonexistent) +++ user/sbruno/pxe_http/acpi_sony/acpi_sony.h (revision 245442) @@ -0,0 +1,635 @@ +/* + * ACPI Sony Programmable I/O Control Device and + * Sony Notebook Controller driver for VAIO + * + * based on: + * - sony-laptop - Linux driver for Sony notebooks + * http://www.linux.it/~malattia/wiki/index.php/Sony-laptop + * - acpi_sony - older SNC driver for FreeBSD + * - spic - older SPIC driver for FreeBSD + */ + +#ifndef _ACPI_SONY_H_ +#define _ACPI_SONY_H_ + +#include +#include + +#include +#include +#include + +#define ACPI_SONY_VERBOSE + +enum SPIC_TYPE { + SPIC_TYPE1 = 0, + SPIC_TYPE2 = 1, + SPIC_TYPE3 = 2, + SPIC_TYPE4 = 3, + SPIC_ALL_TYPES = 4 +}; + +/* event codes, almost the same as in sony-laptop */ +#define SPIC_EVENT_NONE 255 +#define SPIC_EVENT_JOGDIAL_DOWN 1 +#define SPIC_EVENT_JOGDIAL_UP 2 +#define SPIC_EVENT_JOGDIAL_DOWN_PRESSED 3 +#define SPIC_EVENT_JOGDIAL_UP_PRESSED 4 +#define SPIC_EVENT_JOGDIAL_PRESSED 5 +#define SPIC_EVENT_JOGDIAL_RELEASED 6 +#define SPIC_EVENT_CAPTURE_PRESSED 7 +#define SPIC_EVENT_CAPTURE_RELEASED 8 +#define SPIC_EVENT_CAPTURE_PARTIALPRESSED 9 +#define SPIC_EVENT_CAPTURE_PARTIALRELEASED 10 +#define SPIC_EVENT_FNKEY_ESC 11 +#define SPIC_EVENT_FNKEY_F1 12 +#define SPIC_EVENT_FNKEY_F2 13 +#define SPIC_EVENT_FNKEY_F3 14 +#define SPIC_EVENT_FNKEY_F4 15 +#define SPIC_EVENT_FNKEY_F5 16 +#define SPIC_EVENT_FNKEY_F6 17 +#define SPIC_EVENT_FNKEY_F7 18 +#define SPIC_EVENT_FNKEY_F8 19 +#define SPIC_EVENT_FNKEY_F9 20 +#define SPIC_EVENT_FNKEY_F10 21 +#define SPIC_EVENT_FNKEY_F11 22 +#define SPIC_EVENT_FNKEY_F12 23 +#define SPIC_EVENT_FNKEY_1 24 +#define SPIC_EVENT_FNKEY_2 25 +#define SPIC_EVENT_FNKEY_D 26 +#define SPIC_EVENT_FNKEY_E 27 +#define SPIC_EVENT_FNKEY_F 28 +#define SPIC_EVENT_FNKEY_S 29 +#define SPIC_EVENT_FNKEY_B 30 +#define SPIC_EVENT_BLUETOOTH_PRESSED 31 +#define SPIC_EVENT_PKEY_P1 32 +#define SPIC_EVENT_PKEY_P2 33 +#define SPIC_EVENT_PKEY_P3 34 +#define SPIC_EVENT_BACK_PRESSED 35 +#define SPIC_EVENT_LID_CLOSED 36 +#define SPIC_EVENT_LID_OPENED 37 +#define SPIC_EVENT_BLUETOOTH_ON 38 +#define SPIC_EVENT_BLUETOOTH_OFF 39 +#define SPIC_EVENT_HELP_PRESSED 40 +#define SPIC_EVENT_FNKEY_ONLY 41 +#define SPIC_EVENT_JOGDIAL_FAST_DOWN 42 +#define SPIC_EVENT_JOGDIAL_FAST_UP 43 +#define SPIC_EVENT_JOGDIAL_FAST_DOWN_PRESSED 44 +#define SPIC_EVENT_JOGDIAL_FAST_UP_PRESSED 45 +#define SPIC_EVENT_JOGDIAL_VFAST_DOWN 46 +#define SPIC_EVENT_JOGDIAL_VFAST_UP 47 +#define SPIC_EVENT_JOGDIAL_VFAST_DOWN_PRESSED 48 +#define SPIC_EVENT_JOGDIAL_VFAST_UP_PRESSED 49 +#define SPIC_EVENT_ZOOM_PRESSED 50 +#define SPIC_EVENT_ZOOM_IN_PRESSED 51 +#define SPIC_EVENT_ZOOM_OUT_PRESSED 52 +#define SPIC_EVENT_THUMBPHRASE_PRESSED 53 +#define SPIC_EVENT_MEYE_FACE 54 +#define SPIC_EVENT_MEYE_OPPOSITE 55 +#define SPIC_EVENT_MEMORYSTICK_INSERT 56 +#define SPIC_EVENT_MEMORYSTICK_EJECT 57 +#define SPIC_EVENT_ANYBUTTON_RELEASED 58 +#define SPIC_EVENT_BATTERY_INSERT 59 +#define SPIC_EVENT_BATTERY_REMOVE 60 +#define SPIC_EVENT_FNKEY_RELEASED 61 +#define SPIC_EVENT_WIRELESS_ON 62 +#define SPIC_EVENT_WIRELESS_OFF 63 +#define SPIC_EVENT_TOGGLE_SPEED 64 +#define SPIC_EVENT_TOGGLE_STAMINA 65 + +/* definitions of some additional methods */ +#define ACPI_SONY_METHOD_FAN 0x0000 +#define ACPI_SONY_METHOD_CAMERA_POWER 0x0001 +#define ACPI_SONY_METHOD_BLUETOOTH_POWER 0x0002 +#define ACPI_SONY_METHOD_WWAN_POWER 0x0003 + +/* EC data offset to fan level */ +#define SONY_EC_FANSPEED 0x93 + +/* PCI vendor definitions, used to determiny SPIC type model */ +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 +#define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 +#define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 +#define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 + +/* used to define entries for SPIC type detection */ +#define SPIC_PCIID(_vid, _did, _type) \ + { \ + .vid = PCI_VENDOR_ID_ ## _vid, \ + .did = PCI_DEVICE_ID_ ## _did, \ + .type = _type \ + } + +#define SPIC_PCIID_END() \ + { \ + .vid = 0, \ + .did = 0, \ + .type = 0 \ + } + +struct spic_pciid { + uint16_t vid; + uint16_t did; + enum SPIC_TYPE type; +}; + +const struct spic_pciid spic_pciids[] = +{ + SPIC_PCIID(INTEL, INTEL_82371AB_3, SPIC_TYPE1), + SPIC_PCIID(INTEL, INTEL_ICH6_1, SPIC_TYPE3), + SPIC_PCIID(INTEL, INTEL_ICH7_1, SPIC_TYPE4), + SPIC_PCIID(INTEL, INTEL_ICH8_4, SPIC_TYPE4), + + SPIC_PCIID_END() +}; + +/* mapping from SPIC code to event code */ +struct spic_event { + uint8_t code; /* code, returned by SPIC */ + uint8_t event; /* one of SPIC_EVENT_... */ +}; + +struct acpi_sony_softc; +struct spic_event_group; + +/* event handler for events */ +typedef int (*acpi_sony_event_handler_t)(struct acpi_sony_softc *sc, struct spic_event_group *group, + uint8_t mask, uint8_t event); + +/* default handler for events */ +static int acpi_spic_default_handler(struct acpi_sony_softc *sc, struct spic_event_group *group, + uint8_t mask, uint8_t event); + +/* defines group of events by event mask */ +struct spic_event_group { + uint8_t mask; /* event mask */ + struct spic_event *events; /* pointer to definition of events */ + acpi_sony_event_handler_t handler; /* optional handler of event */ +}; + +/* used to define event group */ +#define SPIC_EVENT_GROUP(_mask, _events, _handler) \ + { \ + .handler = _handler, \ + .mask = _mask, \ + .events = _events \ + } + +/* marker of groups definition end */ +#define SPIC_END_GROUP() \ + { \ + .handler = NULL, \ + .mask = 0, \ + .events = 0 \ + } + +/* used to define code <-> event mappings */ +#define SPIC_EVENT(_code, _event) \ + { \ + .code = _code, \ + .event = SPIC_EVENT_##_event \ + } + +/* marker of events description end */ +#define SPIC_END_EVENTS() \ + { \ + .code = 0, \ + .event = 0 \ + } + + +/* NOTE: + * event's codes and masks MUST BE in ascending order + */ + +/* button release events */ +const struct spic_event release_ev[] = { + SPIC_EVENT(0x00, ANYBUTTON_RELEASED), + + SPIC_END_EVENTS() +}; + +/* jogddial events */ +const struct spic_event jogdial_ev[] = { + SPIC_EVENT(0x01, JOGDIAL_DOWN), + SPIC_EVENT(0x02, JOGDIAL_FAST_DOWN), + SPIC_EVENT(0x03, JOGDIAL_VFAST_DOWN), + + SPIC_EVENT(0x1d, JOGDIAL_VFAST_UP), + SPIC_EVENT(0x1e, JOGDIAL_FAST_UP), + SPIC_EVENT(0x1f, JOGDIAL_UP), + + SPIC_EVENT(0x40, JOGDIAL_PRESSED), + + SPIC_EVENT(0x41, JOGDIAL_DOWN_PRESSED), + SPIC_EVENT(0x42, JOGDIAL_FAST_DOWN_PRESSED), + SPIC_EVENT(0x43, JOGDIAL_VFAST_DOWN_PRESSED), + + SPIC_EVENT(0x5d, JOGDIAL_VFAST_UP_PRESSED), + SPIC_EVENT(0x5e, JOGDIAL_FAST_UP_PRESSED), + SPIC_EVENT(0x5f, JOGDIAL_UP_PRESSED), + + SPIC_END_EVENTS() +}; + +/* capture button events */ +const struct spic_event capture_ev[] = { + SPIC_EVENT(0x01, CAPTURE_PARTIALRELEASED), + SPIC_EVENT(0x05, CAPTURE_PARTIALPRESSED), + SPIC_EVENT(0x07, CAPTURE_PRESSED), + SPIC_EVENT(0x40, CAPTURE_PRESSED), + + SPIC_END_EVENTS() +}; + +/* Fn keys events */ +const struct spic_event fnkey_ev[] = { + SPIC_EVENT(0x10, FNKEY_ESC), + SPIC_EVENT(0x11, FNKEY_F1), + SPIC_EVENT(0x12, FNKEY_F2), + SPIC_EVENT(0x13, FNKEY_F3), + SPIC_EVENT(0x14, FNKEY_F4), + SPIC_EVENT(0x15, FNKEY_F5), + SPIC_EVENT(0x16, FNKEY_F6), + SPIC_EVENT(0x17, FNKEY_F7), + SPIC_EVENT(0x18, FNKEY_F8), + SPIC_EVENT(0x19, FNKEY_F9), + SPIC_EVENT(0x1a, FNKEY_F10), + SPIC_EVENT(0x1b, FNKEY_F11), + SPIC_EVENT(0x1c, FNKEY_F12), + SPIC_EVENT(0x1f, FNKEY_RELEASED), + SPIC_EVENT(0x21, FNKEY_1), + SPIC_EVENT(0x22, FNKEY_2), + SPIC_EVENT(0x31, FNKEY_D), + SPIC_EVENT(0x32, FNKEY_E), + SPIC_EVENT(0x33, FNKEY_F), + SPIC_EVENT(0x34, FNKEY_S), + SPIC_EVENT(0x35, FNKEY_B), + SPIC_EVENT(0x36, FNKEY_ONLY), + + SPIC_END_EVENTS() +}; + +/* program key events */ +const struct spic_event pkey_ev[] = { + SPIC_EVENT(0x01, PKEY_P1), + SPIC_EVENT(0x02, PKEY_P2), + SPIC_EVENT(0x03, TOGGLE_STAMINA), + SPIC_EVENT(0x04, PKEY_P3), + + SPIC_END_EVENTS() +}; + +/* bluetooth events */ +const struct spic_event bluetooth_ev[] = { + SPIC_EVENT(0x55, BLUETOOTH_PRESSED), + SPIC_EVENT(0x59, BLUETOOTH_ON), + SPIC_EVENT(0x5a, BLUETOOTH_OFF), + + SPIC_END_EVENTS() +}; + +/* wireless events */ +const struct spic_event wireless_ev[] = { + SPIC_EVENT(0x59, WIRELESS_ON), + SPIC_EVENT(0x5a, WIRELESS_OFF), + + SPIC_END_EVENTS() +}; + +/* back button events */ +const struct spic_event back_ev[] = { + SPIC_EVENT(0x20, BACK_PRESSED), + + SPIC_END_EVENTS() +}; + +/* help button events */ +const struct spic_event help_ev[] = { + SPIC_EVENT(0x3b, HELP_PRESSED), + + SPIC_END_EVENTS() +}; + +/* lid events */ +const struct spic_event lid_ev[] = { + SPIC_EVENT(0x50, LID_OPENED), + SPIC_EVENT(0x51, LID_CLOSED), + + SPIC_END_EVENTS() +}; + +/* zoom events */ +const struct spic_event zoom_ev[] = { + SPIC_EVENT(0x10, ZOOM_IN_PRESSED), + SPIC_EVENT(0x20, ZOOM_OUT_PRESSED), + SPIC_EVENT(0x39, ZOOM_PRESSED), + + SPIC_END_EVENTS() +}; + +/* thumbphrase events */ +const struct spic_event thumbphrase_ev[] = { + SPIC_EVENT(0x3a, THUMBPHRASE_PRESSED), + + SPIC_END_EVENTS() +}; + +/* motioneye camera events */ +const struct spic_event meye_ev[] = { + SPIC_EVENT(0x00, MEYE_FACE), + SPIC_EVENT(0x01, MEYE_OPPOSITE), + + SPIC_END_EVENTS() +}; + +/* memorystick events */ +const struct spic_event memorystick_ev[] = { + SPIC_EVENT(0x53, MEMORYSTICK_INSERT), + SPIC_EVENT(0x54, MEMORYSTICK_EJECT), + + SPIC_END_EVENTS() +}; + +/* battery events */ +const struct spic_event battery_ev[] = { + SPIC_EVENT(0x20, BATTERY_INSERT), + SPIC_EVENT(0x30, BATTERY_REMOVE), + + SPIC_END_EVENTS() +}; + +/* type4 extra events */ +const struct spic_event type4_extra_ev[] = { + SPIC_EVENT(0x5c, NONE), + SPIC_EVENT(0x5f, NONE), + SPIC_EVENT(0x61, NONE), + SPIC_END_EVENTS() +}; + +/* type4 extra event handler */ +static int acpi_spic4_extra_handler(struct acpi_sony_softc *sc, + struct spic_event_group *group, uint8_t mask, uint8_t event); + +/* type4 extra event handler */ +static int acpi_spic4_pkey_handler(struct acpi_sony_softc *sc, + struct spic_event_group *group, uint8_t mask, uint8_t event); + +/* type1 event groups */ +const struct spic_event_group spic_type1_events[] = { + SPIC_EVENT_GROUP(0x00, release_ev, NULL), + SPIC_EVENT_GROUP(0x10, jogdial_ev, NULL), + SPIC_EVENT_GROUP(0x20, fnkey_ev, NULL), + SPIC_EVENT_GROUP(0x30, bluetooth_ev, NULL), + SPIC_EVENT_GROUP(0x30, lid_ev, NULL), + SPIC_EVENT_GROUP(0x30, memorystick_ev, NULL), + SPIC_EVENT_GROUP(0x40, pkey_ev, NULL), + SPIC_EVENT_GROUP(0x40, battery_ev, NULL), + SPIC_EVENT_GROUP(0x60, capture_ev, NULL), + SPIC_EVENT_GROUP(0x70, meye_ev, NULL), + + SPIC_END_GROUP() +}; + +/* type2 event groups */ +const struct spic_event_group spic_type2_events[] = { + SPIC_EVENT_GROUP(0x00, release_ev, NULL), + SPIC_EVENT_GROUP(0x08, pkey_ev, NULL), + SPIC_EVENT_GROUP(0x11, jogdial_ev, NULL), + SPIC_EVENT_GROUP(0x11, back_ev, NULL), + SPIC_EVENT_GROUP(0x20, thumbphrase_ev, NULL), + SPIC_EVENT_GROUP(0x21, fnkey_ev, NULL), + SPIC_EVENT_GROUP(0x21, help_ev, NULL), + SPIC_EVENT_GROUP(0x21, zoom_ev, NULL), + SPIC_EVENT_GROUP(0x31, bluetooth_ev, NULL), + SPIC_EVENT_GROUP(0x31, pkey_ev, NULL), + SPIC_EVENT_GROUP(0x31, memorystick_ev, NULL), + SPIC_EVENT_GROUP(0x38, lid_ev, NULL), + SPIC_EVENT_GROUP(0x41, battery_ev, NULL), + SPIC_EVENT_GROUP(0x61, capture_ev, NULL), + + SPIC_END_GROUP() +}; + +/* type3 event groups */ +const struct spic_event_group spic_type3_events[] = { + SPIC_EVENT_GROUP(0x00, release_ev, NULL), + SPIC_EVENT_GROUP(0x21, fnkey_ev, NULL), + SPIC_EVENT_GROUP(0x31, pkey_ev, NULL), + SPIC_EVENT_GROUP(0x31, wireless_ev, NULL), + SPIC_EVENT_GROUP(0x31, memorystick_ev, NULL), + SPIC_EVENT_GROUP(0x41, battery_ev, NULL), + + SPIC_END_GROUP() +}; + +/* type4 event groups */ +const struct spic_event_group spic_type4_events[] = { + SPIC_EVENT_GROUP(0x00, release_ev, NULL), + SPIC_EVENT_GROUP(0x05, pkey_ev, acpi_spic4_pkey_handler), + SPIC_EVENT_GROUP(0x05, zoom_ev, NULL), + SPIC_EVENT_GROUP(0x05, capture_ev, NULL), + SPIC_EVENT_GROUP(0x21, fnkey_ev, NULL), + SPIC_EVENT_GROUP(0x31, wireless_ev, NULL), + SPIC_EVENT_GROUP(0x31, memorystick_ev, NULL), + SPIC_EVENT_GROUP(0x31, type4_extra_ev, acpi_spic4_extra_handler), + SPIC_EVENT_GROUP(0x41, battery_ev, NULL), + + SPIC_END_GROUP() +}; + +const struct { + uint16_t evport_offset; + struct spic_event_group *events; +} spic_types[SPIC_ALL_TYPES] = { + { 0x04, spic_type1_events }, + { 0x12, spic_type2_events }, + { 0x12, spic_type3_events }, + { 0x12, spic_type4_events } +}; + +/* used to define SNC oids */ +#define SNC_OID(_get, _set, _name, _descript) \ + { \ + .nodename = _name, \ + .getmethod = _get, \ + .setmethod = _set, \ + .comment = _descript \ + } + +/* ACPI Methods, for which oids may be created */ +const struct { + char *nodename; + char *getmethod; + char *setmethod; + char *comment; +} acpi_snc_oids[] = { + SNC_OID("GBRT", "SBRT", "brightness", "Display brightness"), + SNC_OID("GPBR", "SPBR", "def_brightness", "Display default brightness"), + SNC_OID("GCTR", "SCTR", "contrast", "Display contrast"), + SNC_OID("GPCR", "SPCR", "def_contrast", "Display default contrast"), + SNC_OID("GAZP", "AZPW", "power_audio", "Audio device power"), + SNC_OID("GLNP", "LNPW", "power_lan", "Ethernet device power"), + SNC_OID("GWDP", NULL, "power_wlan", "Wireless device power"), + SNC_OID("GCDP", "CDPW", "power_cd", "CD power"), + SNC_OID("GCDP", "SCDP", "power_cd", "CD power"), /* alternative combination */ + SNC_OID("GLID", NULL, "lid_status", "LID status"), + SNC_OID("GHKE", NULL, "hot_key", "Hot key status"), + SNC_OID("GILS", "SILS", "indicator", "Lamp indicator status"), + SNC_OID("GMCB", "CMGB", "gain_bass", "Gain bass"), + SNC_OID("GPID", NULL, "processor_id", "Processor id (if applicable)"), + /* experimental */ + + /* end of table */ + { NULL, NULL, NULL, NULL } +}; + +/* used to define SPIC oids */ +#define SPIC_OID(_name, _method, _flags, _descript) \ + { \ + .name = _name, \ + .method = ACPI_SONY_METHOD_##_method, \ + .access = _flags, \ + .comment = _descript \ + } + +/* additional oids */ +const struct { + char *name; + int method; + int access; + char *comment; +} acpi_spic_oids[] = { + SPIC_OID("fan_speed", FAN, CTLTYPE_INT | CTLFLAG_RW, "Fan speed"), + SPIC_OID("power_bluetooth", BLUETOOTH_POWER, CTLTYPE_INT | CTLFLAG_RW, "Bluetooth power state"), + + { NULL, 0, 0, NULL } +}; + +/* driver structure for device */ +struct acpi_sony_softc { + + /* device and it's ACPI handle */ + device_t dev; + ACPI_HANDLE handle; + + /* embedded controller and it's ACPI handle*/ + device_t ec_dev; + ACPI_HANDLE ec_handle; + + /* 1 if device is SPIC*/ + int is_spic; + + // SPIC related only + enum SPIC_TYPE model; + uint16_t evport_offset; + struct spic_event_group *events; + + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + + uint8_t power_bluetooth; + + uint8_t prev_event; + /* start of IO ports range */ + uint16_t port_addr; + /* IRQ */ + uint8_t intr; + uint8_t open_count; + + /* resource allocation related */ + struct resource *port_res; /* IO ports resource */ + struct resource *intr_res; /* IRQ resource */ + int port_rid; /* IO ports resource id */ + int intr_rid; /* IRQ resource id */ + + void *icookie; /* coockie for interrupt */ + + /* Received via ACPI walking resources */ + ACPI_RESOURCE_IO io; + ACPI_RESOURCE_IRQ interrupt; + }; + +#define SPIC_DESCRIPT(event) \ + { \ + .code = SPIC_EVENT_ ## event, \ + .name = #event, \ + } + +#ifdef ACPI_SONY_VERBOSE +const struct { + uint8_t code; + char *name; +} event_descriptors[] = +{ + SPIC_DESCRIPT(JOGDIAL_DOWN), + SPIC_DESCRIPT(JOGDIAL_UP), + SPIC_DESCRIPT(JOGDIAL_DOWN_PRESSED), + SPIC_DESCRIPT(JOGDIAL_UP_PRESSED), + SPIC_DESCRIPT(JOGDIAL_PRESSED), + SPIC_DESCRIPT(JOGDIAL_RELEASED), + SPIC_DESCRIPT(CAPTURE_PRESSED), + SPIC_DESCRIPT(CAPTURE_RELEASED), + SPIC_DESCRIPT(CAPTURE_PARTIALPRESSED), + SPIC_DESCRIPT(CAPTURE_PARTIALRELEASED), + SPIC_DESCRIPT(FNKEY_ESC), + SPIC_DESCRIPT(FNKEY_F1), + SPIC_DESCRIPT(FNKEY_F2), + SPIC_DESCRIPT(FNKEY_F3), + SPIC_DESCRIPT(FNKEY_F4), + SPIC_DESCRIPT(FNKEY_F5), + SPIC_DESCRIPT(FNKEY_F6), + SPIC_DESCRIPT(FNKEY_F7), + SPIC_DESCRIPT(FNKEY_F8), + SPIC_DESCRIPT(FNKEY_F9), + SPIC_DESCRIPT(FNKEY_F10), + SPIC_DESCRIPT(FNKEY_F11), + SPIC_DESCRIPT(FNKEY_F12), + SPIC_DESCRIPT(FNKEY_1), + SPIC_DESCRIPT(FNKEY_2), + SPIC_DESCRIPT(FNKEY_D), + SPIC_DESCRIPT(FNKEY_E), + SPIC_DESCRIPT(FNKEY_F), + SPIC_DESCRIPT(FNKEY_S), + SPIC_DESCRIPT(FNKEY_B), + SPIC_DESCRIPT(BLUETOOTH_PRESSED), + SPIC_DESCRIPT(PKEY_P1), + SPIC_DESCRIPT(PKEY_P2), + SPIC_DESCRIPT(PKEY_P3), + SPIC_DESCRIPT(BACK_PRESSED), + SPIC_DESCRIPT(LID_CLOSED), + SPIC_DESCRIPT(LID_OPENED), + SPIC_DESCRIPT(BLUETOOTH_ON), + SPIC_DESCRIPT(BLUETOOTH_OFF), + SPIC_DESCRIPT(HELP_PRESSED), + SPIC_DESCRIPT(FNKEY_ONLY), + SPIC_DESCRIPT(JOGDIAL_FAST_DOWN), + SPIC_DESCRIPT(JOGDIAL_FAST_UP), + SPIC_DESCRIPT(JOGDIAL_FAST_DOWN_PRESSED), + SPIC_DESCRIPT(JOGDIAL_FAST_UP_PRESSED), + SPIC_DESCRIPT(JOGDIAL_VFAST_DOWN), + SPIC_DESCRIPT(JOGDIAL_VFAST_UP), + SPIC_DESCRIPT(JOGDIAL_VFAST_DOWN_PRESSED), + SPIC_DESCRIPT(JOGDIAL_VFAST_UP_PRESSED), + SPIC_DESCRIPT(ZOOM_PRESSED), + SPIC_DESCRIPT(ZOOM_IN_PRESSED), + SPIC_DESCRIPT(ZOOM_OUT_PRESSED), + SPIC_DESCRIPT(THUMBPHRASE_PRESSED), + SPIC_DESCRIPT(MEYE_FACE), + SPIC_DESCRIPT(MEYE_OPPOSITE), + SPIC_DESCRIPT(MEMORYSTICK_INSERT), + SPIC_DESCRIPT(MEMORYSTICK_EJECT), + SPIC_DESCRIPT(ANYBUTTON_RELEASED), + SPIC_DESCRIPT(BATTERY_INSERT), + SPIC_DESCRIPT(BATTERY_REMOVE), + SPIC_DESCRIPT(FNKEY_RELEASED), + SPIC_DESCRIPT(WIRELESS_ON), + SPIC_DESCRIPT(WIRELESS_OFF), + SPIC_DESCRIPT(TOGGLE_SPEED), + SPIC_DESCRIPT(TOGGLE_STAMINA) +}; + +#endif + +#endif /* _ACPI_SONY_H_ */ Index: user/sbruno/pxe_http/btx_mod/Makefile =================================================================== --- user/sbruno/pxe_http/btx_mod/Makefile (nonexistent) +++ user/sbruno/pxe_http/btx_mod/Makefile (revision 245442) @@ -0,0 +1,9 @@ +# $FreeBSD: src/sys/boot/i386/btx/lib/Makefile,v 1.13 2004/12/21 08:47:14 ru Exp $ + +PROG= crt0.o +INTERNALPROG= +NO_MAN= +SRCS= btxcsu.s btxsys.s btxv86.s +LDFLAGS=-Wl,-r + +.include Index: user/sbruno/pxe_http/btx_mod/Makefile.inc =================================================================== --- user/sbruno/pxe_http/btx_mod/Makefile.inc (nonexistent) +++ user/sbruno/pxe_http/btx_mod/Makefile.inc (revision 245442) @@ -0,0 +1,3 @@ +# $FreeBSD: src/sys/boot/i386/btx/Makefile.inc,v 1.2 2004/02/06 21:58:31 ru Exp $ + +.include "../Makefile.inc" Index: user/sbruno/pxe_http/btx_mod/btx/Makefile =================================================================== --- user/sbruno/pxe_http/btx_mod/btx/Makefile (nonexistent) +++ user/sbruno/pxe_http/btx_mod/btx/Makefile (revision 245442) @@ -0,0 +1,33 @@ +# $FreeBSD: src/sys/boot/i386/btx/btx/Makefile,v 1.19 2004/12/21 08:47:13 ru Exp $ + +PROG= btx +INTERNALPROG= +NO_MAN= +SRCS= btx.S + +.if defined(PAGING) +CFLAGS+=-DPAGING +.endif + +.if defined(BOOT_BTX_NOHANG) +BOOT_BTX_FLAGS=0x1 +.else +BOOT_BTX_FLAGS=0x0 +.endif + +CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS} + +.if defined(BTX_SERIAL) +BOOT_COMCONSOLE_PORT?= 0x3f8 +BOOT_COMCONSOLE_SPEED?= 9600 +B2SIOFMT?= 0x3 + +CFLAGS+=-DBTX_SERIAL -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ + -DSIOFMT=${B2SIOFMT} -DSIOSPD=${BOOT_COMCONSOLE_SPEED} +.endif + +ORG= 0x9000 + +LDFLAGS=-N -e start -Ttext ${ORG} -Wl,-S,--oformat,binary + +.include Index: user/sbruno/pxe_http/btx_mod/btx/btx.S =================================================================== --- user/sbruno/pxe_http/btx_mod/btx/btx.S (nonexistent) +++ user/sbruno/pxe_http/btx_mod/btx/btx.S (revision 245442) @@ -0,0 +1,1285 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD: src/sys/boot/i386/btx/btx/btx.S,v 1.38.2.2 2006/12/07 22:26:51 jhb Exp $ + */ + +/* + * Memory layout. + */ + .set MEM_BTX,0x1000 # Start of BTX memory + .set MEM_ESP0,0x1800 # Supervisor stack + .set MEM_BUF,0x1800 # Scratch buffer + .set MEM_ESP1,0x1e00 # Link stack + .set MEM_IDT,0x1e00 # IDT + .set MEM_TSS,0x1f98 # TSS + .set MEM_MAP,0x2000 # I/O bit map + .set MEM_DIR,0x4000 # Page directory + .set MEM_TBL,0x5000 # Page tables + .set MEM_ORG,0x9000 # BTX code + .set MEM_USR,0xa000 # Start of user memory +/* + * Paging control. + */ + .set PAG_SIZ,0x1000 # Page size + .set PAG_CNT,0x1000 # Pages to map +/* + * Segment selectors. + */ + .set SEL_SCODE,0x8 # Supervisor code + .set SEL_SDATA,0x10 # Supervisor data + .set SEL_RCODE,0x18 # Real mode code + .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_CALLGATE,0x40 # super2user callgate +/* + * Task state segment fields. + */ + .set TSS_ESP0,0x4 # PL 0 ESP + .set TSS_SS0,0x8 # PL 0 SS + .set TSS_ESP1,0xc # PL 1 ESP + .set TSS_MAP,0x66 # I/O bit map base +/* + * System calls. + */ + .set SYS_EXIT,0x0 # Exit + .set SYS_EXEC,0x1 # Exec + .set SYS_ISR_INSTALL,0x2 # ISR_install +/* + * V86 constants. + */ + .set V86_FLG,0x208eff # V86 flag mask + .set V86_STK,0x400 # V86 stack allowance +/* + * Dump format control bytes. + */ + .set DMP_X16,0x1 # Word + .set DMP_X32,0x2 # Long + .set DMP_MEM,0x4 # Memory + .set DMP_EOL,0x8 # End of line +/* + * Screen defaults and assumptions. + */ + .set SCR_MAT,0x7 # Mode/attribute + .set SCR_COL,0x50 # Columns per row + .set SCR_ROW,0x19 # Rows per screen +/* + * BIOS Data Area locations. + */ + .set BDA_MEM,0x413 # Free memory + .set BDA_KEYFLAGS,0x417 # Keyboard shift-state flags + .set BDA_SCR,0x449 # Video mode + .set BDA_POS,0x450 # Cursor position + .set BDA_BOOT,0x472 # Boot howto flag +/* + * Derivations, for brevity. + */ + .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0 + .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1 + .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base + .set _TSSLM,MEM_DIR-MEM_TSS-1 # TSS limit + .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit +/* + * Code segment. + */ + .globl start + .code16 +start: # Start of code +/* + * BTX header. + */ +btx_hdr: .byte 0xeb # Machine ID + .byte 0xe # Header size + .ascii "BTX" # Magic + .byte 0x1 # Major version + .byte 0x1 # Minor version + .byte BTX_FLAGS # Flags + .word PAG_CNT-MEM_ORG>>0xc # Paging control + .word break-start # Text size + .long 0x0 # Entry address +/* + * Initialization routine. + */ +init: cli # Disable interrupts + xor %ax,%ax # Zero/segment + mov %ax,%ss # Set up + mov $MEM_ESP0,%sp # stack + mov %ax,%es # Address + mov %ax,%ds # data + pushl $0x2 # Clear + popfl # flags +/* + * Initialize memory. + */ + mov $MEM_IDT,%di # Memory to initialize + mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero + push %di # Save + rep # Zero-fill + stosw # memory + pop %di # Restore +/* + * Create IDT. + */ + mov $idtctl,%si # Control string +init.1: lodsb # Get entry + cbw # count + xchg %ax,%cx # as word + jcxz init.4 # If done + lodsb # Get segment + xchg %ax,%dx # P:DPL:type + lodsw # Get control + xchg %ax,%bx # set + lodsw # Get handler offset + mov $SEL_SCODE,%dh # Segment selector +init.2: shr %bx # Handle this int? + jnc init.3 # No + mov %ax,(%di) # Set handler offset + mov %dh,0x2(%di) # and selector + mov %dl,0x5(%di) # Set P:DPL:type + add $0x4,%ax # Next handler +init.3: lea 0x8(%di),%di # Next entry + loop init.2 # Till set done + jmp init.1 # Continue +/* + * Initialize TSS. + */ +init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0 + movb $SEL_SDATA,TSS_SS0(%di) # Set SS0 + movb $_ESP1H,TSS_ESP1+1(%di) # Set ESP1 + movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base +#ifdef PAGING +/* + * Create page directory. + */ + xor %edx,%edx # Page + mov $PAG_SIZ>>0x8,%dh # size + xor %eax,%eax # Zero + mov $MEM_DIR,%di # Page directory + mov $PAG_CNT>>0xa,%cl # Entries + mov $MEM_TBL|0x7,%ax # First entry +init.5: stosl # Write entry + add %dx,%ax # To next + loop init.5 # Till done +/* + * Create page tables. + */ + mov $MEM_TBL,%di # Page table + mov $PAG_CNT>>0x8,%ch # Entries + xor %ax,%ax # Start address +init.6: mov $0x7,%al # Set U:W:P flags + cmp btx_hdr+0x8,%cx # Standard user page? + jb init.7 # Yes + cmp $PAG_CNT-MEM_BTX>>0xc,%cx # BTX memory? + jae init.7 # No or first page + and $~0x2,%al # Clear W flag + cmp $PAG_CNT-MEM_USR>>0xc,%cx # User page zero? + jne init.7 # No + testb $0x80,btx_hdr+0x7 # Unmap it? + jz init.7 # No + and $~0x1,%al # Clear P flag +init.7: stosl # Set entry + add %edx,%eax # Next address + loop init.6 # Till done +#endif +/* + * Bring up the system. + */ + mov $0x2820,%bx # Set protected mode + callw setpic # IRQ offsets + lidt idtdesc # Set IDT +#ifdef PAGING + xor %eax,%eax # Set base + mov $MEM_DIR>>0x8,%ah # of page + mov %eax,%cr3 # directory +#endif + lgdt gdtdesc # Set GDT + mov %cr0,%eax # Switch to protected +#ifdef PAGING + or $0x80000001,%eax # mode and enable paging +#else + inc %ax # mode +#endif + mov %eax,%cr0 # + ljmp $SEL_SCODE,$init.8 # To 32-bit code + .code32 +init.8: xorl %ecx,%ecx # Zero + movb $SEL_SDATA,%cl # To 32-bit + movw %cx,%ss # stack +/* + * Launch user task. + */ + movb $SEL_TSS,%cl # Set task + ltr %cx # register + movl $MEM_USR,%edx # User base address + movzwl %ss:BDA_MEM,%eax # Get free memory + shll $0xa,%eax # To bytes + subl $0x1000,%eax # Less arg space + subl %edx,%eax # Less base + movb $SEL_UDATA,%cl # User data selector + pushl %ecx # Set SS + pushl %eax # Set ESP + push $0x202 # Set flags (IF set) + push $SEL_UCODE # Set CS + pushl btx_hdr+0xc # Set EIP + pushl %ecx # Set GS + pushl %ecx # Set FS + pushl %ecx # Set DS + pushl %ecx # Set ES + pushl %edx # Set EAX + movb $0x7,%cl # Set remaining +init.9: push $0x0 # general + loop init.9 # registers +#ifdef BTX_SERIAL + call sio_init # setup the serial console +#endif + popa # and initialize + popl %es # Initialize + popl %ds # user + popl %fs # segment + popl %gs # registers + iret # To user mode +/* + * Exit routine. + */ +exit: cli # Disable interrupts + movl $MEM_ESP0,%esp # Clear stack +/* + * Turn off paging. + */ + movl %cr0,%eax # Get CR0 + andl $~0x80000000,%eax # Disable + movl %eax,%cr0 # paging + xorl %ecx,%ecx # Zero + movl %ecx,%cr3 # Flush TLB +/* + * Restore the GDT in case we caught a kernel trap. + */ + lgdt gdtdesc # Set GDT +/* + * To 16 bits. + */ + ljmpw $SEL_RCODE,$exit.1 # Reload CS + .code16 +exit.1: mov $SEL_RDATA,%cl # 16-bit selector + mov %cx,%ss # Reload SS + mov %cx,%ds # Load + mov %cx,%es # remaining + mov %cx,%fs # segment + mov %cx,%gs # registers +/* + * To real-address mode. + */ + dec %ax # Switch to + mov %eax,%cr0 # real mode + ljmp $0x0,$exit.2 # Reload CS +exit.2: xor %ax,%ax # Real mode segment + mov %ax,%ss # Reload SS + mov %ax,%ds # Address data + mov $0x7008,%bx # Set real mode + callw setpic # IRQ offsets + lidt ivtdesc # Set IVT +/* + * Reboot or await reset. + */ + sti # Enable interrupts + testb $0x1,btx_hdr+0x7 # Reboot? +exit.3: jz exit.3 # No + movw $0x1234, BDA_BOOT # Do a warm boot + ljmp $0xf000,$0xfff0 # reboot the machine +/* + * Set IRQ offsets by reprogramming 8259A PICs. + */ +setpic: in $0x21,%al # Save master + push %ax # IMR + in $0xa1,%al # Save slave + push %ax # IMR + movb $0x11,%al # ICW1 to + outb %al,$0x20 # master, + outb %al,$0xa0 # slave + movb %bl,%al # ICW2 to + outb %al,$0x21 # master + movb %bh,%al # ICW2 to + outb %al,$0xa1 # slave + movb $0x4,%al # ICW3 to + outb %al,$0x21 # master + movb $0x2,%al # ICW3 to + outb %al,$0xa1 # slave + movb $0x1,%al # ICW4 to + outb %al,$0x21 # master, + outb %al,$0xa1 # slave + pop %ax # Restore slave + outb %al,$0xa1 # IMR + pop %ax # Restore master + outb %al,$0x21 # IMR + retw # To caller + .code32 +/* + * Initiate return from V86 mode to user mode. + */ +inthlt: hlt # To supervisor mode +/* + * Exception jump table. + */ +intx00: push $0x0 # Int 0x0: #DE + jmp ex_noc # Divide error + push $0x1 # Int 0x1: #DB + jmp ex_noc # Debug + push $0x3 # Int 0x3: #BP + jmp ex_noc # Breakpoint + push $0x4 # Int 0x4: #OF + jmp ex_noc # Overflow + push $0x5 # Int 0x5: #BR + jmp ex_noc # BOUND range exceeded + push $0x6 # Int 0x6: #UD + jmp ex_noc # Invalid opcode + push $0x7 # Int 0x7: #NM + jmp ex_noc # Device not available + push $0x8 # Int 0x8: #DF + jmp except # Double fault + push $0xa # Int 0xa: #TS + jmp except # Invalid TSS + push $0xb # Int 0xb: #NP + jmp except # Segment not present + push $0xc # Int 0xc: #SS + jmp except # Stack segment fault + push $0xd # Int 0xd: #GP + jmp ex_v86 # General protection + push $0xe # Int 0xe: #PF + jmp except # Page fault +intx10: push $0x10 # Int 0x10: #MF + jmp ex_noc # Floating-point error +/* + * Handle #GP exception. + */ +ex_v86: testb $0x2,0x12(%esp,1) # V86 mode? + jz except # No + jmp v86mon # To monitor +/* + * Save a zero error code. + */ +ex_noc: pushl (%esp,1) # Duplicate int no + movb $0x0,0x4(%esp,1) # Fake error code +/* + * Handle exception. + */ +except: cld # String ops inc + pushl %ds # Save + pushl %es # most + pusha # registers + movb $0x6,%al # Push loop count + testb $0x2,0x3a(%esp,1) # V86 mode? + jnz except.1 # Yes + pushl %gs # Set GS + pushl %fs # Set FS + pushl %ds # Set DS + pushl %es # Set ES + movb $0x2,%al # Push loop count + cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode? + jne except.1 # No + pushl %ss # Set SS + leal 0x50(%esp,1),%eax # Set + pushl %eax # ESP + jmp except.2 # Join common code +except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES + decb %al # (if V86 mode), and + jne except.1 # SS, ESP +except.2: push $SEL_SDATA # Set up + popl %ds # to + pushl %ds # address + popl %es # data + movl %esp,%ebx # Stack frame + movl $dmpfmt,%esi # Dump format string + pushl %edi # Dump to + call dump # buffer + popl %esi # and + call putstr # display + leal 0x18(%esp,1),%esp # Discard frame + popa # Restore + popl %es # registers + popl %ds # saved + cmpb $0x3,(%esp,1) # Breakpoint? + je except.3 # Yes + cmpb $0x1,(%esp,1) # Debug? + jne except.2a # No + testl $0x100,0x10(%esp,1) # Trap flag set? + jnz except.3 # Yes +except.2a: jmp exit # Exit +except.3: leal 0x8(%esp,1),%esp # Discard err, int no + iret # From interrupt +/* + * Return to user mode from V86 mode. + */ +intrtn: cld # String ops inc + pushl %ds # Address + popl %es # data + leal 0x3c(%ebp),%edx # V86 Segment registers + movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer + lodsl # INT_V86 args pointer + movl %esi,%ebx # Saved exception frame + testl %eax,%eax # INT_V86 args? + jz intrtn.2 # No + movl $MEM_USR,%edi # User base + movl 0x1c(%esi),%ebx # User ESP + movl %eax,(%edi,%ebx,1) # Restore to user stack + leal 0x8(%edi,%eax,1),%edi # Arg segment registers + testb $0x4,-0x6(%edi) # Return flags? + jz intrtn.1 # No + movl 0x30(%ebp),%eax # Get V86 flags + movw %ax,0x18(%esi) # Set user flags +intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame + xchgl %edx,%esi # Segment registers + movb $0x4,%cl # Update seg regs + rep # in INT_V86 + movsl # args +intrtn.2: xchgl %edx,%esi # Segment registers + leal 0x28(%ebp),%edi # Set up seg + movb $0x4,%cl # regs for + rep # later + movsl # pop + xchgl %ebx,%esi # Restore exception + movb $0x5,%cl # frame to + rep # supervisor + movsl # stack + movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer + popa # Restore + leal 0x8(%esp,1),%esp # Discard err, int no + popl %es # Restore + popl %ds # user + popl %fs # segment + popl %gs # registers + iret # To user mode +/* + * V86 monitor. + */ +v86mon: cld # String ops inc + pushl $SEL_SDATA # Set up for + popl %ds # flat addressing + pusha # Save registers + movl %esp,%ebp # Address stack frame + movzwl 0x2c(%ebp),%edi # Load V86 CS + shll $0x4,%edi # To linear + movl 0x28(%ebp),%esi # Load V86 IP + addl %edi,%esi # Code pointer + xorl %ecx,%ecx # Zero + movb $0x2,%cl # 16-bit operands + xorl %eax,%eax # Zero +v86mon.1: lodsb # Get opcode + cmpb $0x66,%al # Operand size prefix? + jne v86mon.2 # No + movb $0x4,%cl # 32-bit operands + jmp v86mon.1 # Continue +v86mon.2: cmpb $0xf4,%al # HLT? + jne v86mon.3 # No + cmpl $inthlt+0x1,%esi # Is inthlt? + jne v86mon.7 # No (ignore) + jmp intrtn # Return to user mode +v86mon.3: cmpb $0xf,%al # Prefixed instruction? + jne v86mon.4 # No + cmpb $0x09,(%esi) # Is it a WBINVD? + je v86wbinvd # Yes + cmpb $0x30,(%esi) # Is it a WRMSR? + je v86wrmsr # Yes + cmpb $0x32,(%esi) # Is it a RDMSR? + je v86rdmsr # Yes + cmpb $0x20,(%esi) # Is this a MOV reg,CRx? + je v86mov # Yes +v86mon.4: cmpb $0xfa,%al # CLI? + je v86cli # Yes + cmpb $0xfb,%al # STI? + je v86sti # Yes + cmpb $0xcc,%al # INT3? + je v86mon.7 # Yes, ignore + movzwl 0x38(%ebp),%ebx # Load V86 SS + shll $0x4,%ebx # To offset + pushl %ebx # Save + addl 0x34(%ebp),%ebx # Add V86 SP + movl 0x30(%ebp),%edx # Load V86 flags + cmpb $0x9c,%al # PUSHF/PUSHFD? + je v86pushf # Yes + cmpb $0x9d,%al # POPF/POPFD? + je v86popf # Yes + cmpb $0xcd,%al # INT imm8? + je v86intn # Yes + cmpb $0xcf,%al # IRET/IRETD? + je v86iret # Yes + popl %ebx # Restore + popa # Restore + jmp except # Handle exception +v86mon.5: movl %edx,0x30(%ebp) # Save V86 flags +v86mon.6: popl %edx # V86 SS adjustment + subl %edx,%ebx # Save V86 + movl %ebx,0x34(%ebp) # SP +v86mon.7: subl %edi,%esi # From linear + movl %esi,0x28(%ebp) # Save V86 IP + popa # Restore + leal 0x8(%esp,1),%esp # Discard int no, error + iret # To V86 mode +/* + * Emulate MOV reg,CRx. + */ +v86mov: movb 0x1(%esi),%bl # Fetch Mod R/M byte + testb $0x10,%bl # Read CR2 or CR3? + jnz v86mov.1 # Yes + movl %cr0,%eax # Read CR0 + testb $0x20,%bl # Read CR4 instead? + jz v86mov.2 # No + movl %cr4,%eax # Read CR4 + jmp v86mov.2 +v86mov.1: movl %cr2,%eax # Read CR2 + testb $0x08,%bl # Read CR3 instead? + jz v86mov.2 # No + movl %cr3,%eax # Read CR3 +v86mov.2: andl $0x7,%ebx # Compute offset in + shl $2,%ebx # frame of destination + neg %ebx # register + movl %eax,0x1c(%ebp,%ebx,1) # Store CR to reg + incl %esi # Adjust IP +/* + * Return from emulating a 0x0f prefixed instruction + */ +v86preret: incl %esi # Adjust IP + jmp v86mon.7 # Finish up +/* + * Emulate WBINVD + */ +v86wbinvd: wbinvd # Write back and invalidate + # cache + jmp v86preret # Finish up +/* + * Emulate WRMSR + */ +v86wrmsr: movl 0x18(%ebp),%ecx # Get user's %ecx (MSR to write) + movl 0x14(%ebp),%edx # Load the value + movl 0x1c(%ebp),%eax # to write + wrmsr # Write MSR + jmp v86preret # Finish up +/* + * Emulate RDMSR + */ +v86rdmsr: movl 0x18(%ebp),%ecx # MSR to read + rdmsr # Read the MSR + movl %eax,0x1c(%ebp) # Return the value of + movl %edx,0x14(%ebp) # the MSR to the user + jmp v86preret # Finish up +/* + * Emulate CLI. + */ +v86cli: andb $~0x2,0x31(%ebp) # Clear IF + jmp v86mon.7 # Finish up +/* + * Emulate STI. + */ +v86sti: orb $0x2,0x31(%ebp) # Set IF + jmp v86mon.7 # Finish up +/* + * Emulate PUSHF/PUSHFD. + */ +v86pushf: subl %ecx,%ebx # Adjust SP + cmpb $0x4,%cl # 32-bit + je v86pushf.1 # Yes + data16 # 16-bit +v86pushf.1: movl %edx,(%ebx) # Save flags + jmp v86mon.6 # Finish up +/* + * Emulate IRET/IRETD. + */ +v86iret: movzwl (%ebx),%esi # Load V86 IP + movzwl 0x2(%ebx),%edi # Load V86 CS + leal 0x4(%ebx),%ebx # Adjust SP + movl %edi,0x2c(%ebp) # Save V86 CS + xorl %edi,%edi # No ESI adjustment +/* + * Emulate POPF/POPFD (and remainder of IRET/IRETD). + */ +v86popf: cmpb $0x4,%cl # 32-bit? + je v86popf.1 # Yes + movl %edx,%eax # Initialize + data16 # 16-bit +v86popf.1: movl (%ebx),%eax # Load flags + addl %ecx,%ebx # Adjust SP + andl $V86_FLG,%eax # Merge + andl $~V86_FLG,%edx # the + orl %eax,%edx # flags + jmp v86mon.5 # Finish up +/* + * trap int 15, function 87 + * reads %es:%si from saved registers on stack to find a GDT containing + * source and destination locations + * reads count of words from saved %cx + * returns success by setting %ah to 0 + */ +int15_87: pushl %esi # Save + pushl %edi # registers + movl 0x3C(%ebp),%edi # Load ES + movzwl 0x4(%ebp),%eax # Load user's SI + shll $0x4,%edi # EDI = (ES << 4) + + addl %eax,%edi # SI + movl 0x11(%edi),%eax # Read base of + movb 0x17(%edi),%al # GDT entry + ror $8,%eax # for source + xchgl %eax,%esi # into %esi + movl 0x19(%edi),%eax # Read base of + movb 0x1f(%edi),%al # GDT entry for + ror $8,%eax # destination + xchgl %eax,%edi # into %edi + pushl %ds # Make: + popl %es # es = ds + movzwl 0x18(%ebp),%ecx # Get user's CX + shll $0x1,%ecx # Convert count from words + rep # repeat... + movsb # perform copy. + popl %edi # Restore + popl %esi # registers + movb $0x0,0x1d(%ebp) # set ah = 0 to indicate + # success + andb $0xfe,%dl # clear CF + jmp v86mon.5 # Finish up + +/* + * Reboot the machine by setting the reboot flag and exiting + */ +reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag + jmp exit # Terminate BTX and reboot + +/* + * Emulate INT imm8... also make sure to check if it's int 15/87 + */ +v86intn: lodsb # Get int no + cmpb $0x19,%al # is it int 19? + je reboot # yes, reboot the machine + cmpb $0x15,%al # is it int 15? + jne v86intn.1 # no, skip parse + cmpb $0x87,0x1d(%ebp) # is it the memcpy subfunction? + je int15_87 # yes + cmpw $0x4f53,0x1c(%ebp) # is it the delete key callout? + jne v86intn.1 # no, handle the int normally + movb BDA_KEYFLAGS,%ch # get the shift key state + andb $0xc,%ch # mask off just Ctrl and Alt + cmpb $0xc,%ch # are both Ctrl and Alt down? + je reboot # yes, reboot the machine +v86intn.1: subl %edi,%esi # From + shrl $0x4,%edi # linear + movw %dx,-0x2(%ebx) # Save flags + movw %di,-0x4(%ebx) # Save CS + leal -0x6(%ebx),%ebx # Adjust SP + movw %si,(%ebx) # Save IP + shll $0x2,%eax # Scale + movzwl (%eax),%esi # Load IP + movzwl 0x2(%eax),%edi # Load CS + movl %edi,0x2c(%ebp) # Save CS + xorl %edi,%edi # No ESI adjustment + andb $~0x1,%dh # Clear TF + jmp v86mon.5 # Finish up +/* + * Hardware interrupt jump table. + */ +intx20: push $0x8 # Int 0x20: IRQ0 + jmp int_hw # V86 int 0x8 + push $0x9 # Int 0x21: IRQ1 + jmp int_hw # V86 int 0x9 + push $0xa # Int 0x22: IRQ2 + jmp int_hw # V86 int 0xa + push $0xb # Int 0x23: IRQ3 + jmp int_hw # V86 int 0xb + push $0xc # Int 0x24: IRQ4 + jmp int_hw # V86 int 0xc + push $0xd # Int 0x25: IRQ5 + jmp int_hw # V86 int 0xd + push $0xe # Int 0x26: IRQ6 + jmp int_hw # V86 int 0xe + push $0xf # Int 0x27: IRQ7 + jmp int_hw # V86 int 0xf + push $0x70 # Int 0x28: IRQ8 + jmp int_hw # V86 int 0x70 + push $0x71 # Int 0x29: IRQ9 + jmp int_hw # V86 int 0x71 +# push $0x72 # Int 0x2a: IRQ10 +# jmp int_hw # V86 int 0x72 +# just to test, my NIC's IRQ + nop + jmp user_isr_call + push $0x73 # Int 0x2b: IRQ11 + jmp int_hw # V86 int 0x73 + jmp user_isr_call + push $0x74 # Int 0x2c: IRQ12 + jmp int_hw # V86 int 0x74 + push $0x75 # Int 0x2d: IRQ13 + jmp int_hw # V86 int 0x75 + push $0x76 # Int 0x2e: IRQ14 + jmp int_hw # V86 int 0x76 + push $0x77 # Int 0x2f: IRQ15 + jmp int_hw # V86 int 0x77 +/* + * Reflect hardware interrupts. + */ +int_hw: testb $0x2,0xe(%esp,1) # V86 mode? + jz intusr # No + pushl $SEL_SDATA # Address + popl %ds # data + xchgl %eax,(%esp,1) # Swap EAX, int no + pushl %ebp # Address + movl %esp,%ebp # stack frame + pushl %ebx # Save + shll $0x2,%eax # Get int + movl (%eax),%eax # vector + subl $0x6,0x14(%ebp) # Adjust V86 ESP + movzwl 0x18(%ebp),%ebx # V86 SS + shll $0x4,%ebx # * 0x10 + addl 0x14(%ebp),%ebx # + V86 ESP + xchgw %ax,0x8(%ebp) # Swap V86 IP + rorl $0x10,%eax # Swap words + xchgw %ax,0xc(%ebp) # Swap V86 CS + roll $0x10,%eax # Swap words + movl %eax,(%ebx) # CS:IP for IRET + movl 0x10(%ebp),%eax # V86 flags + movw %ax,0x4(%ebx) # Flags for IRET + andb $~0x3,0x11(%ebp) # Clear IF, TF + popl %ebx # Restore + popl %ebp # saved + popl %eax # registers + iret # To V86 mode +/* + * Invoke V86 interrupt from user mode, with arguments. + */ +intx31: stc # Have btx_v86 + pushl %eax # Missing int no +/* + * Invoke V86 interrupt from user mode. + */ +intusr: std # String ops dec + pushl %eax # Expand + pushl %eax # stack + pushl %eax # frame + pusha # Save + pushl %gs # Save + movl %esp,%eax # seg regs + pushl %fs # and + pushl %ds # point + pushl %es # to them + push $SEL_SDATA # Set up + popl %ds # to + pushl %ds # address + popl %es # data + movl $MEM_USR,%ebx # User base + movl %ebx,%edx # address + jc intusr.1 # If btx_v86 + xorl %edx,%edx # Control flags + xorl %ebp,%ebp # btx_v86 pointer +intusr.1: leal 0x50(%esp,1),%esi # Base of frame + pushl %esi # Save + addl -0x4(%esi),%ebx # User ESP + movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer + leal -0x4(%edi),%edi # Adjust for push + xorl %ecx,%ecx # Zero + movb $0x5,%cl # Push exception + rep # frame on + movsl # link stack + xchgl %eax,%esi # Saved seg regs + movl 0x40(%esp,1),%eax # Get int no + testl %edx,%edx # Have btx_v86? + jz intusr.2 # No + movl (%ebx),%ebp # btx_v86 pointer + movb $0x4,%cl # Count + addl %ecx,%ebx # Adjust for pop + rep # Push saved seg regs + movsl # on link stack + addl %ebp,%edx # Flatten btx_v86 ptr + leal 0x14(%edx),%esi # Seg regs pointer + movl 0x4(%edx),%eax # Get int no/address + movzwl 0x2(%edx),%edx # Get control flags +intusr.2: movl %ebp,(%edi) # Push btx_v86 and + movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr + popl %edi # Base of frame + xchgl %eax,%ebp # Save intno/address + movl 0x48(%esp,1),%eax # Get flags + testb $0x2,%dl # Simulate CALLF? + jnz intusr.3 # Yes + decl %ebx # Push flags + decl %ebx # on V86 + movw %ax,(%ebx) # stack +intusr.3: movb $0x4,%cl # Count + subl %ecx,%ebx # Push return address + movl $inthlt,(%ebx) # on V86 stack + rep # Copy seg regs to + movsl # exception frame + xchgl %eax,%ecx # Save flags + movl %ebx,%eax # User ESP + subl $V86_STK,%eax # Less bytes + ja intusr.4 # to + xorl %eax,%eax # keep +intusr.4: shrl $0x4,%eax # Gives segment + stosl # Set SS + shll $0x4,%eax # To bytes + xchgl %eax,%ebx # Swap + subl %ebx,%eax # Gives offset + stosl # Set ESP + xchgl %eax,%ecx # Get flags + btsl $0x11,%eax # Set VM + andb $~0x1,%ah # Clear TF + stosl # Set EFL + xchgl %eax,%ebp # Get int no/address + testb $0x1,%dl # Address? + jnz intusr.5 # Yes + shll $0x2,%eax # Scale + movl (%eax),%eax # Load int vector +intusr.5: movl %eax,%ecx # Save + shrl $0x10,%eax # Gives segment + stosl # Set CS + movw %cx,%ax # Restore + stosl # Set EIP + leal 0x10(%esp,1),%esp # Discard seg regs + popa # Restore + iret # To V86 mode +/* + * 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 + pushl %es # segment + popl %ds # registers + pushl %ds # for the + popl %fs # program + pushl %fs # we're + popl %gs # invoking + movl $MEM_USR,%eax # User base address + addl 0xc(%esp,1),%eax # Change to user + leal 0x4(%eax),%esp # stack +#ifdef PAGING + movl %cr0,%eax # Turn + andl $~0x80000000,%eax # off + movl %eax,%cr0 # paging + xorl %eax,%eax # Flush + movl %eax,%cr3 # TLB +#endif + popl %eax # Call + call *%eax # program +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 user_isr_call, 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 + */ +# xorl %eax, %eax # clear +# movw %bx, %ax # getting interrupt number +# mov $0x08, %bl # calculating offset +# mulb %bl # to IDT entry +# # +# movl $MEM_IDT,%edi # base address of IDT. +# addl %eax, %edi # calculate address of entry +# +# movb $SEL_SCODE, %dh # supervisor code selector +# mov user_isr_call, %ax # tramp address +# movb $0x8e, %dl # i386+ interrupt gate, DPL=0 +# +# movw %ax,(%edi) # 0: handler offset 0..15 +# movb %dh, 0x2(%edi) # +2: dest selector +# # +4: 000:word_count=0 +# movb %dl, 0x5(%edi) # +5: P:DPL:type + # +6: handler offset 16..31 +/* + * 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 + +# movl $SEL_UDATA, %eax +# movl %eax, %ds +# pushl %ds +# popl %fs +# pushl %fs +# popl %gs +# pushl %gs +# popl %es + + + 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 +dump: lodsb # Load char + testb %al,%al # End of string? + jz dump.10 # Yes + testb $0x80,%al # Control? + jz dump.0 # No + movb %al,%ch # Save control + movb $'=',%al # Append + stosb # '=' + lodsb # Get offset + pushl %esi # Save + movsbl %al,%esi # To + addl %ebx,%esi # pointer + testb $DMP_X16,%ch # Dump word? + jz dump.1 # No + lodsw # Get and + call hex16 # dump it +dump.1: testb $DMP_X32,%ch # Dump long? + jz dump.2 # No + lodsl # Get and + call hex32 # dump it +dump.2: testb $DMP_MEM,%ch # Dump memory? + jz dump.8 # No + pushl %ds # Save + testb $0x2,0x52(%ebx) # V86 mode? + jnz dump.3 # Yes + verr 0x4(%esi) # Readable selector? + jnz dump.3 # No + ldsl (%esi),%esi # Load pointer + jmp dump.4 # Join common code +dump.3: lodsl # Set offset + xchgl %eax,%edx # Save + lodsl # Get segment + shll $0x4,%eax # * 0x10 + addl %edx,%eax # + offset + xchgl %eax,%esi # Set pointer +dump.4: movb $2,%dl # Num lines +dump.4a: movb $0x10,%cl # Bytes to dump +dump.5: lodsb # Get byte and + call hex8 # dump it + decb %cl # Keep count + jz dump.6a # If done + movb $'-',%al # Separator + cmpb $0x8,%cl # Half way? + je dump.6 # Yes + movb $' ',%al # Use space +dump.6: stosb # Save separator + jmp dump.5 # Continue +dump.6a: decb %dl # Keep count + jz dump.7 # If done + movb $0xa,%al # Line feed + stosb # Save one + movb $7,%cl # Leading + movb $' ',%al # spaces +dump.6b: stosb # Dump + decb %cl # spaces + jnz dump.6b + jmp dump.4a # Next line +dump.7: popl %ds # Restore +dump.8: popl %esi # Restore + movb $0xa,%al # Line feed + testb $DMP_EOL,%ch # End of line? + jnz dump.9 # Yes + movb $' ',%al # Use spaces + stosb # Save one +dump.9: jmp dump.0 # Continue +dump.10: stosb # Terminate string + ret # To caller +/* + * Convert EAX, AX, or AL to hex, saving the result to [EDI]. + */ +hex32: pushl %eax # Save + shrl $0x10,%eax # Do upper + call hex16 # 16 + popl %eax # Restore +hex16: call hex16.1 # Do upper 8 +hex16.1: xchgb %ah,%al # Save/restore +hex8: pushl %eax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + popl %eax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + stosb # Save char + ret # (Recursive) +/* + * Output zero-terminated string [ESI] to the console. + */ +putstr.0: call putchr # Output char +putstr: lodsb # Load char + testb %al,%al # End of string? + jnz putstr.0 # No + ret # To caller +#ifdef BTX_SERIAL + .set SIO_PRT,SIOPRT # Base port + .set SIO_FMT,SIOFMT # 8N1 + .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD + +/* + * void sio_init(void) + */ +sio_init: movw $SIO_PRT+0x3,%dx # Data format reg + movb $SIO_FMT|0x80,%al # Set format + outb %al,(%dx) # and DLAB + pushl %edx # Save + subb $0x3,%dl # Divisor latch reg + movw $SIO_DIV,%ax # Set + outw %ax,(%dx) # BPS + popl %edx # Restore + movb $SIO_FMT,%al # Clear + outb %al,(%dx) # DLAB + incl %edx # Modem control reg + movb $0x3,%al # Set RTS, + outb %al,(%dx) # DTR + incl %edx # Line status reg + +/* + * void sio_flush(void) + */ +sio_flush.0: call sio_getc.1 # Get character +sio_flush: call sio_ischar # Check for character + jnz sio_flush.0 # Till none + ret # To caller + +/* + * void sio_putc(int c) + */ +sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg + xor %ecx,%ecx # Timeout + movb $0x40,%ch # counter +sio_putc.1: inb (%dx),%al # Transmitter + testb $0x20,%al # buffer empty? + loopz sio_putc.1 # No + jz sio_putc.2 # If timeout + movb 0x4(%esp,1),%al # Get character + subb $0x5,%dl # Transmitter hold reg + outb %al,(%dx) # Write character +sio_putc.2: ret $0x4 # To caller + +/* + * int sio_getc(void) + */ +sio_getc: call sio_ischar # Character available? + jz sio_getc # No +sio_getc.1: subb $0x5,%dl # Receiver buffer reg + inb (%dx),%al # Read character + ret # To caller + +/* + * int sio_ischar(void) + */ +sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register + xorl %eax,%eax # Zero + inb (%dx),%al # Received data + andb $0x1,%al # ready? + ret # To caller + +/* + * Output character AL to the serial console. + */ +putchr: pusha # Save + cmpb $10, %al # is it a newline? + jne putchr.1 # no?, then leave + push $13 # output a carriage + call sio_putc # return first + movb $10, %al # restore %al +putchr.1: pushl %eax # Push the character + # onto the stack + call sio_putc # Output the character + popa # Restore + ret # To caller +#else +/* + * Output character AL to the console. + */ +putchr: pusha # Save + xorl %ecx,%ecx # Zero for loops + movb $SCR_MAT,%ah # Mode/attribute + movl $BDA_POS,%ebx # BDA pointer + movw (%ebx),%dx # Cursor position + movl $0xb8000,%edi # Regen buffer (color) + cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? + jne putchr.1 # No + xorw %di,%di # Regen buffer (mono) +putchr.1: cmpb $0xa,%al # New line? + je putchr.2 # Yes + xchgl %eax,%ecx # Save char + movb $SCR_COL,%al # Columns per row + mulb %dh # * row position + addb %dl,%al # + column + adcb $0x0,%ah # position + shll %eax # * 2 + xchgl %eax,%ecx # Swap char, offset + movw %ax,(%edi,%ecx,1) # Write attr:char + incl %edx # Bump cursor + cmpb $SCR_COL,%dl # Beyond row? + jb putchr.3 # No +putchr.2: xorb %dl,%dl # Zero column + incb %dh # Bump row +putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? + jb putchr.4 # No + leal 2*SCR_COL(%edi),%esi # New top line + movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move + rep # Scroll + movsl # screen + movb $0x20,%al # Space + movb $SCR_COL,%cl # Columns to clear + rep # Clear + stosw # line + movb $SCR_ROW-1,%dh # Bottom line +putchr.4: movw %dx,(%ebx) # Update position + popa # Restore + ret # To caller +#endif + + .p2align 4 +/* + * Global descriptor table. + */ +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE + .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA + .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE + .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA + .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE + .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA +# .word 0xffff,MEM_USR,0xba00,0xcf# SEL_UCODE +# .word 0xffff,MEM_USR,0xb200,0xcf# SEL_UDATA + .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS +callgate: .word 0x0, SEL_UCODE,0xec00,0x0 # SEL_CALLGATE +gdt.1: +/* + * Pseudo-descriptors. + */ +gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT +idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT +ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT +/* + * IDT construction control string. + */ +idtctl: .byte 0x10, 0x8e # Int 0x0-0xf + .word 0x7dfb,intx00 # (exceptions) + .byte 0x10, 0x8e # Int 0x10 + .word 0x1, intx10 # (exception) + .byte 0x10, 0x8e # Int 0x20-0x2f + .word 0xffff,intx20 # (hardware) + .byte 0x1, 0xee # int 0x30 + .word 0x1, intx30 # (system call) + .byte 0x2, 0xee # Int 0x31-0x32 + .word 0x1, intx31 # (V86, null) + .byte 0x0 # End of string +/* + * Dump format string. + */ +dmpfmt: .byte '\n' # "\n" + .ascii "int" # "int=" + .byte 0x80|DMP_X32, 0x40 # "00000000 " + .ascii "err" # "err=" + .byte 0x80|DMP_X32, 0x44 # "00000000 " + .ascii "efl" # "efl=" + .byte 0x80|DMP_X32, 0x50 # "00000000 " + .ascii "eip" # "eip=" + .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n" + .ascii "eax" # "eax=" + .byte 0x80|DMP_X32, 0x34 # "00000000 " + .ascii "ebx" # "ebx=" + .byte 0x80|DMP_X32, 0x28 # "00000000 " + .ascii "ecx" # "ecx=" + .byte 0x80|DMP_X32, 0x30 # "00000000 " + .ascii "edx" # "edx=" + .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n" + .ascii "esi" # "esi=" + .byte 0x80|DMP_X32, 0x1c # "00000000 " + .ascii "edi" # "edi=" + .byte 0x80|DMP_X32, 0x18 # "00000000 " + .ascii "ebp" # "ebp=" + .byte 0x80|DMP_X32, 0x20 # "00000000 " + .ascii "esp" # "esp=" + .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n" + .ascii "cs" # "cs=" + .byte 0x80|DMP_X16, 0x4c # "0000 " + .ascii "ds" # "ds=" + .byte 0x80|DMP_X16, 0xc # "0000 " + .ascii "es" # "es=" + .byte 0x80|DMP_X16, 0x8 # "0000 " + .ascii " " # " " + .ascii "fs" # "fs=" + .byte 0x80|DMP_X16, 0x10 # "0000 " + .ascii "gs" # "gs=" + .byte 0x80|DMP_X16, 0x14 # "0000 " + .ascii "ss" # "ss=" + .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n" + .ascii "cs:eip" # "cs:eip=" + .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n" + .ascii "ss:esp" # "ss:esp=" + .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n" + .asciz "BTX halted\n" # End +#save_esp: .word 0x0000,0x0000 + +/* + * End of BTX memory. + */ + .p2align 4 +break: Index: user/sbruno/pxe_http/btx_mod/btxcsu.s =================================================================== --- user/sbruno/pxe_http/btx_mod/btxcsu.s (nonexistent) +++ user/sbruno/pxe_http/btx_mod/btxcsu.s (revision 245442) @@ -0,0 +1,51 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxcsu.s,v 1.4 2004/08/05 06:00:05 kan Exp $ + +# +# BTX C startup code (ELF). +# + +# +# Globals. +# + .global _start +# +# Constants. +# + .set ARGADJ,0xfa0 # Argument adjustment +# +# Client entry point. +# +_start: cld + pushl %eax + movl $_edata,%edi + movl $_end,%ecx + subl %edi, %ecx + xorb %al, %al + rep + stosb + popl __base + movl %esp,%eax # Set + addl $ARGADJ,%eax # argument + movl %eax,__args # pointer + call main # Invoke client main() + call exit # Invoke client exit() +# +# Data. +# + .comm __base,4 # Client base address + .comm __args,4 # Client arguments Index: user/sbruno/pxe_http/btx_mod/btxldr/Makefile =================================================================== --- user/sbruno/pxe_http/btx_mod/btxldr/Makefile (nonexistent) +++ user/sbruno/pxe_http/btx_mod/btxldr/Makefile (revision 245442) @@ -0,0 +1,16 @@ +# $FreeBSD: src/sys/boot/i386/btx/btxldr/Makefile,v 1.18 2004/12/21 08:47:13 ru Exp $ + +PROG= btxldr +INTERNALPROG= +NO_MAN= +SRCS= btxldr.S + +CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS} + +.if defined(BTXLDR_VERBOSE) +CFLAGS+=-DBTXLDR_VERBOSE +.endif + +LDFLAGS=-N -e start -Ttext ${LOADER_ADDRESS} -Wl,-S,--oformat,binary + +.include Index: user/sbruno/pxe_http/btx_mod/btxldr/btxldr.S =================================================================== --- user/sbruno/pxe_http/btx_mod/btxldr/btxldr.S (nonexistent) +++ user/sbruno/pxe_http/btx_mod/btxldr/btxldr.S (revision 245442) @@ -0,0 +1,396 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD: src/sys/boot/i386/btx/btxldr/btxldr.S,v 1.17 2004/05/14 20:29:30 ru Exp $ + */ + +/* + * Prototype BTX loader program, written in a couple of hours. The + * real thing should probably be more flexible, and in C. + */ + +/* + * Memory locations. + */ + .set MEM_STUB,0x600 # Real mode stub + .set MEM_ESP,0x1000 # New stack pointer + .set MEM_TBL,0x5000 # BTX page tables + .set MEM_ENTRY,0x9010 # BTX entry point + .set MEM_DATA,start+0x1000 # Data segment +/* + * Segment selectors. + */ + .set SEL_SCODE,0x8 # 4GB code + .set SEL_SDATA,0x10 # 4GB data + .set SEL_RCODE,0x18 # 64K code + .set SEL_RDATA,0x20 # 64K data +/* + * Paging constants. + */ + .set PAG_SIZ,0x1000 # Page size + .set PAG_ENT,0x4 # Page entry size +/* + * Screen constants. + */ + .set SCR_MAT,0x7 # Mode/attribute + .set SCR_COL,0x50 # Columns per row + .set SCR_ROW,0x19 # Rows per screen +/* + * BIOS Data Area locations. + */ + .set BDA_MEM,0x413 # Free memory + .set BDA_SCR,0x449 # Video mode + .set BDA_POS,0x450 # Cursor position +/* + * Required by aout gas inadequacy. + */ + .set SIZ_STUB,0x1a # Size of stub +/* + * We expect to be loaded by boot2 at the origin defined in ./Makefile. + */ + .globl start +/* + * BTX program loader for ELF clients. + */ +start: cld # String ops inc + movl $m_logo,%esi # Identify + call putstr # ourselves + movzwl BDA_MEM,%eax # Get base memory + shll $0xa,%eax # in bytes + movl %eax,%ebp # Base of user stack +#ifdef BTXLDR_VERBOSE + movl $m_mem,%esi # Display + call hexout # amount of + call putstr # base memory +#endif + lgdt gdtdesc # Load new GDT +/* + * Relocate caller's arguments. + */ +#ifdef BTXLDR_VERBOSE + movl $m_esp,%esi # Display + movl %esp,%eax # caller + call hexout # stack + call putstr # pointer + movl $m_args,%esi # Format string + leal 0x4(%esp,1),%ebx # First argument + movl $0x6,%ecx # Count +start.1: movl (%ebx),%eax # Get argument and + addl $0x4,%ebx # bump pointer + call hexout # Display it + loop start.1 # Till done + call putstr # End message +#endif + movl $0x48,%ecx # Allocate space + subl %ecx,%ebp # for bootinfo + movl 0x18(%esp,1),%esi # Source: bootinfo + cmpl $0x0, %esi # If the bootinfo pointer + je start_null_bi # is null, don't copy it + movl %ebp,%edi # Destination + rep # Copy + movsb # it + movl %ebp,0x18(%esp,1) # Update pointer +#ifdef BTXLDR_VERBOSE + movl $m_rel_bi,%esi # Display + movl %ebp,%eax # bootinfo + call hexout # relocation + call putstr # message +#endif +start_null_bi: movl $0x18,%ecx # Allocate space + subl %ecx,%ebp # for arguments + leal 0x4(%esp,1),%esi # Source + movl %ebp,%edi # Destination + rep # Copy + movsb # them +#ifdef BTXLDR_VERBOSE + movl $m_rel_args,%esi # Display + movl %ebp,%eax # argument + call hexout # relocation + call putstr # message +#endif +/* + * Set up BTX kernel. + */ + movl $MEM_ESP,%esp # Set up new stack + movl $MEM_DATA,%ebx # Data segment + movl $m_vers,%esi # Display BTX + call putstr # version message + movb 0x5(%ebx),%al # Get major version + addb $'0',%al # Display + call putchr # it + movb $'.',%al # And a + call putchr # dot + movb 0x6(%ebx),%al # Get minor + xorb %ah,%ah # version + movb $0xa,%dl # Divide + divb %dl,%al # by 10 + addb $'0',%al # Display + call putchr # tens + movb %ah,%al # Get units + addb $'0',%al # Display + call putchr # units + call putstr # End message + movl %ebx,%esi # BTX image + movzwl 0x8(%ebx),%edi # Compute + orl $PAG_SIZ/PAG_ENT-1,%edi # the + incl %edi # BTX + shll $0x2,%edi # load + addl $MEM_TBL,%edi # address + pushl %edi # Save load address + movzwl 0xa(%ebx),%ecx # Image size +#ifdef BTXLDR_VERBOSE + pushl %ecx # Save image size +#endif + rep # Relocate + movsb # BTX + movl %esi,%ebx # Keep place +#ifdef BTXLDR_VERBOSE + movl $m_rel_btx,%esi # Restore + popl %eax # parameters + call hexout # and +#endif + popl %ebp # display +#ifdef BTXLDR_VERBOSE + movl %ebp,%eax # the + call hexout # relocation + call putstr # message +#endif + addl $PAG_SIZ,%ebp # Display +#ifdef BTXLDR_VERBOSE + movl $m_base,%esi # the + movl %ebp,%eax # user + call hexout # base + call putstr # address +#endif +/* + * Set up ELF-format client program. + */ + cmpl $0x464c457f,(%ebx) # ELF magic number? + je start.3 # Yes + movl $e_fmt,%esi # Display error + call putstr # message +start.2: jmp start.2 # Hang +start.3: +#ifdef BTXLDR_VERBOSE + movl $m_elf,%esi # Display ELF + call putstr # message + movl $m_segs,%esi # Format string +#endif + movl $0x2,%edi # Segment count + movl 0x1c(%ebx),%edx # Get e_phoff + addl %ebx,%edx # To pointer + movzwl 0x2c(%ebx),%ecx # Get e_phnum +start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? + jne start.6 # No +#ifdef BTXLDR_VERBOSE + movl 0x4(%edx),%eax # Display + call hexout # p_offset + movl 0x8(%edx),%eax # Display + call hexout # p_vaddr + movl 0x10(%edx),%eax # Display + call hexout # p_filesz + movl 0x14(%edx),%eax # Display + call hexout # p_memsz + call putstr # End message +#endif + pushl %esi # Save + pushl %edi # working + pushl %ecx # registers + movl 0x4(%edx),%esi # Get p_offset + addl %ebx,%esi # as pointer + movl 0x8(%edx),%edi # Get p_vaddr + addl %ebp,%edi # as pointer + movl 0x10(%edx),%ecx # Get p_filesz + rep # Set up + movsb # segment + movl 0x14(%edx),%ecx # Any bytes + subl 0x10(%edx),%ecx # to zero? + jz start.5 # No + xorb %al,%al # Then + rep # zero + stosb # them +start.5: popl %ecx # Restore + popl %edi # working + popl %esi # registers + decl %edi # Segments to do + je start.7 # If none +start.6: addl $0x20,%edx # To next entry + loop start.4 # Till done +start.7: +#ifdef BTXLDR_VERBOSE + movl $m_done,%esi # Display done + call putstr # message +#endif + movl $start.8,%esi # Real mode stub + movl $MEM_STUB,%edi # Destination + movl $start.9-start.8,%ecx # Size + rep # Relocate + movsb # it + ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code + .code16 +start.8: xorw %ax,%ax # Data + movb $SEL_RDATA,%al # selector + movw %ax,%ss # Reload SS + movw %ax,%ds # Reset + movw %ax,%es # other + movw %ax,%fs # segment + movw %ax,%gs # limits + movl %cr0,%eax # Switch to + decw %ax # real + movl %eax,%cr0 # mode + ljmp $0,$MEM_ENTRY # Jump to BTX entry point +start.9: + .code32 +/* + * Output message [ESI] followed by EAX in hex. + */ +hexout: pushl %eax # Save + call putstr # Display message + popl %eax # Restore + pushl %esi # Save + pushl %edi # caller's + movl $buf,%edi # Buffer + pushl %edi # Save + call hex32 # To hex + xorb %al,%al # Terminate + stosb # string + popl %esi # Restore +hexout.1: lodsb # Get a char + cmpb $'0',%al # Leading zero? + je hexout.1 # Yes + testb %al,%al # End of string? + jne hexout.2 # No + decl %esi # Undo +hexout.2: decl %esi # Adjust for inc + call putstr # Display hex + popl %edi # Restore + popl %esi # caller's + ret # To caller +/* + * Output zero-terminated string [ESI] to the console. + */ +putstr.0: call putchr # Output char +putstr: lodsb # Load char + testb %al,%al # End of string? + jne putstr.0 # No + ret # To caller +/* + * Output character AL to the console. + */ +putchr: pusha # Save + xorl %ecx,%ecx # Zero for loops + movb $SCR_MAT,%ah # Mode/attribute + movl $BDA_POS,%ebx # BDA pointer + movw (%ebx),%dx # Cursor position + movl $0xb8000,%edi # Regen buffer (color) + cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? + jne putchr.1 # No + xorw %di,%di # Regen buffer (mono) +putchr.1: cmpb $0xa,%al # New line? + je putchr.2 # Yes + xchgl %eax,%ecx # Save char + movb $SCR_COL,%al # Columns per row + mulb %dh # * row position + addb %dl,%al # + column + adcb $0x0,%ah # position + shll %eax # * 2 + xchgl %eax,%ecx # Swap char, offset + movw %ax,(%edi,%ecx,1) # Write attr:char + incl %edx # Bump cursor + cmpb $SCR_COL,%dl # Beyond row? + jb putchr.3 # No +putchr.2: xorb %dl,%dl # Zero column + incb %dh # Bump row +putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? + jb putchr.4 # No + leal 2*SCR_COL(%edi),%esi # New top line + movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move + rep # Scroll + movsl # screen + movb $' ',%al # Space + movb $SCR_COL,%cl # Columns to clear + rep # Clear + stosw # line + movb $SCR_ROW-1,%dh # Bottom line +putchr.4: movw %dx,(%ebx) # Update position + popa # Restore + ret # To caller +/* + * Convert EAX, AX, or AL to hex, saving the result to [EDI]. + */ +hex32: pushl %eax # Save + shrl $0x10,%eax # Do upper + call hex16 # 16 + popl %eax # Restore +hex16: call hex16.1 # Do upper 8 +hex16.1: xchgb %ah,%al # Save/restore +hex8: pushl %eax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + popl %eax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + stosb # Save char + ret # (Recursive) + + .data + .p2align 4 +/* + * Global descriptor table. + */ +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE + .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA + .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE + .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA +gdt.1: +gdtdesc: .word gdt.1-gdt-1 # Limit + .long gdt # Base +/* + * Messages. + */ +m_logo: .asciz " \nBTX loader 1.00 " +m_vers: .asciz "BTX version is \0\n" +e_fmt: .asciz "Error: Client format not supported\n" +#ifdef BTXLDR_VERBOSE +m_mem: .asciz "Starting in protected mode (base mem=\0)\n" +m_esp: .asciz "Arguments passed (esp=\0):\n" +m_args: .asciz"\n" +m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" +m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" +m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" +m_base: .asciz "Client base address is \0\n" +m_elf: .asciz "Client format is ELF\n" +m_segs: .asciz "text segment: offset=" + .asciz " vaddr=" + .asciz " filesz=" + .asciz " memsz=\0\n" + .asciz "data segment: offset=" + .asciz " vaddr=" + .asciz " filesz=" + .asciz " memsz=\0\n" +m_done: .asciz "Loading complete\n" +#endif +/* + * Uninitialized data area. + */ +buf: # Scratch buffer Index: user/sbruno/pxe_http/btx_mod/btxsys.s =================================================================== --- user/sbruno/pxe_http/btx_mod/btxsys.s (nonexistent) +++ user/sbruno/pxe_http/btx_mod/btxsys.s (revision 245442) @@ -0,0 +1,46 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxsys.s,v 1.2 1999/08/28 00:40:07 peter Exp $ + +# +# BTX system calls. +# + +# +# Globals. +# + .global __exit + .global __exec + .global __isr_install +# +# Constants. +# + .set INT_SYS,0x30 # Interrupt number +# +# System call: exit +# +__exit: xorl %eax,%eax # BTX system + int $INT_SYS # call 0x0 +# +# System call: exec +# +__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 Index: user/sbruno/pxe_http/btx_mod/btxv86.h =================================================================== --- user/sbruno/pxe_http/btx_mod/btxv86.h (nonexistent) +++ user/sbruno/pxe_http/btx_mod/btxv86.h (revision 245442) @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +/* + * $FreeBSD: src/sys/boot/i386/btx/lib/btxv86.h,v 1.5 1999/08/28 00:40:08 peter Exp $ + */ + +#ifndef _BTXV86_H_ +#define _BTXV86_H_ + +#include + +#define V86_ADDR 0x10000 /* Segment:offset address */ +#define V86_CALLF 0x20000 /* Emulate far call */ +#define V86_FLAGS 0x40000 /* Return flags */ + +struct __v86 { + uint32_t ctl; /* Control flags */ + uint32_t addr; /* Interrupt number or address */ + uint32_t es; /* V86 ES register */ + uint32_t ds; /* V86 DS register */ + uint32_t fs; /* V86 FS register */ + uint32_t gs; /* V86 GS register */ + uint32_t eax; /* V86 EAX register */ + uint32_t ecx; /* V86 ECX register */ + uint32_t edx; /* V86 EDX register */ + uint32_t ebx; /* V86 EBX register */ + uint32_t efl; /* V86 eflags register */ + uint32_t ebp; /* V86 EBP register */ + uint32_t esi; /* V86 ESI register */ + uint32_t edi; /* V86 EDI register */ +}; + +extern struct __v86 __v86; /* V86 interface structure */ +void __v86int(void); + +#define v86 __v86 +#define v86int __v86int + +extern u_int32_t __base; +extern u_int32_t __args; + +#define PTOV(pa) ((caddr_t)(pa) - __base) +#define VTOP(va) ((vm_offset_t)(va) + __base) +#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4) +#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf) + +void __exit(int) __attribute__((__noreturn__)); +void __exec(caddr_t, ...); +/* + * Installs interrupt handler function for interrupt int_num. + * caddr_t - in userspace. + */ +void __isr_install(uint8_t int_num, caddr_t isr); + +#endif /* !_BTXV86_H_ */ Index: user/sbruno/pxe_http/btx_mod/btxv86.s =================================================================== --- user/sbruno/pxe_http/btx_mod/btxv86.s (nonexistent) +++ user/sbruno/pxe_http/btx_mod/btxv86.s (revision 245442) @@ -0,0 +1,85 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxv86.s,v 1.3 1999/08/28 00:40:08 peter Exp $ + +# +# BTX V86 interface. +# + +# +# Globals. +# + .global __v86int +# +# Fields in V86 interface structure. +# + .set V86_CTL,0x0 # Control flags + .set V86_ADDR,0x4 # Int number/address + .set V86_ES,0x8 # V86 ES + .set V86_DS,0xc # V86 DS + .set V86_FS,0x10 # V86 FS + .set V86_GS,0x14 # V86 GS + .set V86_EAX,0x18 # V86 EAX + .set V86_ECX,0x1c # V86 ECX + .set V86_EDX,0x20 # V86 EDX + .set V86_EBX,0x24 # V86 EBX + .set V86_EFL,0x28 # V86 eflags + .set V86_EBP,0x2c # V86 EBP + .set V86_ESI,0x30 # V86 ESI + .set V86_EDI,0x34 # V86 EDI +# +# Other constants. +# + .set INT_V86,0x31 # Interrupt number + .set SIZ_V86,0x38 # Size of V86 structure +# +# V86 interface function. +# +__v86int: popl __v86ret # Save return address + pushl $__v86 # Push pointer + call __v86_swap # Load V86 registers + int $INT_V86 # To BTX + call __v86_swap # Load user registers + addl $0x4,%esp # Discard pointer + pushl __v86ret # Restore return address + ret # To user +# +# Swap V86 and user registers. +# +__v86_swap: xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP + xchgl %eax,V86_EAX(%ebp) # Swap EAX + xchgl %ecx,V86_ECX(%ebp) # Swap ECX + xchgl %edx,V86_EDX(%ebp) # Swap EDX + xchgl %ebx,V86_EBX(%ebp) # Swap EBX + pushl %eax # Save + pushf # Put eflags + popl %eax # in EAX + xchgl %eax,V86_EFL(%ebp) # Swap + pushl %eax # Put EAX + popf # in eflags + movl 0x8(%esp,1),%eax # Load EBP + xchgl %eax,V86_EBP(%ebp) # Swap + movl %eax,0x8(%esp,1) # Save EBP + popl %eax # Restore + xchgl %esi,V86_ESI(%ebp) # Swap ESI + xchgl %edi,V86_EDI(%ebp) # Swap EDI + xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP + ret # To caller +# +# V86 interface structure. +# + .comm __v86,SIZ_V86 + .comm __v86ret,4 Index: user/sbruno/pxe_http/btx_mod/lib/Makefile =================================================================== --- user/sbruno/pxe_http/btx_mod/lib/Makefile (nonexistent) +++ user/sbruno/pxe_http/btx_mod/lib/Makefile (revision 245442) @@ -0,0 +1,9 @@ +# $FreeBSD: src/sys/boot/i386/btx/lib/Makefile,v 1.13 2004/12/21 08:47:14 ru Exp $ + +PROG= crt0.o +INTERNALPROG= +NO_MAN= +SRCS= btxcsu.s btxsys.s btxv86.s +LDFLAGS=-Wl,-r + +.include Index: user/sbruno/pxe_http/btx_mod/lib/btxcsu.s =================================================================== --- user/sbruno/pxe_http/btx_mod/lib/btxcsu.s (nonexistent) +++ user/sbruno/pxe_http/btx_mod/lib/btxcsu.s (revision 245442) @@ -0,0 +1,51 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxcsu.s,v 1.4 2004/08/05 06:00:05 kan Exp $ + +# +# BTX C startup code (ELF). +# + +# +# Globals. +# + .global _start +# +# Constants. +# + .set ARGADJ,0xfa0 # Argument adjustment +# +# Client entry point. +# +_start: cld + pushl %eax + movl $_edata,%edi + movl $_end,%ecx + subl %edi, %ecx + xorb %al, %al + rep + stosb + popl __base + movl %esp,%eax # Set + addl $ARGADJ,%eax # argument + movl %eax,__args # pointer + call main # Invoke client main() + call exit # Invoke client exit() +# +# Data. +# + .comm __base,4 # Client base address + .comm __args,4 # Client arguments Index: user/sbruno/pxe_http/btx_mod/lib/btxsys.s =================================================================== --- user/sbruno/pxe_http/btx_mod/lib/btxsys.s (nonexistent) +++ user/sbruno/pxe_http/btx_mod/lib/btxsys.s (revision 245442) @@ -0,0 +1,46 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxsys.s,v 1.2 1999/08/28 00:40:07 peter Exp $ + +# +# BTX system calls. +# + +# +# Globals. +# + .global __exit + .global __exec + .global __isr_install +# +# Constants. +# + .set INT_SYS,0x30 # Interrupt number +# +# System call: exit +# +__exit: xorl %eax,%eax # BTX system + int $INT_SYS # call 0x0 +# +# System call: exec +# +__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 Index: user/sbruno/pxe_http/btx_mod/lib/btxv86.h =================================================================== --- user/sbruno/pxe_http/btx_mod/lib/btxv86.h (nonexistent) +++ user/sbruno/pxe_http/btx_mod/lib/btxv86.h (revision 245442) @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +/* + * $FreeBSD: src/sys/boot/i386/btx/lib/btxv86.h,v 1.5 1999/08/28 00:40:08 peter Exp $ + */ + +#ifndef _BTXV86_H_ +#define _BTXV86_H_ + +#include + +#define V86_ADDR 0x10000 /* Segment:offset address */ +#define V86_CALLF 0x20000 /* Emulate far call */ +#define V86_FLAGS 0x40000 /* Return flags */ + +struct __v86 { + uint32_t ctl; /* Control flags */ + uint32_t addr; /* Interrupt number or address */ + uint32_t es; /* V86 ES register */ + uint32_t ds; /* V86 DS register */ + uint32_t fs; /* V86 FS register */ + uint32_t gs; /* V86 GS register */ + uint32_t eax; /* V86 EAX register */ + uint32_t ecx; /* V86 ECX register */ + uint32_t edx; /* V86 EDX register */ + uint32_t ebx; /* V86 EBX register */ + uint32_t efl; /* V86 eflags register */ + uint32_t ebp; /* V86 EBP register */ + uint32_t esi; /* V86 ESI register */ + uint32_t edi; /* V86 EDI register */ +}; + +extern struct __v86 __v86; /* V86 interface structure */ +void __v86int(void); + +#define v86 __v86 +#define v86int __v86int + +extern u_int32_t __base; +extern u_int32_t __args; + +#define PTOV(pa) ((caddr_t)(pa) - __base) +#define VTOP(va) ((vm_offset_t)(va) + __base) +#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4) +#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf) + +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_ */ Index: user/sbruno/pxe_http/btx_mod/lib/btxv86.s =================================================================== --- user/sbruno/pxe_http/btx_mod/lib/btxv86.s (nonexistent) +++ user/sbruno/pxe_http/btx_mod/lib/btxv86.s (revision 245442) @@ -0,0 +1,85 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxv86.s,v 1.3 1999/08/28 00:40:08 peter Exp $ + +# +# BTX V86 interface. +# + +# +# Globals. +# + .global __v86int +# +# Fields in V86 interface structure. +# + .set V86_CTL,0x0 # Control flags + .set V86_ADDR,0x4 # Int number/address + .set V86_ES,0x8 # V86 ES + .set V86_DS,0xc # V86 DS + .set V86_FS,0x10 # V86 FS + .set V86_GS,0x14 # V86 GS + .set V86_EAX,0x18 # V86 EAX + .set V86_ECX,0x1c # V86 ECX + .set V86_EDX,0x20 # V86 EDX + .set V86_EBX,0x24 # V86 EBX + .set V86_EFL,0x28 # V86 eflags + .set V86_EBP,0x2c # V86 EBP + .set V86_ESI,0x30 # V86 ESI + .set V86_EDI,0x34 # V86 EDI +# +# Other constants. +# + .set INT_V86,0x31 # Interrupt number + .set SIZ_V86,0x38 # Size of V86 structure +# +# V86 interface function. +# +__v86int: popl __v86ret # Save return address + pushl $__v86 # Push pointer + call __v86_swap # Load V86 registers + int $INT_V86 # To BTX + call __v86_swap # Load user registers + addl $0x4,%esp # Discard pointer + pushl __v86ret # Restore return address + ret # To user +# +# Swap V86 and user registers. +# +__v86_swap: xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP + xchgl %eax,V86_EAX(%ebp) # Swap EAX + xchgl %ecx,V86_ECX(%ebp) # Swap ECX + xchgl %edx,V86_EDX(%ebp) # Swap EDX + xchgl %ebx,V86_EBX(%ebp) # Swap EBX + pushl %eax # Save + pushf # Put eflags + popl %eax # in EAX + xchgl %eax,V86_EFL(%ebp) # Swap + pushl %eax # Put EAX + popf # in eflags + movl 0x8(%esp,1),%eax # Load EBP + xchgl %eax,V86_EBP(%ebp) # Swap + movl %eax,0x8(%esp,1) # Save EBP + popl %eax # Restore + xchgl %esi,V86_ESI(%ebp) # Swap ESI + xchgl %edi,V86_EDI(%ebp) # Swap EDI + xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP + ret # To caller +# +# V86 interface structure. +# + .comm __v86,SIZ_V86 + .comm __v86ret,4 Index: user/sbruno/pxe_http/devd2dbus/bsdbus.c =================================================================== --- user/sbruno/pxe_http/devd2dbus/bsdbus.c (nonexistent) +++ user/sbruno/pxe_http/devd2dbus/bsdbus.c (revision 245442) @@ -0,0 +1,625 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * main.c - Auto-generated by Anjuta's Makefile project wizard + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "bsdbus.h" + +static char* known_bus_path[DBUS_ALL_KNOWN_BUS] = { NULL, NULL}; + +size_t +dbus_pad (size_t stream_index, size_t align) +{ + size_t pad = stream_index % align; + return ((pad == 0) ? 0 : align - pad); +} + +size_t +dbus_align_index(size_t stream_index, size_t align) +{ + size_t pad = stream_index % align; + return (stream_index += (pad == 0) ? 0 : align - pad); +} + +void +dbus_push_elem(struct DBus_message *message, enum DBus_param_type type, void *data, size_t size) +{ + struct DBus_body_elem *elem = (struct DBus_body_elem *)malloc(sizeof(struct DBus_body_elem)); + + elem->type = type; + elem->data = data; + elem->size = size; + elem->next = NULL; + + if (message->start == NULL) { + message->start = elem; + } else { + message->tail->next = elem; + } + + message->tail = elem; + + // add padding size + // printf("size = %lu, align = %lu\n", message->size, DBus_field_align[type]); + message->size += dbus_pad (message->size, DBus_field_align[type]); + // add new body element size + // printf("pad + size = %lu\n", message->size); + message->size += size; + message->elem_count += 1; +} + +void +dbus_push_byte(struct DBus_message *message, uint8_t val) +{ + uint8_t *data = (uint8_t *)malloc(1); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_BYTE, data, 1); +} + +void +dbus_push_boolean(struct DBus_message *message, uint32_t val) +{ + uint32_t *data = (uint32_t *)malloc(4); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_BOOLEAN, data, 4); +} + +void +dbus_push_int16(struct DBus_message *message, int16_t val) +{ + int16_t *data = (int16_t *)malloc(2); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_INT16, data, 1); +} + +void +dbus_push_uint16(struct DBus_message *message, uint16_t val) +{ + uint16_t *data = (uint16_t *)malloc(2); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_UINT16, data, 2); +} + +void +dbus_push_int32(struct DBus_message *message, int32_t val) +{ + int32_t *data = (int32_t *)malloc(4); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_INT32, data, 4); +} + +void +dbus_push_uint32(struct DBus_message *message, uint32_t val) +{ + uint32_t *data = (uint32_t *)malloc(4); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_UINT32, data, 4); +} + +void +dbus_push_int64(struct DBus_message *message, int64_t val) +{ + int64_t *data = (int64_t *)malloc(8); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_INT64, data, 8); +} + +void +dbus_push_uint64(struct DBus_message *message, uint64_t val) +{ + uint64_t *data = (uint64_t *)malloc(8); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_UINT64, data, 8); +} + +void +dbus_push_double(struct DBus_message *message, double val) +{ + double *data = (double *)malloc(8); + *data = val; + + dbus_push_elem(message, DBUS_PARAM_DOUBLE, data, 8); +} + +void +dbus_push_struct_align(struct DBus_message *message) +{ + dbus_push_elem(message, DBUS_PARAM_STRUCT, NULL, 0); +} + +void +dbus_push_string(struct DBus_message *message, const char *val) +{ + uint32_t len = (uint32_t)strlen(val); + uint8_t *data = (uint8_t *)malloc(len + 5); + + *((uint32_t *)data) = len; + //data += 4; + + memcpy(data + 4, val, len); + data[len + 4] = '\0'; + + dbus_push_elem(message, DBUS_PARAM_STRING, data, len + 5); +} + +void +dbus_push_object_path(struct DBus_message *message, const char *val) +{ + /* TODO: valid object path check */ + dbus_push_string (message, val); +} + +void +dbus_push_signature(struct DBus_message *message, const char *val) +{ + uint8_t len = (uint8_t)strlen(val); + uint8_t *data = (uint8_t *)malloc(len + 2); + + *data = len; + //data += 1; + + memcpy(data + 1, val, len); + data[len + 1] = '\0'; + + dbus_push_elem(message, DBUS_PARAM_SIGNATURE, data, len + 2); +} + +struct DBus_message * +dbus_alloc_message() +{ + struct DBus_message *tmpMessage = malloc(sizeof(struct DBus_message)); + + if (tmpMessage == NULL) { + printf("failed to allocate memory for message.\n"); + return (NULL); + } + + memset(tmpMessage, 0, sizeof(struct DBus_message)); + + return (tmpMessage); +} + +void +dbus_free_message(struct DBus_message *message) +{ + struct DBus_body_elem *elem = message->start; + + while (elem != NULL) { + struct DBus_body_elem *tmp = elem->next; + free(elem->data); + free(elem); + elem = tmp; + } + + free(message); +} + +void * +dbus_format_message(struct DBus_message *message, int pad) +{ + // printf("dbus_format_message(%lu):\n", message->size); + + if (message->size == 0) { + return (message); + } + + if (pad != DBUS_NO_PADDING) { + message->size += dbus_pad(message->size, pad); + } + // allocating storage for body + message->data = malloc(message->size); + + if (message->data == NULL) + return (NULL); + + memset(message->data, 0, message->size); + + size_t pos = 0; + uint8_t *data = (uint8_t *)message->data; + + struct DBus_body_elem *elem = message->start; + + while (elem != NULL) { + + pos += dbus_pad (pos, DBus_field_align[elem->type]); + + if (elem->data != NULL) /* may be NULL only for structure */ + memcpy(data + pos, elem->data, elem->size); + + pos += elem->size; + + elem = elem->next; + } + + return (message->data); +} + +enum DBus_communication_state +dbus_send(struct DBus_connection *connection, struct DBus_message *message, + const char *path, const char *interface, const char *name) +{ + struct DBus_message *hdrMsg = dbus_alloc_message (); + struct DBus_message_header hdr; + + printf("dbus_send(): "); + hdr.endyFlag = DBUS_LITTLE_ENDIAN; + hdr.type = DBUS_METHOD_CALL; + hdr.flags = 0; + hdr.proto = 1; + hdr.length = message->size; + hdr.serial = 1; + + + dbus_push_struct_align(hdrMsg); + dbus_push_byte(hdrMsg, DBUS_PATH); + dbus_push_signature(hdrMsg, "o"); + dbus_push_object_path(hdrMsg, path); + + dbus_push_struct_align(hdrMsg); + dbus_push_byte(hdrMsg, DBUS_INTERFACE); + dbus_push_signature(hdrMsg, "s"); + dbus_push_string(hdrMsg, interface); + + dbus_push_struct_align(hdrMsg); + dbus_push_byte(hdrMsg, DBUS_MEMBER); + dbus_push_signature(hdrMsg, "s"); + dbus_push_string(hdrMsg, name); + + dbus_push_struct_align(hdrMsg); + dbus_push_byte(hdrMsg, DBUS_DESTINATION); + dbus_push_signature(hdrMsg, "s"); + dbus_push_string(hdrMsg, DBUS_SERVICE_DBUS); + + hdr.arrSize = hdrMsg->size; + + dbus_format_message (hdrMsg, 8); + + FILE *fd = connection->fd; + + if (1 != fwrite(&hdr, sizeof(struct DBus_message_header), 1, fd)) { + printf("failed to write message header\n"); + goto error; + } + + printf("data = %p, %lu", hdrMsg->data, hdrMsg->size); + if (1 != fwrite(hdrMsg->data, hdrMsg->size, 1, fd)) { + printf("failed to write message header fields\n"); + goto error; + } + + printf("; data = %p, %lu: ", message->data, message->size); + if (message->size != 0) { + if (1 != fwrite(message->data, message->size, 1, fd)) { + printf("failed to write message body\n"); + goto error; + } + } + + fflush(fd); + + printf("ok\n"); + + uint8_t reply[512]; + ssize_t reply_size = 0; + + usleep(10); + reply_size = recv(connection->socket, reply, 512, 0); + + FILE *fout = fopen("bsdbus.dump", "w+"); + fwrite(&hdr, sizeof(struct DBus_message_header), 1, fout); + fwrite(hdrMsg->data, hdrMsg->size, 1, fout); + fwrite(message->data, message->size, 1, fout); + + if (reply_size > 0) { + printf("method return received\n"); + fwrite(reply, reply_size, 1, fout); + } + + fflush(fout); + fclose(fout); + + + // dbus_free_message(hdrMsg); + + return (DBUS_COMMUNICATION_OK); + +error: + // dbus_free_message(hdrMsg); + + return (DBUS_COMMUNICATION_FAILED); +} + +void +dbus_getuid(char *hex) +{ + uid_t uid = getuid(); + + char str[128] = {0}; + + sprintf(str, "%Lu", uid); + + size_t len = strlen(str); + + size_t i = 0; + + for (; i < len; ++i) { + sprintf(&hex[2*i], "%2x", str[i]); + } + + hex[2 * len] = '\0'; +} + +struct DBus_connection * +dbus_auth(struct DBus_connection* connection) +{ + FILE *fd = connection->fd; + char buf[256]; + char uid[256]; + + dbus_getuid(uid); + + sprintf(buf, "AUTH EXTERNAL %s\r\n", uid); + + size_t res = fwrite(buf, strlen(buf), 1, fd); + fflush(fd); + + if (1 != res) { + printf("failed to write AUTH (%d)\n", ferror(fd)); + return (NULL); + } + + printf("wrote string: %s", buf); + + buf[0] ='\0'; + + while(buf[0] == '\0') { + if ( (fgets(buf, 256, fd) == NULL) && (!feof(fd))) { + printf("failed to get answer to AUTH (%d)\n", ferror(fd)); + if (ferror(fd) == EBADF) + printf("stream is not readable\n"); + return (NULL); + } + + usleep(10); + } + + printf("received %s\n", buf); + + sprintf(buf, "BEGIN\r\n"); + fwrite(buf, strlen(buf), 1, fd); + fflush(fd); + + return (connection); +} + +struct dbus_credential_msg { + struct cmsghdr hdr; + struct cmsgcred cred; +}; + +struct DBus_connection * +dbus_credential(struct DBus_connection* connection) +{ + int written = -1; + uint8_t byte = 0; + + struct iovec vec; + struct msghdr msg; + struct dbus_credential_msg cmsg; + + vec.iov_base = &byte; + vec.iov_len = 1; + + memset (&msg, 0, sizeof (msg)); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof (cmsg); + + memset (&cmsg, 0, sizeof (cmsg)); + + cmsg.hdr.cmsg_len = sizeof (cmsg); + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_CREDS; + + do { + written = sendmsg (connection->socket, &msg, 0); + } while (written < 0 && errno == EINTR); + + if (written != 1) { + printf("failed to write credentials byte. %s\n", written == 0 ? + "no bytes written" : "error occured"); + return (NULL); + } + + printf ("wrote credentials byte\n"); + + return (connection); +} + +struct DBus_connection * +dbus_connect(enum DBus_connection_type conType) +{ + if (conType >= DBUS_ALL_KNOWN_BUS) { + return (NULL); + } + + if (known_bus_path[conType] == NULL) { + const char *path = getenv(DBus_connection_str[conType]); + + if (path == NULL) { + known_bus_path[conType] = strdup(DBus_default_path[conType]); + } else { + + const char *eq = strchr(path, '='); + + if (eq == NULL) + return (NULL); + + const char *zap = strchr(path, ','); + + size_t len = (zap != NULL) ? (zap - eq - 1) : strlen(path) - (eq - path) - 1; + + known_bus_path[conType] = (char *)malloc(len); + memcpy(known_bus_path[conType] , eq + 1, len); + known_bus_path[conType][len] = '\0'; + } + } + + struct DBus_connection *tmpStruct = + (struct DBus_connection *)malloc(sizeof(struct DBus_connection)); + + memset(tmpStruct, 0, sizeof(struct DBus_connection)); + + if (!dbus_open_connect (tmpStruct, known_bus_path[conType])) { + free(tmpStruct); + return (NULL); + } + + if (!dbus_credential(tmpStruct)) { + dbus_disconnect(tmpStruct); + return (NULL); + } + + if (!dbus_auth(tmpStruct)) { + dbus_disconnect (tmpStruct); + return (NULL); + } + + printf("connected to dbus\n"); + + return (tmpStruct); +} + +void +dbus_disconnect(struct DBus_connection *connection) +{ + if (connection->socket != -1) { + if (connection->fd != NULL) + fclose(connection->fd); + else + close(connection->socket); + } + + printf("disconnected...\n"); + + free(connection); +} + +struct DBus_connection * +dbus_open_connect(struct DBus_connection *connection, const char *path) +{ + struct sockaddr_un addr; + size_t len; + + connection->socket = socket(AF_LOCAL, SOCK_STREAM, 0); + + if (connection->socket < 0) { + printf("Failed to open socket\n"); + return (NULL); + } + + memset(&addr, 0, sizeof(addr)); + + addr.sun_family = PF_LOCAL; + len = strlen (path); + + memcpy (addr.sun_path, path, len); + + printf("connecting to %s\n", path); + + int result = connect(connection->socket, (struct sockaddr *)&addr, + sizeof(struct sockaddr_un)); + + if (result < 0) { + printf("Failed to connect to socket %s\n", path); + + close(connection->socket); + connection->socket = -1; + + return (NULL); + } + + int flags = fcntl (connection->socket, F_GETFL, 0); + + if (flags < 0) { + printf("Failed to get socket flags\n"); + + close(connection->socket); + connection->socket = -1; + + return (NULL); + } + + /* result = fcntl (connection->socket, F_SETFL, flags | O_NONBLOCK); + + if (result < 0) { + printf("Failed to set O_NONBLOCK flag on connection socket\n"); + + close(connection->socket); + connection->socket = -1; + + return (NULL); + } +*/ + + + connection->fd = fdopen(connection->socket, "r+"); + + if (connection->fd == NULL) { + printf("Failed to open FILE descriptor\n"); + close(connection->socket); + connection->socket = -1; + return (NULL); + } + + return (connection); +} + +int main() +{ + printf("bsdbus test\n"); + + struct DBus_connection *connection = dbus_connect (DBUS_SESSION_BUS); + + if (connection == NULL) { + printf("Failed to open connection to sesion bus\n"); + return (1); + } + + struct DBus_message *msg = dbus_alloc_message(); + + if (dbus_format_message (msg, DBUS_NO_PADDING) == NULL) { + printf("failed to format message\n"); + } else { + dbus_send(connection, msg, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, + "Hello"); + } + + // dbus_free_message(msg); + + dbus_disconnect (connection); + + return (0); +} Index: user/sbruno/pxe_http/devd2dbus/bsdbus.h =================================================================== --- user/sbruno/pxe_http/devd2dbus/bsdbus.h (nonexistent) +++ user/sbruno/pxe_http/devd2dbus/bsdbus.h (revision 245442) @@ -0,0 +1,186 @@ +#ifndef BSDBUS_H +#define BSDBUS_H + +#include +#include + +enum DBus_connection_state { + DBUS_CONNECTED = 0, + DBUS_DISCONNECTED = 1 +}; + +enum DBus_connection_type { + DBUS_SYSTEM_BUS = 0, + DBUS_SESSION_BUS = 1, + DBUS_ALL_KNOWN_BUS = 2 +}; + +const char DBus_connection_str[DBUS_ALL_KNOWN_BUS][32] = { + "DBUS_SYSTEM_BUS_ADDRESS", + "DBUS_SESSION_BUS_ADDRESS" +}; + +const char DBus_default_path[DBUS_ALL_KNOWN_BUS][32] = { + "/var/run/dbus/system-bus-socket", + "/var/run/dbus/session-bus-socket" +}; + +enum DBus_communication_state { + DBUS_COMMUNICATION_FAILED = 0, + DBUS_COMMUNICATION_OK = 1 +}; + +struct DBus_connection +{ + enum DBus_connection_type type; + enum DBus_connection_state state; + FILE *fd; + int socket; +}; + +enum DBus_param_type +{ + DBUS_PARAM_INVALID = 0, + DBUS_PARAM_BYTE = 1, + DBUS_PARAM_BOOLEAN = 2, + DBUS_PARAM_INT16 = 3, + DBUS_PARAM_UINT16 = 4, + DBUS_PARAM_INT32 = 5, + DBUS_PARAM_UINT32 = 6, + DBUS_PARAM_INT64 = 7, + DBUS_PARAM_UINT64 = 8, + DBUS_PARAM_DOUBLE = 9, + DBUS_PARAM_STRING = 10, + DBUS_PARAM_OBJECT_PATH = 11, + DBUS_PARAM_SIGNATURE = 12, + DBUS_PARAM_ARRAY = 13, + DBUS_PARAM_STRUCT = 14, + DBUS_PARAM_VARIANT = 15, + DBUS_PARAM_DICT_ENTRY = 16, + DBUS_ALL_TYPES = 17 +}; +struct DBus_body_elem +{ + struct DBus_body_elem *next; + enum DBus_param_type type; + void *data; + size_t size; +}; + +struct DBus_message { + // outcoming message data + struct DBus_body_elem *start; + struct DBus_body_elem *tail; + + // raw message data + size_t size; + void *data; + + // raw incoming data + const uint8_t *body; + const uint8_t *header; + + size_t elem_count; +}; + +struct DBus_connection *dbus_connect(enum DBus_connection_type conType); +struct DBus_connection *dbus_open_connect(struct DBus_connection * connection, const char *path); +void dbus_disconnect(struct DBus_connection *connection); + +enum DBus_communication_state dbus_send(struct DBus_connection *connection, + struct DBus_message *message, + const char *path, const char *interface, const char *name); + +void dbus_free_message(struct DBus_message *message); +void *dbus_format_message(struct DBus_message *message, int pad); +struct DBus_message *dbus_alloc_message(); + +void dbus_push_elem(struct DBus_message *message, enum DBus_param_type type, void *data, size_t size); +void dbus_push_byte(struct DBus_message *message, uint8_t val); +void dbus_push_boolean(struct DBus_message *message, uint32_t val); +void dbus_push_int16(struct DBus_message *message, int16_t val); +void dbus_push_uint16(struct DBus_message *message, uint16_t val); +void dbus_push_int32(struct DBus_message *message, int32_t val); +void dbus_push_uint32(struct DBus_message *message, uint32_t val); +void dbus_push_int64(struct DBus_message *message, int64_t val); +void dbus_push_uint64(struct DBus_message *message, uint64_t val); +void dbus_push_double(struct DBus_message *message, double val); +void dbus_push_string(struct DBus_message *message, const char *val); +void dbus_push_object_path(struct DBus_message *message, const char *val); +void dbus_push_signature(struct DBus_message *message, const char *val); +void dbus_push_struct_align(struct DBus_message *message); + +#define RETURN_IF(x) (if (x) return); + +enum DBus_endian { + DBUS_BIG_ENDIAN = (uint8_t)'B', + DBUS_LITTLE_ENDIAN = (uint8_t)'l' +}; + +enum DBus_message_type { + DBUS_MESSAGE_INVALID = 0, + DBUS_METHOD_CALL = 1, + DBUS_METHOD_RETURN = 2, + DBUS_ERROR = 3, + DBUS_SIGNAL = 4 +}; + +enum DBus_message_flags { + DBUS_NO_REPLY_EXPECTED = 0x1, + DBUS_NO_AUTO_START = 0x2 +}; + +const uint8_t DBUS_PROTOCOL_VERSION = 1; + +struct DBus_message_header +{ + uint8_t endyFlag; + uint8_t type; + uint8_t flags; + uint8_t proto; + uint32_t length; + uint32_t serial; + uint32_t arrSize; + /* ended by array of struct (byte, variant) */ +}; + +struct DBus_tube +{ + struct DBus_connection *connection; + struct DBus_message_header header; + struct DBus_message *header_fields; +}; + +struct DBus_tube *dbus_signal_tube(struct DBus_connection *connection, + const char *path, const char *interface, char *signature); + +void dbus_tube_send(struct DBus_tube *tube, + const char *name, + struct DBus_message *message); + +void dbus_tube_close(struct DBus_tube_open); + +enum DBus_field_code { + DBUS_INVALID = 0, + DBUS_PATH = 1, + DBUS_INTERFACE = 2, + DBUS_MEMBER = 3, + DBUS_ERROR_NAME = 4, + DBUS_REPLY_SERIAL = 5, + DBUS_DESTINATION = 6, + DBUS_SENDER = 7, + DBUS_SIGNATURE = 8, + DBUS_ALL_FIELDS = 9 +}; + +const size_t DBus_field_align[DBUS_ALL_TYPES] = { 0, 1, 4, 2, 2, 4, 4, 8, 8, 8, 4, 4, 1, 4, 8, 1, 8 }; +const uint8_t DBus_param_code[DBUS_ALL_TYPES] = { 0, 121, 98, 110, 113, 105, 117, 120, 116, 100, 115, 111, 103, 97, 114, 118, 101 }; + +const char DBUS_INTERFACE_DBUS[] = "org.freedesktop.DBus"; +const char DBUS_SERVICE_DBUS[] = "org.freedesktop.DBus"; +const char DBUS_PATH_DBUS[] = "/org/freedesktop/DBus"; + +const int DBUS_NO_PADDING = 0; + +#endif /* BSDBUS_H */ + Index: user/sbruno/pxe_http/httpfs.c =================================================================== --- user/sbruno/pxe_http/httpfs.c (nonexistent) +++ user/sbruno/pxe_http/httpfs.c (revision 245442) @@ -0,0 +1,343 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include +#include + +#include "pxe_core.h" +#include "pxe_http.h" +#include "pxe_ip.h" +#include "pxe_sock.h" + +static int http_open(const char *path, struct open_file *f); +static int http_close(struct open_file *f); +static int http_read(struct open_file *f, void *buf, size_t size, + size_t *resid); +static int http_write(struct open_file *f, void *buf, size_t size, + size_t *resid); +static off_t http_seek(struct open_file *f, off_t offset, int where); +static int http_stat(struct open_file *f, struct stat *sb); + +struct fs_ops http_fsops = { + "httpfs", + http_open, + http_close, + http_read, + http_write, + http_seek, + http_stat, + null_readdir +}; + +/* http server name. It is set if rootpath option was in DHCP reply */ +char servername[256] = {0}; + +void +handle_cleanup(PXE_HTTP_HANDLE *httpfile) +{ + if (httpfile == NULL) + return; + + if (httpfile->buf != NULL) + free(httpfile->buf); + + if (httpfile->filename != NULL) + free(httpfile->filename); + + if ( (httpfile->servername != NULL) && + (!servername[0]) ) + free(httpfile->servername); + + if (httpfile->socket != -1) + pxe_close(httpfile->socket); + + free(httpfile); +} + +static int +http_open(const char *path, struct open_file *f) +{ +#ifdef PXE_HTTP_DEBUG + printf("http_open(): %s\n", path); +#endif + PXE_HTTP_HANDLE *httpfile = + (PXE_HTTP_HANDLE *)malloc(sizeof(PXE_HTTP_HANDLE)); + + if (httpfile == NULL) + return (ENOMEM); + + pxe_memset(httpfile, 0, sizeof(PXE_HTTP_HANDLE)); + + httpfile->offset = 0; + httpfile->socket = -1; + + httpfile->filename = strdup(path); + + if (httpfile->filename == NULL) { + handle_cleanup(httpfile); + return (ENOMEM); + } + + pxe_memcpy(pxe_get_ip(PXE_IP_WWW), &httpfile->addr, sizeof(PXE_IPADDR)); + + if (servername[0]) { + httpfile->servername = servername; + } else { + httpfile->servername = strdup(inet_ntoa(httpfile->addr.ip)); + } + +#ifdef PXE_DEBUG_HELL + printf("servername: %s\n", httpfile->servername); +#endif + if (httpfile->servername == NULL) { + handle_cleanup(httpfile); + } + + httpfile->buf = malloc(PXE_MAX_HTTP_HDRLEN); + + if (httpfile->buf == NULL) { + handle_cleanup(httpfile); + return (ENOMEM); + } + + httpfile->bufsize = PXE_MAX_HTTP_HDRLEN; + + if (!pxe_exists(httpfile)) { + handle_cleanup(httpfile); + return (EEXIST); + } + + f->f_fsdata = (void *) httpfile; + +#ifdef PXE_HTTP_DEBUG + printf("http_open(): %s opened\n", httpfile->filename); +#endif + + return (0); +} + +static int +http_read(struct open_file *f, void *addr, size_t size, size_t *resid) +{ + PXE_HTTP_HANDLE *httpfile = (PXE_HTTP_HANDLE *) f->f_fsdata; + int result = -1; + + if (httpfile == NULL) { + printf("http_read(): NULL file descriptor.\n"); + return (EINVAL); + } + +#ifdef PXE_HTTP_DEBUG_HELL + printf("http_read(): %s:%llu+%lu\n", + httpfile->filename, httpfile->offset, size); +#endif + if (((httpfile->size != PXE_HTTP_SIZE_UNKNOWN) && + (httpfile->offset >= httpfile->size)) || + (size == 0)) + { + if (resid) + *resid = size; +#ifdef PXE_HTTP_DEBUG_HELL + printf("http_read(): EOF\n"); +#endif + return (0); + } + + size_t to_read = (httpfile->offset + size < httpfile->size) ? + size: httpfile->size - (size_t)httpfile->offset; + +#ifndef PXE_HTTPFS_CACHING + result = pxe_get(httpfile, to_read, addr); +#else + void *addr2 = addr; + int part1 = -1; + + if (httpfile->cache_size < to_read) { + + /* read all we have in buffer */ + if (httpfile->cache_size != 0) { + part1 = pxe_recv(httpfile->socket, addr2, + httpfile->cache_size, PXE_SOCK_BLOCKING); +#ifdef PXE_HTTP_DEBUG_HELL + printf("http_read(): cache -> %ld/%lu/%lu/%u bytes\n", + part1, to_read, size, httpfile->cache_size); +#endif + } + + if (part1 != -1) { + to_read -= part1; + addr2 += part1; + httpfile->cache_size -= part1; + } + + /* update cache. If auto keep-alive, then skip socket check */ + PXE_BUFFER *buf = NULL; + +#ifndef PXE_HTTP_AUTO_KEEPALIVE + if (httpfile->socket != -1) { + + PXE_BUFFER *buf = + pxe_sock_recv_buffer(httpfile->socket); +#endif + size_t to_get = httpfile->size - httpfile->offset - + ((part1 != -1) ? part1 : 0 ); + + if (buf != NULL) { + if (to_get > buf->bufsize / 2) + to_get = buf->bufsize / 2; + } else { + if (to_get > PXE_DEFAULT_RECV_BUFSIZE / 2) + to_get = PXE_DEFAULT_RECV_BUFSIZE / 2; + } + +#ifdef PXE_HTTP_DEBUG_HELL + printf("http_read(): cache <- %lu bytes\n", to_get); +#endif + /* if none keep-alive connection, then connection + * is already closed, but we used socket recv buffer + * to store cache data till now. Now, closing socket. + */ + if ( (httpfile->isKeepAlive == 0) && + (httpfile->socket != -1) ) + pxe_close(httpfile->socket); + + pxe_get(httpfile, to_get, NULL); +#ifndef PXE_HTTP_AUTO_KEEPALIVE + } +#endif + } + + /* try reading of cache */ + if (httpfile->cache_size < to_read) { + printf("http_read(): read of cache failed\n"); + return (EINVAL); + } + + result = pxe_recv(httpfile->socket, addr2, to_read, PXE_SOCK_BLOCKING); +#ifdef PXE_HTTP_DEBUG_HELL + printf("http_read(): cache > %ld/%lu/%lu/%u bytes\n", + result, to_read, size, httpfile->cache_size); +#endif + if (result != -1) { + httpfile->cache_size -= to_read; + result += (part1 != -1) ? part1 : 0; + } else + result = part1; + +#endif + if (result == -1) { + printf("http_read(): failed to read\n"); + return (EINVAL); + } + + httpfile->offset += result; + +/* #ifdef PXE_HTTP_DEBUG */ + if (httpfile->size != PXE_HTTP_SIZE_UNKNOWN) + printf("%3llu%%\b\b\b\b", + 100LL * httpfile->offset / httpfile->size); + else + printf("http_read(): %llu byte(s) read\n", httpfile->offset); +/* #endif */ + if (resid) + *resid = size - result; + + return (0); +} + +static int +http_close(struct open_file *f) +{ + PXE_HTTP_HANDLE *httpfile = (PXE_HTTP_HANDLE *) f->f_fsdata; + +#ifdef PXE_HTTP_DEBUG + printf("http_close(): closing file %s\n", httpfile->filename); +#endif + handle_cleanup(httpfile); + + return (0); +} + +static int +http_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + /* cannot write */ + return (EROFS); +} + +static int +http_stat(struct open_file *f, struct stat *sb) +{ + PXE_HTTP_HANDLE *httpfile = (PXE_HTTP_HANDLE *) f->f_fsdata; + +#ifdef PXE_HTTP_DEBUG + printf("http_stat(): stat for file %s\n", httpfile->filename); +#endif + sb->st_mode = 0444 | S_IFREG; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + + sb->st_size = (httpfile != NULL) ? httpfile->size : -1; + + return (0); +} + +static off_t +http_seek(struct open_file *f, off_t offset, int where) +{ + PXE_HTTP_HANDLE *httpfile = (PXE_HTTP_HANDLE *) f->f_fsdata; + +#ifdef PXE_HTTP_DEBUG + printf("http_seek(): file 0x%x\n", httpfile); +#endif + + if (httpfile == NULL) { /* to be sure */ + errno = EINVAL; + return (-1); + } + + switch (where) { + case SEEK_SET: + httpfile->offset = offset; + break; + + case SEEK_CUR: + httpfile->offset += offset; + break; + + default: + errno = EOFFSET; + return (-1); + } +#ifdef PXE_HTTPFS_CACHING + /* if we seeked somewhere, cache failed, need clean it */ + pxe_recv(httpfile->socket, httpfile->cache_size, NULL, PXE_SOCK_BLOCKING); + httpfile->cache_size = 0; +#endif + return (httpfile->offset); +} Index: user/sbruno/pxe_http/httpfs.h =================================================================== --- user/sbruno/pxe_http/httpfs.h (nonexistent) +++ user/sbruno/pxe_http/httpfs.h (revision 245442) @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef HTTPFS_INCLUDED +#define HTTPFS_INCLUDED + +/* + * Implements httpfs - illusion of filesystem through http + */ + +#include + +extern struct fs_ops http_fsops; + +#endif Index: user/sbruno/pxe_http/i386_mod/Makefile =================================================================== --- user/sbruno/pxe_http/i386_mod/Makefile (nonexistent) +++ user/sbruno/pxe_http/i386_mod/Makefile (revision 245442) @@ -0,0 +1,9 @@ +# $FreeBSD: src/sys/boot/i386/Makefile,v 1.21 2007/05/29 14:35:57 simokawa Exp $ + +SUBDIR= mbr boot0 boot0sio btx boot2 cdboot kgzldr libi386 libfirewire \ + pxe_http loader + +# special boot programs, 'self-extracting boot2+loader' +SUBDIR+= pxeldr + +.include Index: user/sbruno/pxe_http/libi386_mod/Makefile =================================================================== --- user/sbruno/pxe_http/libi386_mod/Makefile (nonexistent) +++ user/sbruno/pxe_http/libi386_mod/Makefile (revision 245442) @@ -0,0 +1,64 @@ +# $FreeBSD: src/sys/boot/i386/libi386/Makefile,v 1.43 2007/10/12 17:09:43 ps Exp $ +# +LIB= i386 +INTERNALLIB= + +SRCS= biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \ + biospci.c biossmap.c bootinfo.c bootinfo32.c bootinfo64.c \ + comconsole.c devicename.c elf32_freebsd.c \ + elf64_freebsd.c \ + i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \ + smbios.c time.c vidconsole.c amd64_tramp.S + +# Enable PXE TFTP or NFS support, not both. +.if defined(LOADER_TFTP_SUPPORT) +CFLAGS+= -DLOADER_TFTP_SUPPORT +.else +CFLAGS+= -DLOADER_NFS_SUPPORT +.endif + +BOOT_COMCONSOLE_PORT?= 0x3f8 +CFLAGS+= -DCOMPORT=${BOOT_COMCONSOLE_PORT} + +BOOT_COMCONSOLE_SPEED?= 9600 +CFLAGS+= -DCOMSPEED=${BOOT_COMCONSOLE_SPEED} + +.ifdef(BOOT_BIOSDISK_DEBUG) +# Make the disk code more talkative +CFLAGS+= -DDISK_DEBUG +.endif + +.if !defined(BOOT_HIDE_SERIAL_NUMBERS) +# Export serial numbers, UUID, and asset tag from loader. +CFLAGS+= -DSMBIOS_SERIAL_NUMBERS +.endif + +# Include simple terminal emulation (cons25-compatible) +CFLAGS+= -DTERM_EMU + +# Enable PXE debugging +CDLAGS+= -DPXE_DEBUG + +# Allow pxe_http perform udpread/udpwrite +CFLAGS+= -DPXEHTTP_UDP_FOR_LIBSTAND + +# XXX: make alloca() useable +CFLAGS+= -Dalloca=__builtin_alloca + +CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../btx/lib \ + -I${.CURDIR}/../../../contrib/dev/acpica \ + -I${.CURDIR}/../../.. -I. -I${.CURDIR}/../pxe_http/ +# the location of libstand +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ + +.if ${MACHINE_ARCH} == "amd64" +CLEANFILES+= machine +machine: + ln -sf ${.CURDIR}/../../../i386/include machine +.endif + +.include + +.if ${MACHINE_ARCH} == "amd64" +beforedepend ${OBJS}: machine +.endif Index: user/sbruno/pxe_http/libi386_mod/pxe.c =================================================================== --- user/sbruno/pxe_http/libi386_mod/pxe.c (nonexistent) +++ user/sbruno/pxe_http/libi386_mod/pxe.c (revision 245442) @@ -0,0 +1,533 @@ +/*- + * Copyright (c) 2000 Alfred Perlstein + * Copyright (c) 2000 Paul Saab + * Copyright (c) 2000 John Baldwin + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#include +__FBSDID("$FreeBSD: src/sys/boot/i386/libi386/pxe.c,v 1.23 2007/10/12 17:09:43 ps Exp $"); + +#include +#include +#include + +#include +#include +#include + +#include +#include +#ifdef LOADER_NFS_SUPPORT +#include +#endif + +#include + +#include +#include +#include "btxv86.h" +#include "pxe.h" +#include "pxe_core.h" +#include "pxe_dhcp.h" +#include "pxe_isr.h" +#include "pxe_ip.h" +#include "pxe_udp.h" + +#define PXE_TFTP_BUFFER_SIZE 512 + +#ifndef PXEHTTP_UDP_FOR_LIBSTAND +extern uint8_t *scratch_buffer; +extern uint8_t *data_buffer; +#endif + +extern char servername[256]; +static pxenv_t *pxenv_p = NULL; /* PXENV+ */ +static pxe_t *pxe_p = NULL; /* !PXE */ + +int pxe_sock = -1; +static int pxe_opens = 0; + +void pxe_enable(void *pxeinfo); + +static int pxe_init(void); +static int pxe_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize); + +static int pxe_open(struct open_file *f, ...); +static int pxe_close(struct open_file *f); +static void pxe_cleanup(void); +static void pxe_setnfshandle(char *rootpath); +static void pxe_print(int verbose); + +static int pxe_netif_match(struct netif *nif, void *machdep_hint); +static int pxe_netif_probe(struct netif *nif, void *machdep_hint); +static void pxe_netif_init(struct iodesc *desc, void *machdep_hint); +static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, + time_t timeout); + +static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len); +static void pxe_netif_end(struct netif *nif); + +extern struct netif_stats pxe_st[]; + +struct netif_dif pxe_ifs[] = { + /* dif_unit dif_nsel dif_stats dif_private */ + {0, 1, &pxe_st[0], 0} + }; + +struct netif_stats pxe_st[NENTS(pxe_ifs)]; + +struct netif_driver pxenetif = { + "pxenet", + pxe_netif_match, + pxe_netif_probe, + pxe_netif_init, + pxe_netif_get, + pxe_netif_put, + pxe_netif_end, + pxe_ifs, + NENTS(pxe_ifs) +}; + +struct netif_driver *netif_drivers[] = { + &pxenetif, + NULL +}; + +struct devsw pxedisk = { + "pxe", + DEVT_NET, + pxe_init, + pxe_strategy, + pxe_open, + pxe_close, + noioctl, + pxe_print, + pxe_cleanup +}; + +/* pxe_enable() - This function is called by the loader to enable PXE support + * if we are booted by PXE. + * in: + * pxeinfo - pointer is a pointer to the PXENV+ structure. + * out: + * none + */ +void +pxe_enable(void *pxeinfo) +{ + + pxenv_p = (pxenv_t *)pxeinfo; + pxe_p = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 + + pxenv_p->PXEPtr.offset); +} + +/* pxe_init() - inits pxe_core structs + * in: + * none + * out: + * 2 - already initialized + * 1 - if pxe structures are found & initialized + * 0 - failed + */ +static int +pxe_init(void) +{ + + if (__pxe_nic_irq != 0) + return (2); + + return pxe_core_init(pxenv_p, pxe_p); +} + +/* block device strategy function */ +static int +pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size, + char *buf, size_t *rsize) +{ + + return (EIO); +} + +static void +pxe_print(int verbose) +{ + printf(" pxenet0: MAC %6D\n", pxe_get_mymac(), ":"); + printf(" ISR: at %x:%x (chained at: %x:%x)\n", + __pxe_entry_seg, __pxe_entry_off, + __chained_irq_seg, __chained_irq_off); + + return; +} + +static int +pxe_open(struct open_file *f, ...) +{ + va_list args; + char *devname = NULL; + int i = 0; + + va_start(args, f); + devname = va_arg(args, char*); + va_end(args); + + if (pxe_opens == 0) { + /* Find network interface. */ + if (pxe_sock < 0) { + pxe_sock = netif_open(devname); + + if (pxe_sock < 0) { + printf("pxe_open: netif_open() failed\n"); + return (ENXIO); + } + + } + +#ifdef PXE_BOOTP_USE_LIBSTAND + const PXE_IPADDR *addr = pxe_get_ip(PXE_IP_ROOT); + + if ( (addr->ip == 0)) { + pxe_dhcp_query(0); + pxe_core_update_bootp(); + +#ifdef PXEHTTP_UDP_FOR_LIBSTAND + gateip.s_addr = pxe_get_ip(PXE_IP_GATEWAY)->ip; + rootip.s_addr = pxe_get_ip(PXE_IP_ROOT)->ip; + netmask = pxe_get_ip(PXE_IP_NETMASK)->ip; + myip.s_addr = pxe_get_ip(PXE_IP_MY)->ip; + nameip.s_addr = pxe_get_ip(PXE_IP_NAMESERVER)->ip; +#endif + } +#endif /* PXE_BOOTP_USE_LIBSTAND */ + } + ++pxe_opens; + f->f_devdata = &pxe_sock; + + return (0); +} + +static int +pxe_close(struct open_file *f) +{ + /* On last close, do netif close, etc. */ + f->f_devdata = NULL; + + if (pxe_opens) + --pxe_opens; + + /* Not last close? */ + if (pxe_opens > 0) + return (0); + +#ifdef LOADER_NFS_SUPPORT + /* get an NFS filehandle for our root filesystem */ + pxe_setnfshandle(rootpath); +#endif + if (pxe_sock >= 0) { +#ifdef PXE_DEBUG + printf("pxe_close: calling netif_close()\n"); +#endif + netif_close(pxe_sock); + pxe_sock = -1; + } + + return (0); +} + +static void +pxe_cleanup(void) +{ + pxe_core_shutdown(); +} + +static int +pxe_netif_match(struct netif *nif, void *machdep_hint) +{ +#ifdef PXE_DEBUG + printf("pxe_netif_match() called."); +#endif + return (1); +} + + +static int +pxe_netif_probe(struct netif *nif, void *machdep_hint) +{ +#ifdef PXE_DEBUG + printf("pxe_netif_probe() called."); +#endif + +#ifdef PXEHTTP_UDP_FOR_LIBSTAND + if (__pxe_nic_irq == 0) + return (-1); +#else + t_PXENV_UDP_OPEN *udpopen_p = (t_PXENV_UDP_OPEN *)scratch_buffer; + + bzero(udpopen_p, sizeof(*udpopen_p)); + + const PXE_IPADDR *my = pxe_get_ip(PXE_IP_MY); + udpopen_p->src_ip = my->ip; + + pxe_core_call(PXENV_UDP_OPEN); + + if (udpopen_p->status != 0) { + printf("pxe_netif_probe: failed %x\n", udpopen_p->status); + return (-1); + } +#endif + return (0); +} + +static void +pxe_netif_end(struct netif *nif) +{ +#ifdef PXE_DEBUG + printf("pxe_netif_end() called."); +#endif + +#ifndef PXEHTTP_UDP_FOR_LIBSTAND + t_PXENV_UDP_CLOSE *udpclose_p = (t_PXENV_UDP_CLOSE *)scratch_buffer; + + bzero(udpclose_p, sizeof(*udpclose_p)); + + pxe_core_call(PXENV_UDP_CLOSE); + + if (udpclose_p->status != 0) + printf("pxe_end failed %x\n", udpclose_p->status); +#endif +} + +static void +pxe_netif_init(struct iodesc *desc, void *machdep_hint) +{ + +#ifdef PXE_DEBUG + printf("pxe_netif_init(): called.\n"); +#endif + uint8_t *mac = (uint8_t *)pxe_get_mymac(); + + int i; + for (i = 0; i < 6; ++i) + desc->myea[i] = mac[i]; + + const PXE_IPADDR *my = pxe_get_ip(PXE_IP_MY); + desc->xid = my->ip; +} + +static int +pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) +{ +#ifdef PXE_DEBUG + printf("pxe_netif_get(): called.\n"); +#endif + return (len); +} + +static int +pxe_netif_put(struct iodesc *desc, void *pkt, size_t len) +{ +#ifdef PXE_DEBUG + printf("pxe_netif_put(): called.\n"); +#endif + return (len); +} + +#if defined(LOADER_NFS_SUPPORT) +/* + * Reach inside the libstand NFS code and dig out an NFS handle + * for the root filesystem. + */ +struct nfs_iodesc { + struct iodesc *iodesc; + off_t off; + u_char fh[NFS_FHSIZE]; + /* structure truncated here */ +}; + +extern struct nfs_iodesc nfs_root_node; +extern int rpc_port; + +static void +pxe_rpcmountcall() +{ + struct iodesc *d; + int error; + + if (!(d = socktodesc(pxe_sock))) + return; + d->myport = htons(--rpc_port); + d->destip = rootip; + if ((error = nfs_getrootfh(d, rootpath, nfs_root_node.fh)) != 0) + printf("NFS MOUNT RPC error: %d\n", error); + nfs_root_node.iodesc = d; +} + +static void +pxe_setnfshandle(char *rootpath) +{ + int i; + u_char *fh; + char buf[2 * NFS_FHSIZE + 3], *cp; + + /* + * If NFS files were never opened, we need to do mount call + * ourselves. Use nfs_root_node.iodesc as flag indicating + * previous NFS usage. + */ + if (nfs_root_node.iodesc == NULL) + pxe_rpcmountcall(); + + fh = &nfs_root_node.fh[0]; + buf[0] = 'X'; + cp = &buf[1]; + for (i = 0; i < NFS_FHSIZE; i++, cp += 2) + sprintf(cp, "%02x", fh[i]); + sprintf(cp, "X"); + setenv("boot.nfsroot.nfshandle", buf, 1); +} +#endif + +#ifdef PXEHTTP_UDP_FOR_LIBSTAND +/* new versions of udp send/recv functions */ +ssize_t +sendudp(struct iodesc *h, void *pkt, size_t len) +{ +#ifdef PXE_DEBUG_HELL + printf("sendudp(): sending %u bytes from me:%u -> %s:%u\n", + len, ntohs(h->myport), + inet_ntoa(h->destip), ntohs(h->destport)); +#endif + void *ipdata = pkt - sizeof(PXE_UDP_PACKET); + + PXE_IPADDR dst; + dst.ip = h->destip.s_addr; + + if (!pxe_udp_send(ipdata, &dst, ntohs(h->destport), + ntohs(h->myport), len + sizeof(PXE_UDP_PACKET))) + { + printf("sendudp(): failed\n"); + return (-1); + } + + return (len); +} + +ssize_t +readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) +{ + PXE_UDP_DGRAM dgram; + struct udphdr *uh = (struct udphdr *) pkt - 1; + + /* process any queued incoming packets */ + pxe_core_recv_packets(); + + /* reading from default socket */ + int recv = pxe_udp_read(NULL, pkt, len, &dgram); + + if (recv == -1) { + printf("readudp(): failed\n"); + return (-1); + } +#ifdef PXE_DEBUG_HELL + printf("readudp(): received %d(%u/%u) bytes from %u port\n", + recv, len, dgram.size, dgram.src_port); +#endif + uh->uh_sport = htons(dgram.src_port); + + return (recv); +} + +#else /* !defined(PXEHTTP_UDP_FOR_LIBSTAND) */ +/* old variants of udp send/recv functions */ +ssize_t +sendudp(struct iodesc *h, void *pkt, size_t len) +{ + t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer; + bzero(udpwrite_p, sizeof(*udpwrite_p)); + + udpwrite_p->ip = h->destip.s_addr; + udpwrite_p->dst_port = h->destport; + udpwrite_p->src_port = h->myport; + udpwrite_p->buffer_size = len; + udpwrite_p->buffer.segment = VTOPSEG(pkt); + udpwrite_p->buffer.offset = VTOPOFF(pkt); + + if (netmask == 0 || SAMENET(myip, h->destip, netmask)) + udpwrite_p->gw = 0; + else + udpwrite_p->gw = gateip.s_addr; + + pxe_core_call(PXENV_UDP_WRITE); +#if 0 + /* XXX - I dont know why we need this. */ + delay(1000); +#endif + if (udpwrite_p->status != 0) { + /* XXX: This happens a lot. It shouldn't. */ + if (udpwrite_p->status != 1) + printf("sendudp failed %x\n", udpwrite_p->status); + + return (-1); + } + + return (len); +} + +ssize_t +readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) +{ + t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer; + struct udphdr *uh = NULL; + + uh = (struct udphdr *) pkt - 1; + bzero(udpread_p, sizeof(*udpread_p)); + + udpread_p->dest_ip = h->myip.s_addr; + udpread_p->d_port = h->myport; + udpread_p->buffer_size = len; + udpread_p->buffer.segment = VTOPSEG(data_buffer); + udpread_p->buffer.offset = VTOPOFF(data_buffer); + + pxe_core_call(PXENV_UDP_READ); + +#if 0 + /* XXX - I dont know why we need this. */ + delay(1000); +#endif + if (udpread_p->status != 0) { + /* XXX: This happens a lot. It shouldn't. */ + if (udpread_p->status != 1) + printf("readudp failed %x\n", udpread_p->status); + + return (-1); + } + + bcopy(data_buffer, pkt, udpread_p->buffer_size); + uh->uh_sport = udpread_p->s_port; + + return (udpread_p->buffer_size); +} + +#endif /* PXEHTTP_UDP_FOR_LIBSTAND */ Index: user/sbruno/pxe_http/libi386_mod/pxe.h =================================================================== --- user/sbruno/pxe_http/libi386_mod/pxe.h (nonexistent) +++ user/sbruno/pxe_http/libi386_mod/pxe.h (revision 245442) @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2000 Alfred Perlstein + * All rights reserved. + * Copyright (c) 2000 Paul Saab + * All rights reserved. + * Copyright (c) 2000 John Baldwin + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD: src/sys/boot/i386/libi386/pxe.h,v 1.6 2002/09/23 18:54:26 alfred Exp $ + */ + +/* + * The typedefs and structures declared in this file + * clearly violate style(9), the reason for this is to conform to the + * typedefs/structure-names used in the Intel literature to avoid confusion. + * + * It's for your own good. :) + */ + +/* It seems that intel didn't think about ABI, + * either that or 16bit ABI != 32bit ABI (which seems reasonable) + * I have to thank Intel for the hair loss I incurred trying to figure + * out why PXE was mis-reading structures I was passing it (at least + * from my point of view) + * + * Solution: use gcc's '__packed' to correctly align + * structures passed into PXE + * Question: does this really work for PXE's expected ABI? + */ +#ifndef __PXE__H__ +#define __PXE__H__ + +#define PACKED __packed + +#define S_SIZE(s) s, sizeof(s) - 1 + +#define IP_STR "%d.%d.%d.%d" +#define IP_ARGS(ip) \ + (int)(ip >> 24) & 0xff, (int)(ip >> 16) & 0xff, \ + (int)(ip >> 8) & 0xff, (int)ip & 0xff + +#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ARGS(mac) \ + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + +#define PXENFSROOTPATH "/pxeroot" + +typedef struct { + uint16_t offset; + uint16_t segment; +} SEGOFF16_t; + +typedef struct { + uint16_t Seg_Addr; + uint32_t Phy_Addr; + uint16_t Seg_Size; +} SEGDESC_t; + +typedef uint16_t SEGSEL_t; +typedef uint16_t PXENV_STATUS_t; +typedef uint32_t IP4_t; +typedef uint32_t ADDR32_t; +typedef uint16_t UDP_PORT_t; + +#define MAC_ADDR_LEN 16 +typedef uint8_t MAC_ADDR[MAC_ADDR_LEN]; + +/* PXENV+ */ +typedef struct { + uint8_t Signature[6]; /* 'PXENV+' */ + uint16_t Version; /* MSB = major, LSB = minor */ + uint8_t Length; /* structure length */ + uint8_t Checksum; /* checksum pad */ + SEGOFF16_t RMEntry; /* SEG:OFF to PXE entry point */ + /* don't use PMOffset and PMSelector (from the 2.1 PXE manual) */ + uint32_t PMOffset; /* Protected mode entry */ + SEGSEL_t PMSelector; /* Protected mode selector */ + SEGSEL_t StackSeg; /* Stack segment address */ + uint16_t StackSize; /* Stack segment size (bytes) */ + SEGSEL_t BC_CodeSeg; /* BC Code segment address */ + uint16_t BC_CodeSize; /* BC Code segment size (bytes) */ + SEGSEL_t BC_DataSeg; /* BC Data segment address */ + uint16_t BC_DataSize; /* BC Data segment size (bytes) */ + SEGSEL_t UNDIDataSeg; /* UNDI Data segment address */ + uint16_t UNDIDataSize; /* UNDI Data segment size (bytes) */ + SEGSEL_t UNDICodeSeg; /* UNDI Code segment address */ + uint16_t UNDICodeSize; /* UNDI Code segment size (bytes) */ + SEGOFF16_t PXEPtr; /* SEG:OFF to !PXE struct, + only present when Version > 2.1 */ +} PACKED pxenv_t; + +/* !PXE */ +typedef struct { + uint8_t Signature[4]; + uint8_t StructLength; + uint8_t StructCksum; + uint8_t StructRev; + uint8_t reserved_1; + SEGOFF16_t UNDIROMID; + SEGOFF16_t BaseROMID; + SEGOFF16_t EntryPointSP; + SEGOFF16_t EntryPointESP; + SEGOFF16_t StatusCallout; + uint8_t reserved_2; + uint8_t SegDescCn; + SEGSEL_t FirstSelector; + SEGDESC_t Stack; + SEGDESC_t UNDIData; + SEGDESC_t UNDICode; + SEGDESC_t UNDICodeWrite; + SEGDESC_t BC_Data; + SEGDESC_t BC_Code; + SEGDESC_t BC_CodeWrite; +} PACKED pxe_t; + +#define PXENV_START_UNDI 0x0000 +typedef struct { + PXENV_STATUS_t Status; + uint16_t ax; + uint16_t bx; + uint16_t dx; + uint16_t di; + uint16_t es; +} PACKED t_PXENV_START_UNDI; + +#define PXENV_UNDI_STARTUP 0x0001 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_STARTUP; + +#define PXENV_UNDI_CLEANUP 0x0002 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_CLEANUP; + +#define PXENV_UNDI_INITIALIZE 0x0003 +typedef struct { + PXENV_STATUS_t Status; + ADDR32_t ProtocolIni; /* Phys addr of a copy of the driver module */ + uint8_t reserved[8]; +} PACKED t_PXENV_UNDI_INITIALIZE; + + +#define MAXNUM_MCADDR 8 +typedef struct { + PXENV_STATUS_t Status; + uint16_t MCastAddrCount; + MAC_ADDR McastAddr[MAXNUM_MCADDR]; +} PACKED t_PXENV_UNDI_MCAST_ADDRESS; + +#define PXENV_UNDI_RESET_ADAPTER 0x0004 +typedef struct { + PXENV_STATUS_t Status; + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED t_PXENV_UNDI_RESET; + +#define PXENV_UNDI_SHUTDOWN 0x0005 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_SHUTDOWN; + +#define PXENV_UNDI_OPEN 0x0006 +typedef struct { + PXENV_STATUS_t Status; + uint16_t OpenFlag; + uint16_t PktFilter; +# define FLTR_DIRECTED 0x0001 +# define FLTR_BRDCST 0x0002 +# define FLTR_PRMSCS 0x0003 +# define FLTR_SRC_RTG 0x0004 + + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED t_PXENV_UNDI_OPEN; + +#define PXENV_UNDI_CLOSE 0x0007 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_CLOSE; + +#define PXENV_UNDI_TRANSMIT 0x0008 +typedef struct { + PXENV_STATUS_t Status; + uint8_t Protocol; +# define P_UNKNOWN 0 +# define P_IP 1 +# define P_ARP 2 +# define P_RARP 3 + + uint8_t XmitFlag; +# define XMT_DESTADDR 0x0000 +# define XMT_BROADCAST 0x0001 + + SEGOFF16_t DestAddr; + SEGOFF16_t TBD; + uint32_t Reserved[2]; +} PACKED t_PXENV_UNDI_TRANSMIT; + +#define MAX_DATA_BLKS 8 +typedef struct { + uint16_t ImmedLength; + SEGOFF16_t Xmit; + uint16_t DataBlkCount; + struct DataBlk { + uint8_t TDPtrType; + uint8_t TDRsvdByte; + uint16_t TDDataLen; + SEGOFF16_t TDDataPtr; + } DataBlock[MAX_DATA_BLKS]; +} PACKED t_PXENV_UNDI_TBD; + +#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009 +typedef struct { + PXENV_STATUS_t Status; + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED t_PXENV_UNDI_SET_MCAST_ADDR; + +#define PXENV_UNDI_SET_STATION_ADDRESS 0x000A +typedef struct { + PXENV_STATUS_t Status; + MAC_ADDR StationAddress; /* Temp MAC addres to use */ +} PACKED t_PXENV_UNDI_SET_STATION_ADDR; + +#define PXENV_UNDI_SET_PACKET_FILTER 0x000B +typedef struct { + PXENV_STATUS_t Status; + uint8_t filter; /* see UNDI_OPEN (0x0006) */ +} PACKED t_PXENV_UNDI_SET_PACKET_FILTER; + +#define PXENV_UNDI_GET_INFORMATION 0x000C +typedef struct { + PXENV_STATUS_t Status; + uint16_t BaseIo; /* Adapter base I/O address */ + uint16_t IntNumber; /* Adapter IRQ number */ + uint16_t MaxTranUnit; /* Adapter maximum transmit unit */ + uint16_t HwType; /* Type of protocol at the hardware addr */ +# define ETHER_TYPE 1 +# define EXP_ETHER_TYPE 2 +# define IEEE_TYPE 6 +# define ARCNET_TYPE 7 + + uint16_t HwAddrLen; /* Length of hardware address */ + MAC_ADDR CurrentNodeAddress; /* Current hardware address */ + MAC_ADDR PermNodeAddress; /* Permanent hardware address */ + SEGSEL_t ROMAddress; /* Real mode ROM segment address */ + uint16_t RxBufCt; /* Receive queue length */ + uint16_t TxBufCt; /* Transmit queue length */ +} PACKED t_PXENV_UNDI_GET_INFORMATION; + +#define PXENV_UNDI_GET_STATISTICS 0x000D +typedef struct { + PXENV_STATUS_t Status; + uint32_t XmitGoodFrames; /* Number of successful transmissions */ + uint32_t RcvGoodFrames; /* Number of good frames received */ + uint32_t RcvCRCErrors; /* Number of frames with CRC errors */ + uint32_t RcvResourceErrors; /* Number of frames dropped */ +} PACKED t_PXENV_UNDI_GET_STATISTICS; + +#define PXENV_UNDI_CLEAR_STATISTICS 0x000E +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_CLEAR_STATISTICS; + +#define PXENV_UNDI_INITIATE_DIAGS 0x000F +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_INITIATE_DIAGS; + +#define PXENV_UNDI_FORCE_INTERRUPT 0x0010 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_FORCE_INTERRUPT; + +#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011 +typedef struct { + PXENV_STATUS_t Status; + IP4_t InetAddr; /* IP mulicast address */ + MAC_ADDR MediaAddr; /* MAC multicast address */ +} PACKED t_PXENV_UNDI_GET_MCAST_ADDR; + +#define PXENV_UNDI_GET_NIC_TYPE 0x0012 +typedef struct { + PXENV_STATUS_t Status; + uint8_t NicType; /* Type of NIC */ +# define PCI_NIC 2 +# define PnP_NIC 3 +# define CardBus_NIC 4 + + union { + struct { + uint16_t Vendor_ID; + uint16_t Dev_ID; + uint8_t Base_Class; + uint8_t Sub_Class; + uint8_t Prog_Intf; + uint8_t Rev; + uint16_t BusDevFunc; + uint16_t SubVendor_ID; + uint16_t SubDevice_ID; + } pci, cardbus; + struct { + uint32_t EISA_Dev_ID; + uint8_t Base_Class; + uint8_t Sub_Class; + uint8_t Prog_Intf; + uint16_t CardSelNum; + } pnp; + } info; +} PACKED t_PXENV_UNDI_GET_NIC_TYPE; + +#define PXENV_UNDI_GET_IFACE_INFO 0x0013 +typedef struct { + PXENV_STATUS_t Status; + uint8_t IfaceType[16]; /* Name of MAC type in ASCII. */ + uint32_t LinkSpeed; /* Defined in NDIS 2.0 spec */ + uint32_t ServiceFlags; /* Defined in NDIS 2.0 spec */ + uint32_t Reserved[4]; /* must be 0 */ +} PACKED t_PXENV_UNDI_GET_NDIS_INFO; + +#define PXENV_UNDI_GET_STATE 0x0015 +typedef struct { + PXENV_STATUS_t Status; +#define PXE_UNDI_GET_STATE_STARTED 1 +#define PXE_UNDI_GET_STATE_INITIALIZED 2 +#define PXE_UNDI_GET_STATE_OPENED 3 + uint8_t UNDIstate; /* UNDI engine state */ +} PACKED t_PXENV_UNDI_GET_STATE; + +#define PXENV_UNDI_ISR 0x0014 +typedef struct { + PXENV_STATUS_t Status; + uint16_t FuncFlag; /* PXENV_UNDI_ISR_OUT_xxx */ + uint16_t BufferLength; /* Length of Frame */ + uint16_t FrameLength; /* Total length of reciever frame */ + uint16_t FrameHeaderLength; /* Length of the media header in Frame */ + SEGOFF16_t Frame; /* receive buffer */ + uint8_t ProtType; /* Protocol type */ + uint8_t PktType; /* Packet Type */ +# define PXENV_UNDI_ISR_IN_START 1 +# define PXENV_UNDI_ISR_IN_PROCESS 2 +# define PXENV_UNDI_ISR_IN_GET_NEXT 3 + + /* one of these will be returned for PXENV_UNDI_ISR_IN_START */ +# define PXENV_UNDI_ISR_OUT_OURS 0 +# define PXENV_UNDI_ISR_OUT_NOT_OUTS 1 + + /* + * one of these will bre returnd for PXEND_UNDI_ISR_IN_PROCESS + * and PXENV_UNDI_ISR_IN_GET_NEXT + */ +# define PXENV_UNDI_ISR_OUT_DONE 0 +# define PXENV_UNDI_ISR_OUT_TRANSMIT 2 +# define PXENV_UNDI_ISR_OUT_RECIEVE 3 +# define PXENV_UNDI_ISR_OUT_BUSY 4 +} PACKED t_PXENV_UNDI_ISR; + +#define PXENV_STOP_UNDI 0x0015 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_STOP_UNDI; + +#define PXENV_TFTP_OPEN 0x0020 +typedef struct { + PXENV_STATUS_t Status; + IP4_t ServerIPAddress; + IP4_t GatewayIPAddress; + uint8_t FileName[128]; + UDP_PORT_t TFTPPort; + uint16_t PacketSize; +} PACKED t_PXENV_TFTP_OPEN; + +#define PXENV_TFTP_CLOSE 0x0021 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_TFTP_CLOSE; + +#define PXENV_TFTP_READ 0x0022 +typedef struct { + PXENV_STATUS_t Status; + uint16_t PacketNumber; + uint16_t BufferSize; + SEGOFF16_t Buffer; +} PACKED t_PXENV_TFTP_READ; + +#define PXENV_TFTP_READ_FILE 0x0023 +typedef struct { + PXENV_STATUS_t Status; + uint8_t FileName[128]; + uint32_t BufferSize; + ADDR32_t Buffer; + IP4_t ServerIPAddress; + IP4_t GatewayIPAdress; + IP4_t McastIPAdress; + UDP_PORT_t TFTPClntPort; + UDP_PORT_t TFTPSrvPort; + uint16_t TFTPOpenTimeOut; + uint16_t TFTPReopenDelay; +} PACKED t_PXENV_TFTP_READ_FILE; + +#define PXENV_TFTP_GET_FSIZE 0x0025 +typedef struct { + PXENV_STATUS_t Status; + IP4_t ServerIPAddress; + IP4_t GatewayIPAdress; + uint8_t FileName[128]; + uint32_t FileSize; +} PACKED t_PXENV_TFTP_GET_FSIZE; + +#define PXENV_UDP_OPEN 0x0030 +typedef struct { + PXENV_STATUS_t status; + IP4_t src_ip; /* IP address of this station */ +} PACKED t_PXENV_UDP_OPEN; + +#define PXENV_UDP_CLOSE 0x0031 +typedef struct { + PXENV_STATUS_t status; +} PACKED t_PXENV_UDP_CLOSE; + +#define PXENV_UDP_READ 0x0032 +typedef struct { + PXENV_STATUS_t status; + IP4_t src_ip; /* IP of sender */ + IP4_t dest_ip; /* Only accept packets sent to this IP */ + UDP_PORT_t s_port; /* UDP source port of sender */ + UDP_PORT_t d_port; /* Only accept packets sent to this port */ + uint16_t buffer_size; /* Size of the packet buffer */ + SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */ +} PACKED t_PXENV_UDP_READ; + +#define PXENV_UDP_WRITE 0x0033 +typedef struct { + PXENV_STATUS_t status; + IP4_t ip; /* dest ip addr */ + IP4_t gw; /* ip gateway */ + UDP_PORT_t src_port; /* source udp port */ + UDP_PORT_t dst_port; /* destination udp port */ + uint16_t buffer_size; /* Size of the packet buffer */ + SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */ +} PACKED t_PXENV_UDP_WRITE; + +#define PXENV_UNLOAD_STACK 0x0070 +typedef struct { + PXENV_STATUS_t Status; + uint8_t reserved[10]; +} PACKED t_PXENV_UNLOAD_STACK; + + +#define PXENV_GET_CACHED_INFO 0x0071 +typedef struct { + PXENV_STATUS_t Status; + uint16_t PacketType; /* type (defined right here) */ +# define PXENV_PACKET_TYPE_DHCP_DISCOVER 1 +# define PXENV_PACKET_TYPE_DHCP_ACK 2 +# define PXENV_PACKET_TYPE_BINL_REPLY 3 + uint16_t BufferSize; /* max to copy, leave at 0 for pointer */ + SEGOFF16_t Buffer; /* copy to, leave at 0 for pointer */ + uint16_t BufferLimit; /* max size of buffer in BC dataseg ? */ +} PACKED t_PXENV_GET_CACHED_INFO; + + +/* structure filled in by PXENV_GET_CACHED_INFO + * (how we determine which IP we downloaded the initial bootstrap from) + * words can't describe... + */ +typedef struct { + uint8_t opcode; +# define BOOTP_REQ 1 +# define BOOTP_REP 2 + uint8_t Hardware; /* hardware type */ + uint8_t Hardlen; /* hardware addr len */ + uint8_t Gatehops; /* zero it */ + uint32_t ident; /* random number chosen by client */ + uint16_t seconds; /* seconds since did initial bootstrap */ + uint16_t Flags; /* seconds since did initial bootstrap */ +# define BOOTP_BCAST 0x8000 /* ? */ + IP4_t cip; /* Client IP */ + IP4_t yip; /* Your IP */ + IP4_t sip; /* IP to use for next boot stage */ + IP4_t gip; /* Relay IP ? */ + MAC_ADDR CAddr; /* Client hardware address */ + uint8_t Sname[64]; /* Server's hostname (Optional) */ + uint8_t bootfile[128]; /* boot filename */ + union { +# if 1 +# define BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size */ +# else +# define BOOTP_DHCPVEND 312 /* DHCP standard vendor field size */ +# endif + uint8_t d[BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options */ + struct { + uint8_t magic[4]; /* DHCP magic cookie */ +# ifndef VM_RFC1048 +# define VM_RFC1048 0x63825363L /* ? */ +# endif + uint32_t flags; /* bootp flags/opcodes */ + uint8_t pad[56]; /* I don't think intel knows what a + union does... */ + } v; + } vendor; +} PACKED BOOTPLAYER; + +#define PXENV_RESTART_TFTP 0x0073 +#define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE + +#define PXENV_START_BASE 0x0075 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_START_BASE; + +#define PXENV_STOP_BASE 0x0076 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_STOP_BASE; + +#endif Index: user/sbruno/pxe_http/libstand_mod/printf.c =================================================================== --- user/sbruno/pxe_http/libstand_mod/printf.c (nonexistent) +++ user/sbruno/pxe_http/libstand_mod/printf.c (revision 245442) @@ -0,0 +1,458 @@ +/*- + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 + */ + +#include +__FBSDID("$FreeBSD: src/lib/libstand/printf.c,v 1.10 2007/01/09 01:02:04 imp Exp $"); + +/* + * Standaloneified version of the FreeBSD kernel printf family. + */ + +#include +#include +#include +#include +#include +#include "stand.h" + +/* + * Note that stdarg.h and the ANSI style va_start macro is used for both + * ANSI and traditional C compilers. + */ +#include + +#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) + +static char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); +static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, size_t size, va_list ap); + +int +printf(const char *fmt, ...) +{ + va_list ap; + int retval; + + va_start(ap, fmt); + retval = kvprintf(fmt, putchar, NULL, 10, 0, ap); + va_end(ap); + return retval; +} + +void +vprintf(const char *fmt, va_list ap) +{ + + kvprintf(fmt, putchar, NULL, 10, 0, ap); +} + +int +sprintf(char *buf, const char *cfmt, ...) +{ + int retval; + va_list ap; + + va_start(ap, cfmt); + retval = kvprintf(cfmt, NULL, (void *)buf, 10, 0, ap); + buf[retval] = '\0'; + va_end(ap); + return retval; +} + +int +snprintf(char *buf, size_t size, const char *cfmt, ...) +{ + int retval; + va_list ap; + size_t maxsize = (size > 1) ? size - 1 : 0; + + if (maxsize == 0) { + buf[0] = '\0'; + return (0); + } + + va_start(ap, cfmt); + retval = kvprintf(cfmt, NULL, (void *)buf, 10, maxsize, ap); + + if (retval < maxsize) + buf[retval] = '\0'; + else + buf[maxsize] = '\0'; + + va_end(ap); + + return (retval); +} + +void +vsprintf(char *buf, const char *cfmt, va_list ap) +{ + int retval; + + retval = kvprintf(cfmt, NULL, (void *)buf, 10, 0, ap); + buf[retval] = '\0'; +} + +/* + * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse + * order; return an optional length and a pointer to the last character + * written in the buffer (i.e., the first character of the string). + * The buffer pointed to by `nbuf' must have length >= MAXNBUF. + */ +static char * +ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) +{ + char *p, c; + + p = nbuf; + *p = '\0'; + do { + c = hex2ascii(num % base); + *++p = upper ? toupper(c) : c; + } while (num /= base); + if (lenp) + *lenp = p - nbuf; + return (p); +} + +/* + * Scaled down version of printf(3). + * + * Two additional formats: + * + * The format %b is supported to decode error registers. + * Its usage is: + * + * printf("reg=%b\n", regval, "*"); + * + * where is the output base expressed as a control character, e.g. + * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, + * the first of which gives the bit number to be inspected (origin 1), and + * the next characters (up to a control character, i.e. a character <= 32), + * give the name of the register. Thus: + * + * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * + * would produce output: + * + * reg=3 + * + * XXX: %D -- Hexdump, takes pointer and separator string: + * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX + * ("%*D", len, ptr, " " -> XX XX XX XX ... + */ +static int +kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, size_t maxsize, va_list ap) +{ +#define PCHAR(c) { int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; \ + if (maxsize && (retval == maxsize)) return (retval); \ + } + char nbuf[MAXNBUF]; + char *d; + const char *p, *percent, *q; + u_char *up; + int ch, n; + uintmax_t num; + int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; + int jflag, tflag, zflag; + int dwidth, upper; + char padc; + int retval = 0; + + num = 0; + if (!func) + d = (char *) arg; + else + d = NULL; + + if (fmt == NULL) + fmt = "(fmt null)\n"; + + if (radix < 2 || radix > 36) + radix = 10; + + for (;;) { + padc = ' '; + width = 0; + while ((ch = (u_char)*fmt++) != '%') { + if (ch == '\0') + return (retval); + PCHAR(ch); + } + percent = fmt - 1; + qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + sign = 0; dot = 0; dwidth = 0; upper = 0; + jflag = 0; tflag = 0; zflag = 0; +reswitch: switch (ch = (u_char)*fmt++) { + case '.': + dot = 1; + goto reswitch; + case '#': + sharpflag = 1; + goto reswitch; + case '+': + sign = 1; + goto reswitch; + case '-': + ladjust = 1; + goto reswitch; + case '%': + PCHAR(ch); + break; + case '*': + if (!dot) { + width = va_arg(ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg(ap, int); + } + goto reswitch; + case '0': + if (!dot) { + padc = '0'; + goto reswitch; + } + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (n = 0;; ++fmt) { + n = n * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + case 'b': + num = va_arg(ap, int); + p = va_arg(ap, char *); + for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) + PCHAR(*q--); + + if (num == 0) + break; + + for (tmp = 0; *p;) { + n = *p++; + if (num & (1 << (n - 1))) { + PCHAR(tmp ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + PCHAR(n); + tmp = 1; + } else + for (; *p > ' '; ++p) + continue; + } + if (tmp) + PCHAR('>'); + break; + case 'c': + PCHAR(va_arg(ap, int)); + break; + case 'D': + up = va_arg(ap, u_char *); + p = va_arg(ap, char *); + if (!width) + width = 16; + while(width--) { + PCHAR(hex2ascii(*up >> 4)); + PCHAR(hex2ascii(*up & 0x0f)); + up++; + if (width) + for (q=p;*q;q++) + PCHAR(*q); + } + break; + case 'd': + case 'i': + base = 10; + sign = 1; + goto handle_sign; + case 'j': + jflag = 1; + goto reswitch; + case 'l': + if (lflag) { + lflag = 0; + qflag = 1; + } else + lflag = 1; + goto reswitch; + case 'n': + if (jflag) + *(va_arg(ap, intmax_t *)) = retval; + else if (qflag) + *(va_arg(ap, quad_t *)) = retval; + else if (lflag) + *(va_arg(ap, long *)) = retval; + else if (zflag) + *(va_arg(ap, size_t *)) = retval; + else + *(va_arg(ap, int *)) = retval; + break; + case 'o': + base = 8; + goto handle_nosign; + case 'p': + base = 16; + sharpflag = (width == 0); + sign = 0; + num = (uintptr_t)va_arg(ap, void *); + goto number; + case 'q': + qflag = 1; + goto reswitch; + case 'r': + base = radix; + if (sign) + goto handle_sign; + goto handle_nosign; + case 's': + p = va_arg(ap, char *); + if (p == NULL) + p = "(null)"; + if (!dot) + n = strlen (p); + else + for (n = 0; n < dwidth && p[n]; n++) + continue; + + width -= n; + + if (!ladjust && width > 0) + while (width--) + PCHAR(padc); + while (n--) + PCHAR(*p++); + if (ladjust && width > 0) + while (width--) + PCHAR(padc); + break; + case 't': + tflag = 1; + goto reswitch; + case 'u': + base = 10; + goto handle_nosign; + case 'X': + upper = 1; + case 'x': + base = 16; + goto handle_nosign; + case 'y': + base = 16; + sign = 1; + goto handle_sign; + case 'z': + zflag = 1; + goto reswitch; +handle_nosign: + sign = 0; + if (jflag) + num = va_arg(ap, uintmax_t); + else if (qflag) + num = va_arg(ap, u_quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, u_long); + else if (zflag) + num = va_arg(ap, size_t); + else + num = va_arg(ap, u_int); + goto number; +handle_sign: + if (jflag) + num = va_arg(ap, intmax_t); + else if (qflag) + num = va_arg(ap, quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, long); + else if (zflag) + num = va_arg(ap, size_t); + else + num = va_arg(ap, int); +number: + if (sign && (intmax_t)num < 0) { + neg = 1; + num = -(intmax_t)num; + } + p = ksprintn(nbuf, num, base, &tmp, upper); + if (sharpflag && num != 0) { + if (base == 8) + tmp++; + else if (base == 16) + tmp += 2; + } + if (neg) + tmp++; + + if (!ladjust && width && (width -= tmp) > 0) + while (width--) + PCHAR(padc); + if (neg) + PCHAR('-'); + if (sharpflag && num != 0) { + if (base == 8) { + PCHAR('0'); + } else if (base == 16) { + PCHAR('0'); + PCHAR('x'); + } + } + + while (*p) + PCHAR(*p--); + + if (ladjust && width && (width -= tmp) > 0) + while (width--) + PCHAR(padc); + + break; + default: + while (percent < fmt) + PCHAR(*percent++); + break; + } + } +#undef PCHAR +} Index: user/sbruno/pxe_http/libstand_mod/stand.h =================================================================== --- user/sbruno/pxe_http/libstand_mod/stand.h (nonexistent) +++ user/sbruno/pxe_http/libstand_mod/stand.h (revision 245442) @@ -0,0 +1,412 @@ +/* + * Copyright (c) 1998 Michael Smith. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD: src/lib/libstand/stand.h,v 1.42 2007/01/09 01:02:04 imp Exp $ + * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $ + */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)stand.h 8.1 (Berkeley) 6/11/93 + */ + +#ifndef STAND_H +#define STAND_H + +#include +#include +#include +#include +#include + +#define CHK(fmt, args...) printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args) +#define PCHK(fmt, args...) {printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args); getchar();} + +#ifndef NULL +#define NULL 0 +#endif + +/* Avoid unwanted userlandish components */ +#define _KERNEL +#include +#undef _KERNEL + +/* special stand error codes */ +#define EADAPT (ELAST+1) /* bad adaptor */ +#define ECTLR (ELAST+2) /* bad controller */ +#define EUNIT (ELAST+3) /* bad unit */ +#define ESLICE (ELAST+4) /* bad slice */ +#define EPART (ELAST+5) /* bad partition */ +#define ERDLAB (ELAST+6) /* can't read disk label */ +#define EUNLAB (ELAST+7) /* unlabeled disk */ +#define EOFFSET (ELAST+8) /* relative seek not supported */ +#define ESALAST (ELAST+8) /* */ + +struct open_file; + +/* + * This structure is used to define file system operations in a file system + * independent way. + * + * XXX note that filesystem providers should export a pointer to their fs_ops + * struct, so that consumers can reference this and thus include the + * filesystems that they require. + */ +struct fs_ops { + const char *fs_name; + int (*fo_open)(const char *path, struct open_file *f); + int (*fo_close)(struct open_file *f); + int (*fo_read)(struct open_file *f, void *buf, + size_t size, size_t *resid); + int (*fo_write)(struct open_file *f, void *buf, + size_t size, size_t *resid); + off_t (*fo_seek)(struct open_file *f, off_t offset, int where); + int (*fo_stat)(struct open_file *f, struct stat *sb); + int (*fo_readdir)(struct open_file *f, struct dirent *d); +}; + +/* + * libstand-supplied filesystems + */ +extern struct fs_ops ufs_fsops; +extern struct fs_ops tftp_fsops; +extern struct fs_ops nfs_fsops; +extern struct fs_ops cd9660_fsops; +extern struct fs_ops gzipfs_fsops; +extern struct fs_ops bzipfs_fsops; +extern struct fs_ops dosfs_fsops; +extern struct fs_ops ext2fs_fsops; +extern struct fs_ops splitfs_fsops; + +/* where values for lseek(2) */ +#define SEEK_SET 0 /* set file offset to offset */ +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#define SEEK_END 2 /* set file offset to EOF plus offset */ + +/* + * Device switch + */ +struct devsw { + const char dv_name[8]; + int dv_type; /* opaque type constant, arch-dependant */ + int (*dv_init)(void); /* early probe call */ + int (*dv_strategy)(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize); + int (*dv_open)(struct open_file *f, ...); + int (*dv_close)(struct open_file *f); + int (*dv_ioctl)(struct open_file *f, u_long cmd, void *data); + void (*dv_print)(int verbose); /* print device information */ + void (*dv_cleanup)(void); +}; + +/* + * libstand-supplied device switch + */ +extern struct devsw netdev; + +extern int errno; + +struct open_file { + int f_flags; /* see F_* below */ + struct devsw *f_dev; /* pointer to device operations */ + void *f_devdata; /* device specific data */ + struct fs_ops *f_ops; /* pointer to file system operations */ + void *f_fsdata; /* file system specific data */ + off_t f_offset; /* current file offset */ + char *f_rabuf; /* readahead buffer pointer */ + size_t f_ralen; /* valid data in readahead buffer */ + off_t f_raoffset; /* consumer offset in readahead buffer */ +#define SOPEN_RASIZE 512 +}; + +#define SOPEN_MAX 8 +extern struct open_file files[]; + +/* f_flags values */ +#define F_READ 0x0001 /* file opened for reading */ +#define F_WRITE 0x0002 /* file opened for writing */ +#define F_RAW 0x0004 /* raw device open - no file system */ +#define F_NODEV 0x0008 /* network open - no device */ + +#define isascii(c) (((c) & ~0x7F) == 0) + +static __inline int isupper(int c) +{ + return c >= 'A' && c <= 'Z'; +} + +static __inline int islower(int c) +{ + return c >= 'a' && c <= 'z'; +} + +static __inline int isspace(int c) +{ + return c == ' ' || (c >= 0x9 && c <= 0xd); +} + +static __inline int isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +static __inline int isxdigit(int c) +{ + return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +static __inline int isalpha(int c) +{ + return isupper(c) || islower(c); +} + +static __inline int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +static __inline int toupper(int c) +{ + return islower(c) ? c - 'a' + 'A' : c; +} + +static __inline int tolower(int c) +{ + return isupper(c) ? c - 'A' + 'a' : c; +} + +/* sbrk emulation */ +extern void setheap(void *base, void *top); +extern char *sbrk(int incr); + +/* Matt Dillon's zalloc/zmalloc */ +extern void *malloc(size_t bytes); +extern void free(void *ptr); +/*#define free(p) {CHK("free %p", p); free(p);} */ /* use for catching guard violations */ +extern void *calloc(size_t n1, size_t n2); +extern void *realloc(void *ptr, size_t size); +extern void *reallocf(void *ptr, size_t size); +extern void mallocstats(void); +#ifdef __alpha__ +extern void free_region(void *start, void *end); +#endif + +/* disklabel support (undocumented, may be junk) */ +struct disklabel; +extern char *getdisklabel(const char *, struct disklabel *); + +extern int printf(const char *fmt, ...) __printflike(1, 2); +extern void vprintf(const char *fmt, __va_list); +extern int sprintf(char *buf, const char *cfmt, ...) __printflike(2, 3); +extern int snprintf(char *buf, size_t size, const char *cfmt, ...) __printflike(3, 4); +extern void vsprintf(char *buf, const char *cfmt, __va_list); + +extern void twiddle(void); + +extern void ngets(char *, int); +#define gets(x) ngets((x), 0) +extern int fgetstr(char *buf, int size, int fd); + +extern int open(const char *, int); +#define O_RDONLY 0x0 +#define O_WRONLY 0x1 +#define O_RDWR 0x2 +extern int close(int); +extern void closeall(void); +extern ssize_t read(int, void *, size_t); +extern ssize_t write(int, void *, size_t); +extern struct dirent *readdirfd(int); + +extern void srandom(u_long seed); +extern u_long random(void); + +/* imports from stdlib, locally modified */ +extern long strtol(const char *, char **, int); +extern char *optarg; /* getopt(3) external variables */ +extern int optind, opterr, optopt, optreset; +extern int getopt(int, char * const [], const char *); + +/* pager.c */ +extern void pager_open(void); +extern void pager_close(void); +extern int pager_output(const char *lines); +extern int pager_file(const char *fname); + +/* No signal state to preserve */ +#define setjmp _setjmp +#define longjmp _longjmp + +/* environment.c */ +#define EV_DYNAMIC (1<<0) /* value was dynamically allocated, free if changed/unset */ +#define EV_VOLATILE (1<<1) /* value is volatile, make a copy of it */ +#define EV_NOHOOK (1<<2) /* don't call hook when setting */ + +struct env_var; +typedef char *(ev_format_t)(struct env_var *ev); +typedef int (ev_sethook_t)(struct env_var *ev, int flags, + const void *value); +typedef int (ev_unsethook_t)(struct env_var *ev); + +struct env_var +{ + char *ev_name; + int ev_flags; + void *ev_value; + ev_sethook_t *ev_sethook; + ev_unsethook_t *ev_unsethook; + struct env_var *ev_next, *ev_prev; +}; +extern struct env_var *environ; + +extern struct env_var *env_getenv(const char *name); +extern int env_setenv(const char *name, int flags, + const void *value, ev_sethook_t sethook, + ev_unsethook_t unsethook); +extern char *getenv(const char *name); +extern int setenv(const char *name, const char *value, + int overwrite); +extern int putenv(const char *string); +extern int unsetenv(const char *name); + +extern ev_sethook_t env_noset; /* refuse set operation */ +extern ev_unsethook_t env_nounset; /* refuse unset operation */ + +/* BCD conversions (undocumented) */ +extern u_char const bcd2bin_data[]; +extern u_char const bin2bcd_data[]; +extern char const hex2ascii_data[]; + +#define bcd2bin(bcd) (bcd2bin_data[bcd]) +#define bin2bcd(bin) (bin2bcd_data[bin]) +#define hex2ascii(hex) (hex2ascii_data[hex]) + +/* min/max (undocumented) */ +static __inline int imax(int a, int b) { return (a > b ? a : b); } +static __inline int imin(int a, int b) { return (a < b ? a : b); } +static __inline long lmax(long a, long b) { return (a > b ? a : b); } +static __inline long lmin(long a, long b) { return (a < b ? a : b); } +static __inline u_int max(u_int a, u_int b) { return (a > b ? a : b); } +static __inline u_int min(u_int a, u_int b) { return (a < b ? a : b); } +static __inline quad_t qmax(quad_t a, quad_t b) { return (a > b ? a : b); } +static __inline quad_t qmin(quad_t a, quad_t b) { return (a < b ? a : b); } +static __inline u_long ulmax(u_long a, u_long b) { return (a > b ? a : b); } +static __inline u_long ulmin(u_long a, u_long b) { return (a < b ? a : b); } + +/* swaps (undocumented, useful?) */ +#ifdef __i386__ +extern u_int32_t bswap32(u_int32_t x); +extern u_int64_t bswap64(u_int64_t x); +#endif + +/* null functions for device/filesystem switches (undocumented) */ +extern int nodev(void); +extern int noioctl(struct open_file *, u_long, void *); +extern void nullsys(void); + +extern int null_open(const char *path, struct open_file *f); +extern int null_close(struct open_file *f); +extern int null_read(struct open_file *f, void *buf, size_t size, size_t *resid); +extern int null_write(struct open_file *f, void *buf, size_t size, size_t *resid); +extern off_t null_seek(struct open_file *f, off_t offset, int where); +extern int null_stat(struct open_file *f, struct stat *sb); +extern int null_readdir(struct open_file *f, struct dirent *d); + + +/* + * Machine dependent functions and data, must be provided or stubbed by + * the consumer + */ +extern int getchar(void); +extern int ischar(void); +extern void putchar(int); +extern int devopen(struct open_file *, const char *, const char **); +extern int devclose(struct open_file *f); +extern void panic(const char *, ...) __dead2 __printflike(1, 2); +extern struct fs_ops *file_system[]; +extern struct devsw *devsw[]; + +/* + * Expose byteorder(3) functions. + */ +#ifndef _BYTEORDER_PROTOTYPED +#define _BYTEORDER_PROTOTYPED +extern uint32_t htonl(uint32_t); +extern uint16_t htons(uint16_t); +extern uint32_t ntohl(uint32_t); +extern uint16_t ntohs(uint16_t); +#endif + +#ifndef _BYTEORDER_FUNC_DEFINED +#define _BYTEORDER_FUNC_DEFINED +#define htonl(x) __htonl(x) +#define htons(x) __htons(x) +#define ntohl(x) __ntohl(x) +#define ntohs(x) __ntohs(x) +#endif + +void *Malloc(size_t, const char *, int); +void *Calloc(size_t, size_t, const char *, int); +void *Realloc(void *, size_t, const char *, int); +void Free(void *, const char *, int); + +#if 1 +#define malloc(x) Malloc(x, __FILE__, __LINE__) +#define calloc(x, y) Calloc(x, y, __FILE__, __LINE__) +#define free(x) Free(x, __FILE__, __LINE__) +#define realloc(x, y) Realloc(x, y, __FILE__, __LINE__) +#else +#define malloc(x) Malloc(x, NULL, 0) +#define calloc(x, y) Calloc(x, y, NULL, 0) +#define free(x) Free(x, NULL, 0) +#define realloc(x, y) Realloc(x, y, NULL, 0) +#endif + +#endif /* STAND_H */ Index: user/sbruno/pxe_http/loader_mod/Makefile =================================================================== --- user/sbruno/pxe_http/loader_mod/Makefile (nonexistent) +++ user/sbruno/pxe_http/loader_mod/Makefile (revision 245442) @@ -0,0 +1,126 @@ +# $FreeBSD: src/sys/boot/i386/loader/Makefile,v 1.85 2007/05/29 14:35:57 simokawa Exp $ + +.include + +PROG= loader.sym +INTERNALPROG= +NEWVERSWHAT= "bootstrap loader" i386 + +# architecture-specific loader code +SRCS= main.c conf.c vers.c + +# Put LOADER_FIREWIRE_SUPPORT=yes in /etc/make.conf for FireWire/dcons support +.if defined(LOADER_FIREWIRE_SUPPORT) +CFLAGS+= -DLOADER_FIREWIRE_SUPPORT +LIBFIREWIRE= ${.OBJDIR}/../libfirewire/libfirewire.a +.endif + +CFLAGS+= -DLOADER_HTTP_SUPPORT + +# Enable HTTP support for PXE +.if !defined(LOADER_HTTP_SUPPORT) + +# Enable PXE TFTP or NFS support, not both. +.if defined(LOADER_TFTP_SUPPORT) +CFLAGS+= -DLOADER_TFTP_SUPPORT +.else +CFLAGS+= -DLOADER_NFS_SUPPORT +.endif + +.endif + +.if ${MACHINE_ARCH} == "amd64" +CFLAGS+= -DLOADER_AMD64_ELF_SUPPORT +.endif + +# Include bcache code. +HAVE_BCACHE= yes + +# Enable PnP and ISA-PnP code. +HAVE_PNP= yes +HAVE_ISABUS= yes + +# Enable more pxe_http functions +#CFLAGS+= -DPXE_MORE + +.if ${MK_FORTH} != "no" +# Enable BootForth +BOOT_FORTH= yes +CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386 +LIBFICL= ${.OBJDIR}/../../ficl/libficl.a +.endif + +.if defined(LOADER_BZIP2_SUPPORT) +CFLAGS+= -DLOADER_BZIP2_SUPPORT +.endif +.if !defined(LOADER_NO_GZIP_SUPPORT) +CFLAGS+= -DLOADER_GZIP_SUPPORT +.endif + +# Always add MI sources +.PATH: ${.CURDIR}/../../common +.include "${.CURDIR}/../../common/Makefile.inc" +CFLAGS+= -I${.CURDIR}/../../common +CFLAGS+= -I. + +CLEANFILES= vers.c loader loader.bin loader.help + +CFLAGS+= -Wall +LDFLAGS= -static -Ttext 0x0 + +# i386 standalone support library +LIBI386= ${.OBJDIR}/../libi386/libi386.a ${.OBJDIR}/../pxe_http/libpxe_http.a +CFLAGS+= -I${.CURDIR}/.. + +# BTX components +CFLAGS+= -I${.CURDIR}/../btx/lib + +# pxe_http includes +CFLAGS+= -I${.CURDIR}/../pxe_http + +# Debug me! +#CFLAGS+= -g +#LDFLAGS+= -g + +# Pick up ../Makefile.inc early. +.include + +vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version + sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} + +loader: loader.bin ${BTXLDR} ${BTXKERN} + btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ + -b ${BTXKERN} loader.bin + +loader.bin: loader.sym + cp ${.ALLSRC} ${.TARGET} + strip -R .comment -R .note ${.TARGET} + +loader.help: help.common help.i386 + cat ${.ALLSRC} | awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} + +.PATH: ${.CURDIR}/../../forth +FILES= loader loader.help loader.4th support.4th loader.conf +FILES+= screen.4th frames.4th beastie.4th +# XXX INSTALLFLAGS_loader= -b +FILESMODE_loader= ${BINMODE} -b +FILESDIR_loader.conf= /boot/defaults + +.if !exists(${DESTDIR}/boot/loader.rc) +FILES+= loader.rc +.endif + +# XXX crt0.o needs to be first for pxeboot(8) to work +OBJS= ${BTXCRT} + +DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBI386} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBI386} -lstand + +.include + +.if ${MACHINE_ARCH} == "amd64" +beforedepend ${OBJS}: machine +CLEANFILES+= machine +machine: + ln -sf ${.CURDIR}/../../../i386/include machine +.endif Index: user/sbruno/pxe_http/loader_mod/conf.c =================================================================== --- user/sbruno/pxe_http/loader_mod/conf.c (nonexistent) +++ user/sbruno/pxe_http/loader_mod/conf.c (revision 245442) @@ -0,0 +1,171 @@ +/*- + * Copyright (c) 1998 Michael Smith + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#include +__FBSDID("$FreeBSD: src/sys/boot/i386/loader/conf.c,v 1.26 2007/05/29 14:35:57 simokawa Exp $"); + +#include +#include +#include "libi386/libi386.h" +#include "pxe_http/httpfs.h" + +/* + * We could use linker sets for some or all of these, but + * then we would have to control what ended up linked into + * the bootstrap. So it's easier to conditionalise things + * here. + * + * XXX rename these arrays to be consistent and less namespace-hostile + * + * XXX as libi386 and biosboot merge, some of these can become linker sets. + */ + +#ifdef LOADER_HTTP_SUPPORT +#undef LOADER_NFS_SUPPORT +#undef LOADER_TFTP_SUPPORT +#endif + +#if defined(LOADER_NFS_SUPPORT) && defined(LOADER_TFTP_SUPPORT) +#error "Cannot have both tftp and nfs support yet." +#endif + +#if defined(LOADER_FIREWIRE_SUPPORT) +extern struct devsw fwohci; +#endif + +/* Exported for libstand */ +struct devsw *devsw[] = { + &bioscd, + &biosdisk, +#if defined(LOADER_NFS_SUPPORT) || defined(LOADER_TFTP_SUPPORT) || \ + defined(LOADER_HTTP_SUPPORT) + &pxedisk, +#endif +#if defined(LOADER_FIREWIRE_SUPPORT) + &fwohci, +#endif + NULL +}; + +#ifdef LOADER_HTTP_SUPPORT +/* free as much as possible memory, by removing unused by PXE filesystems */ +#undef LOADER_EXT2_SUPPORT +#undef LOADER_DOS_SUPPORT +#undef LOADER_CD9660_SUPPORT +#undef LOADER_SPLITFS_SUPPORT +#undef LOADER_NFS_SUPPORT +#undef LOADER_TFTP_SUPPORT +#else +#define LOADER_NFS_SUPPORT +#endif + +struct fs_ops *file_system[] = { + &ufs_fsops, +#ifdef LOADER_EXT2_SUPPORT + &ext2fs_fsops, +#endif +#ifdef LOADER_DOS_SUPPORT + &dosfs_fsops, +#endif +#ifdef LOADER_CD9660_SUPPORT + &cd9660_fsops, +#endif +#ifdef LOADER_SPLITFS_SUPPORT + &splitfs_fsops, +#endif +#ifdef LOADER_GZIP_SUPPORT + &gzipfs_fsops, +#endif +#ifdef LOADER_BZIP2_SUPPORT + &bzipfs_fsops, +#endif +#ifdef LOADER_NFS_SUPPORT + &nfs_fsops, +#endif +#ifdef LOADER_TFTP_SUPPORT + &tftp_fsops, +#endif +#ifdef LOADER_HTTP_SUPPORT + &http_fsops, +#endif + NULL +}; + +/* Exported for i386 only */ +/* + * Sort formats so that those that can detect based on arguments + * rather than reading the file go first. + */ +extern struct file_format i386_elf; +extern struct file_format i386_elf_obj; +#ifdef LOADER_AMD64_ELF_SUPPORT +extern struct file_format amd64_elf; +extern struct file_format amd64_elf_obj; +#endif + +struct file_format *file_formats[] = { + &i386_elf, + &i386_elf_obj, +#ifdef LOADER_AMD64_ELF_SUPPORT + &amd64_elf, + &amd64_elf_obj, +#endif + NULL +}; + +/* + * Consoles + * + * We don't prototype these in libi386.h because they require + * data structures from bootstrap.h as well. + */ +extern struct console vidconsole; +extern struct console comconsole; +#if defined(LOADER_FIREWIRE_SUPPORT) +extern struct console dconsole; +#endif +extern struct console nullconsole; + +struct console *consoles[] = { + &vidconsole, + &comconsole, +#if defined(LOADER_FIREWIRE_SUPPORT) + &dconsole, +#endif + &nullconsole, + NULL +}; + +extern struct pnphandler isapnphandler; +extern struct pnphandler biospnphandler; +extern struct pnphandler biospcihandler; + +struct pnphandler *pnphandlers[] = { + &biospnphandler, /* should go first, as it may set isapnp_readport */ + &isapnphandler, + &biospcihandler, + NULL +}; Index: user/sbruno/pxe_http/loader_mod/help.i386 =================================================================== --- user/sbruno/pxe_http/loader_mod/help.i386 (nonexistent) +++ user/sbruno/pxe_http/loader_mod/help.i386 (revision 245442) @@ -0,0 +1,63 @@ +################################################################################ +# TACPI DControl ACPI module behaviour + + $acpi_load + + If set, the ACPI module will be loaded. Clear it with + + unset acpi_load + + $hint.acpi.0.disabled="1" + + If set, the ACPI module won't be loaded. + + Note that the ACPI autodetection sets a number of hints to + pass information to the ACPI module. These should not be + overridden, or system behaviour will be undefined. + + +################################################################################ +# Treboot DReboot the system + + reboot + + Causes the system to immediately reboot. + +################################################################################ +# Theap DDisplay memory management statistics + + heap + + Requests debugging output from the heap manager. For debugging use + only. + +################################################################################ +# Tset Snum_ide_disks DSet the number of IDE disks + + NOTE: this variable is deprecated, use root_disk_unit instead. + + set num_ide_disks= + + When booting from a SCSI disk on a system with one or more IDE disks, + and where the IDE disks are the default boot device, it is necessary + to tell the kernel how many IDE disks there are in order to have it + correctly locate the SCSI disk you are booting from. + +################################################################################ +# Tset Sroot_disk_unit DForce the root disk unit number. + + set root_disk_unit= + + If the code which detects the disk unit number for the root disk is + confused, eg. by a mix of SCSI and IDE disks, or IDE disks with + gaps in the sequence (eg. no primary slave), the unit number can be + forced by setting this variable. + +################################################################################ +# Tsmap DDisplay BIOS SMAP table + + smap + + Displays the BIOS SMAP (system memory map) table. + +################################################################################ Index: user/sbruno/pxe_http/loader_mod/loader.rc =================================================================== --- user/sbruno/pxe_http/loader_mod/loader.rc (nonexistent) +++ user/sbruno/pxe_http/loader_mod/loader.rc (revision 245442) @@ -0,0 +1,21 @@ +\ Loader.rc +\ $FreeBSD: src/sys/boot/i386/loader/loader.rc,v 1.4.4.1 2005/10/30 14:40:39 scottl Exp $ +\ +\ 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 + +echo "loading RAM-drive image" +load -t mfs_root /boot/mfsroot +set vfs.root.mountfrom="ufs:/dev/md0c" + +\ Start the boot menu +beastie-start Index: user/sbruno/pxe_http/loader_mod/main.c =================================================================== --- user/sbruno/pxe_http/loader_mod/main.c (nonexistent) +++ user/sbruno/pxe_http/loader_mod/main.c (revision 245442) @@ -0,0 +1,629 @@ +/*- + * Copyright (c) 1998 Michael Smith + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#include +__FBSDID("$FreeBSD: src/sys/boot/i386/loader/main.c,v 1.40 2007/05/29 14:35:57 simokawa Exp $"); + +/* + * MD bootstrap main() and assorted miscellaneous + * commands. + */ + +#include +#include +#include +#include + +#include "bootstrap.h" +#include "libi386/libi386.h" +#include "btxv86.h" +#ifdef PXE_MORE +#include "pxe_arp.h" +#include "pxe_connection.h" +#include "pxe_dns.h" +#include "pxe_filter.h" +#include "pxe_http.h" +#include "pxe_httpls.h" +#include "pxe_icmp.h" +#include "pxe_ip.h" +#include "pxe_sock.h" +#include "pxe_tcp.h" +#include "pxe_udp.h" +#endif + + +#define KARGS_FLAGS_CD 0x1 +#define KARGS_FLAGS_PXE 0x2 + +/* Arguments passed in from the boot1/boot2 loader */ +static struct +{ + u_int32_t howto; + u_int32_t bootdev; + u_int32_t bootflags; + u_int32_t pxeinfo; + u_int32_t res2; + u_int32_t bootinfo; +} *kargs; + +static u_int32_t initial_howto; +static u_int32_t initial_bootdev; +static struct bootinfo *initial_bootinfo; + +struct arch_switch archsw; /* MI/MD interface boundary */ + +static void extract_currdev(void); +static int isa_inb(int port); +static void isa_outb(int port, int value); +void exit(int code); + +/* from vers.c */ +extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; + +/* XXX debugging */ +extern char end[]; + +static void *heap_top; +static void *heap_bottom; + +int +main(void) +{ + int i; + + /* Pick up arguments */ + kargs = (void *)__args; + initial_howto = kargs->howto; + initial_bootdev = kargs->bootdev; + initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; + + /* + * Initialise the heap as early as possible. Once this is done, malloc() is usable. + */ + bios_getmem(); + +#if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) + heap_top = PTOV(memtop_copyin); + memtop_copyin -= 0x300000; + heap_bottom = PTOV(memtop_copyin); +#else + heap_top = (void *)bios_basemem; + heap_bottom = (void *)end; +#endif + +#if defined(LOADER_HTTP_SUPPORT) || defined (LOADER_TFTP_SUPPORT) || \ + defined(LOADER_NFS_SUPPORT) + /* 0x8d000-0x9f800 memory area is used by UNDI/BC data/code segments + * and PXE stack + */ + /* TODO: check, if conflict with LOADER_BZIP2_SUPPORT exists */ + heap_top = 0x8d000; + heap_bottom = (void *)end; +#endif + + setheap(heap_bottom, heap_top); + + /* + * XXX Chicken-and-egg problem; we want to have console output early, but some + * console attributes may depend on reading from eg. the boot device, which we + * can't do yet. + * + * We can use printf() etc. once this is done. + * If the previous boot stage has requested a serial console, prefer that. + */ + bi_setboothowto(initial_howto); + if (initial_howto & RB_MULTIPLE) { + if (initial_howto & RB_SERIAL) + setenv("console", "comconsole vidconsole", 1); + else + setenv("console", "vidconsole comconsole", 1); + } else if (initial_howto & RB_SERIAL) + setenv("console", "comconsole", 1); + else if (initial_howto & RB_MUTE) + setenv("console", "nullconsole", 1); + cons_probe(); + + /* + * Initialise the block cache + */ + bcache_init(32, 512); /* 16k cache XXX tune this */ + + /* + * Special handling for PXE and CD booting. + */ + if (kargs->bootinfo == 0) { + /* + * We only want the PXE disk to try to init itself in the below + * walk through devsw if we actually booted off of PXE. + */ + if (kargs->bootflags & KARGS_FLAGS_PXE) + pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); + else if (kargs->bootflags & KARGS_FLAGS_CD) + bc_add(initial_bootdev); + } + + /* + * March through the device switch probing for things. + */ + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); + printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); + if (initial_bootinfo != NULL) { + initial_bootinfo->bi_basemem = bios_basemem / 1024; + initial_bootinfo->bi_extmem = bios_extmem / 1024; + } + + /* detect ACPI for future reference */ + biosacpi_detect(); + + /* detect SMBIOS for future reference */ + smbios_detect(); + + printf("\n"); + printf("%s, Revision %s\n", bootprog_name, bootprog_rev); + printf("(%s, %s)\n", bootprog_maker, bootprog_date); + + extract_currdev(); /* set $currdev and $loaddev */ + setenv("LINES", "24", 1); /* optional */ + + bios_getsmap(); + + archsw.arch_autoload = i386_autoload; + archsw.arch_getdev = i386_getdev; + archsw.arch_copyin = i386_copyin; + archsw.arch_copyout = i386_copyout; + archsw.arch_readin = i386_readin; + archsw.arch_isainb = isa_inb; + archsw.arch_isaoutb = isa_outb; + + interact(); /* doesn't return */ + + /* if we ever get here, it is an error */ + return (1); +} + +/* + * Set the 'current device' by (if possible) recovering the boot device as + * supplied by the initial bootstrap. + * + * XXX should be extended for netbooting. + */ +static void +extract_currdev(void) +{ + struct i386_devdesc new_currdev; + int biosdev = -1; + + /* Assume we are booting from a BIOS disk by default */ + new_currdev.d_dev = &biosdisk; + + /* new-style boot loaders such as pxeldr and cdldr */ + if (kargs->bootinfo == 0) { + if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { + /* we are booting from a CD with cdboot */ + new_currdev.d_dev = &bioscd; + new_currdev.d_unit = bc_bios2unit(initial_bootdev); + } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { + /* we are booting from pxeldr */ + new_currdev.d_dev = &pxedisk; + new_currdev.d_unit = 0; + } else { + /* we don't know what our boot device is */ + new_currdev.d_kind.biosdisk.slice = -1; + new_currdev.d_kind.biosdisk.partition = 0; + biosdev = -1; + } + } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { + /* The passed-in boot device is bad */ + new_currdev.d_kind.biosdisk.slice = -1; + new_currdev.d_kind.biosdisk.partition = 0; + biosdev = -1; + } else { + new_currdev.d_kind.biosdisk.slice = (B_ADAPTOR(initial_bootdev) << 4) + + B_CONTROLLER(initial_bootdev) - 1; + new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); + biosdev = initial_bootinfo->bi_bios_dev; + + /* + * If we are booted by an old bootstrap, we have to guess at the BIOS + * unit number. We will lose if there is more than one disk type + * and we are not booting from the lowest-numbered disk type + * (ie. SCSI when IDE also exists). + */ + if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ + biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ + } + new_currdev.d_type = new_currdev.d_dev->dv_type; + + /* + * If we are booting off of a BIOS disk and we didn't succeed in determining + * which one we booted off of, just use disk0: as a reasonable default. + */ + if ((new_currdev.d_type == biosdisk.dv_type) && + ((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) { + printf("Can't work out which disk we are booting from.\n" + "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); + new_currdev.d_unit = 0; + } + env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), + i386_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, + env_nounset); +} + +COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); + +static int +command_reboot(int argc, char *argv[]) +{ + int i; + + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); + + printf("Rebooting...\n"); + delay(1000000); + __exit(0); +} + +/* provide this for panic, as it's not in the startup code */ +void +exit(int code) +{ + __exit(code); +} + +COMMAND_SET(heap, "heap", "show heap usage", command_heap); + +static int +command_heap(int argc, char *argv[]) +{ + mallocstats(); + printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, + sbrk(0), heap_top); + return(CMD_OK); +} + +/* added for pxe_http */ +#ifdef PXE_MORE +static int +command_route(int argc, char *argv[]) +{ + PXE_IPADDR net; + PXE_IPADDR gw; + + if (argc < 2) { + printf("use: route add|del|print [default|net_addr gw_addr] \n"); + return (CMD_OK); + } + + if (!strcmp(argv[1], "print")) { + pxe_ip_route_stat(); + return (CMD_OK); + } + + if (argc < 4) { + printf("use: route add|del default|net_addr gw_addr\n"); + return (CMD_OK); + } + + if ( (strcmp(argv[1], "add") != 0) && (strcmp(argv[1], "del") != 0)) + return (CMD_OK); + + if (!strcmp(argv[2], "default")) { + + if (!strcmp(argv[1], "del")) { + printf("Cannot delete default gateway.\n"); + return (CMD_OK); + } + + gw.ip = pxe_convert_ipstr(argv[3]); + + pxe_ip_route_default(&gw); + + return (CMD_OK); + } + + gw.ip = pxe_convert_ipstr(argv[3]); + net.ip = pxe_convert_ipstr(argv[2]); + + if (!strcmp(argv[1], "add")) { + pxe_ip_route_add(&net, pxe_ip_get_netmask(&net), &gw); + return (CMD_OK); + } + + pxe_ip_route_del(&net, pxe_ip_get_netmask(&net), &gw); + + return (CMD_OK); +} + +static int +command_arp(int argc, char *argv[]) +{ + PXE_IPADDR *ip; + + if (argc > 1) { + + if (strcmp(argv[1], "stats") != 0) + ip = pxe_gethostbyname(argv[1]); + else { + pxe_arp_stats(); + return (CMD_OK); + } + } else { + printf("use: arp ip4_address|stats\n"); + return (CMD_OK); + } + + printf("searching ip: %s\n", (ip != NULL) ? inet_ntoa(ip->ip) : "?"); + + const uint8_t* mac = (const uint8_t *)pxe_arp_ip4mac(ip); + + if (mac != NULL) + printf("MAC: %6D\n", mac, ":"); + else + printf("MAC search failed.\n"); + + return (CMD_OK); +} + +static int +command_ping(int argc, char *argv[]) +{ + PXE_IPADDR* ip = NULL; + + pxe_icmp_init(); + + if (argc > 1) + ip = pxe_gethostbyname(argv[1]); + else { + printf("use: ping ip4_address\n"); + return (CMD_OK); + } + + pxe_ping(ip, 5, 1); + + return (CMD_OK); +} + +static int +command_await() +{ + + while (1) { + if (!pxe_core_recv_packets()) { + twiddle(); + delay(10000); + } + } + + return (0); +} + +static int +command_sock(int argc, char *argv[]) +{ + + if (argc < 2) { + printf("use: socket stats\n"); + return (CMD_OK); + } + + if (!strcmp(argv[1], "stats")) { + pxe_sock_stats(); + return (CMD_OK); + } + + return (CMD_OK); +} + +static int +command_resolve(int argc, char *argv[]) +{ + + if (argc < 2) { + printf("use: resolve dns_name\n"); + return (CMD_OK); + } + + PXE_IPADDR *ip; + + char* name = argv[1]; + + ip = pxe_gethostbyname(name); + + if ( (ip == NULL) || (ip->ip == 0)) + printf("failed to resolve domain %s\n", name); + else + printf("%s resolved as %s\n", name, inet_ntoa(ip->ip)); + + return (CMD_OK); +} + +static int +command_ns(int argc, char *argv[]) +{ + PXE_IPADDR *ip; + + if (argc == 1) { + ip = pxe_get_ip(PXE_IP_NAMESERVER); + + printf("primary nameserver: %s\n", inet_ntoa(ip->ip)); + + return (CMD_OK); + } + + PXE_IPADDR addr; + + addr.ip = pxe_convert_ipstr(argv[1]); + + if (addr.ip != 0) + pxe_set_ip(PXE_IP_NAMESERVER, &addr); + else + printf("Syntax error in ip address.\n"); + + return (CMD_OK); +} + +static int +command_fetch(int argc, char *argv[]) +{ + + if (argc == 1) { + printf("usage: fetch server/path/to/file.ext\n"); + return (CMD_OK); + } + + char *server_name = argv[1]; + char *filename = server_name; + + while (*filename) { + if (*filename == '/') { + *filename = '\0'; + ++filename; + break; + } + ++filename; + } + + /* retrieve all file */ + pxe_fetch(server_name, filename, 0LL, 0L); + + return (CMD_OK); +} + +static int +command_ls(int argc, char *argv[]) +{ + + if (argc == 1) { + printf("usage: ls /path/to/dir\n"); + return (CMD_OK); + } + + int fd = open(argv[1], O_RDONLY); + + if (fd == -1) + return (CMD_OK); + + http_parse_index(fd); + + close(fd); + + return (CMD_OK); +} + +COMMAND_SET(pxe, "pxe", "pxe test module", command_pxe); + +static int +command_pxe(int argc, char *argv[]) +{ + + if (argc<2) { + printf("PXE test module (built at %s %s)\n", __DATE__, __TIME__); + printf(" use: pxe arp|await|connections|fetch|filters|\n" + "\tping|resolve|route|socket\n"); + return (CMD_OK); + } + + if (!strcmp(argv[1], "arp")) + return command_arp(argc - 1, &argv[1]); + + if (!strcmp(argv[1], "ping")) + return command_ping(argc - 1, &argv[1]); + + if (!strcmp(argv[1], "route")) + return command_route(argc - 1, &argv[1]); + + if (!strcmp(argv[1], "filters")) { + pxe_filter_stats(); + return (CMD_OK); + } + + if (!strcmp(argv[1], "socket")) + return command_sock(argc - 1, &argv[1]); + + if (!strcmp(argv[1], "resolve")) + return command_resolve(argc - 1, &argv[1]); + + if (!strcmp(argv[1], "ns")) + return command_ns(argc - 1, &argv[1]); + + if (!strcmp(argv[1], "await")) + return command_await(); + + if (!strcmp(argv[1], "connections")) { + pxe_connection_stats(); + return (CMD_OK); + } + + if (!strcmp(argv[1], "fetch")) { + return command_fetch(argc - 1, &argv[1]); + } + + if (!strcmp(argv[1], "ls")) { + return command_ls(argc - 1, &argv[1]); + } + + printf("unknown pxe command '%s'\n", argv[1]); + + return (CMD_OK); +} +/* pxe_http add end */ +#endif + +/* ISA bus access functions for PnP, derived from */ +static int +isa_inb(int port) +{ + u_char data; + + if (__builtin_constant_p(port) && + (((port) & 0xffff) < 0x100) && + ((port) < 0x10000)) { + __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); + } else { + __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); + } + return(data); +} + +static void +isa_outb(int port, int value) +{ + u_char al = value; + + if (__builtin_constant_p(port) && + (((port) & 0xffff) < 0x100) && + ((port) < 0x10000)) { + __asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port))); + } else { + __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); + } +} + Index: user/sbruno/pxe_http/loader_mod/version =================================================================== --- user/sbruno/pxe_http/loader_mod/version (nonexistent) +++ user/sbruno/pxe_http/loader_mod/version (revision 245442) @@ -0,0 +1,14 @@ +$FreeBSD: src/sys/boot/i386/loader/version,v 1.8 2001/12/11 00:49:33 jhb Exp $ + +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +1.1: New calling conventions for fopen. +1.0: New semantics for finding the kernel, new boot. +0.8: Set/getenv & cia, copyin/out. +0.7: Supports large KVM +0.6: Increased dictionary size -- supports loader.4th +0.5: First release version +0.2: Initial integration with BTX +0.1: Initial i386 version, inspiration and some structure from the + NetBSD version. Index: user/sbruno/pxe_http/ptelnet/README =================================================================== --- user/sbruno/pxe_http/ptelnet/README (nonexistent) +++ user/sbruno/pxe_http/ptelnet/README (revision 245442) @@ -0,0 +1,2 @@ +simple telnet client modules. +based on code from D.E. Comer, D.L. Stevens, "Internetworking with TCP/IP", vol. III \ No newline at end of file Index: user/sbruno/pxe_http/ptelnet/options.c =================================================================== --- user/sbruno/pxe_http/ptelnet/options.c (nonexistent) +++ user/sbruno/pxe_http/ptelnet/options.c (revision 245442) @@ -0,0 +1,245 @@ +#include +#include +#include + +#include "pxe_telnet.h" +#include "telnet_fsm.h" + +extern uint8_t doecho; /* nonzero, if remote ECHO */ +extern uint8_t rcvbinary; /* non-zero if remote TRANSMIT-BINARY */ +extern int substate; +extern uint8_t sndbinary; /* non-zero if TRANSMIT-BINARY */ +extern uint8_t termtype; /* non-zero if received "DO TERMTYPE" */ +extern uint8_t noga; + +int +is_already(uint8_t val, uint8_t opt_cmd) +{ + + if (val) { + if (opt_cmd == TCWILL) + return (1); /* already doing needed option */ + } else if (opt_cmd == TCWONT) + return (1); /* already NOT doing needed option */ + + return (0); +} + +void +do_answer(uint8_t val, uint8_t c, int socket) +{ + + putc(TCIAC, socket); + putc(val ? TCDO : TCDONT, socket); + putc(c, socket); +} + +/* do_echo() - processes ECHO option + * in: + * socket - socket to place data to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +do_echo(int socket, int c) +{ + + if (is_already(doecho, fsm_get_option_cmd())) + return (0); + + doecho = !doecho; + do_answer(doecho, (uint8_t)c, socket); + + return (0); +} + +/* do_noga() - process "no go-ahead" option + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +do_noga(int socket, int c) +{ + + if (is_already(noga, fsm_get_option_cmd())) + return (0); + + noga = !noga; + do_answer(noga, (uint8_t)c, socket); + + return (0); +} + +/* do_notsup() - process not supported will/won't option + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +do_notsup(int socket, int c) +{ + + do_answer(0, (uint8_t)c, socket); + return (0); +} + + +/* do_txbinary() - process transmit binary option + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +do_txbinary(int socket, int c) +{ + + if (is_already(rcvbinary, fsm_get_option_cmd())) + return (0); + + rcvbinary = !rcvbinary; + do_answer(rcvbinary, (uint8_t)c, socket); + + return (0); +} + +/* recopt() - process option type + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +recopt(int socket, int c) +{ + + fsm_set_option_cmd((uint8_t)c); + + return (0); +} + +/* no_op() - don't do anything + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +no_op(int socket, int c) +{ + + return (0); +} + + +/* subend() - end of option subnegotiation + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +subend(int socket, int c) +{ + + return fsm_setstate(FSM_SUBS, SS_START); +} + +/* subopt() - do option subnegotiation FSM state change + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +subopt(int socket, int c) +{ + + return fsm_process(FSM_SUBS, socket, c); +} + + +/* subtermtype() - terminal type subnegotiation + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +subtermtype(int socket, int c) +{ + + putc(TCIAC, socket); + putc(TCSB, socket); + putc(TOTERMTYPE, socket); + putc(TT_IS, socket); + fputs("pxe_term", socket); + putc(TCIAC, socket); + putc(TCSE, socket); + + return (0); +} + +/* will_notsup() - process not supported do/don't option + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +will_notsup(int socket, int c) +{ + + putc(TCIAC, socket); + putc(TCWONT, socket); + putc((uint8_t)c, socket); + + return (0); +} + +/* will_txbinary() - process transmit binary option + * in: + * socket - socket to place response to + * c - provided command + * out: + * 0 - ok + * -1 - problems + */ +int +will_txbinary(int socket, int c) +{ + + if (is_already(sndbinary, fsm_get_option_cmd())) + return (0); + + sndbinary = !sndbinary; + + putc(TCIAC, socket); + putc(sndbinary ? TCWILL : TCWONT, socket); + putc((char)c, socket); + + return (0); +} Index: user/sbruno/pxe_http/ptelnet/pxe_telnet.c =================================================================== --- user/sbruno/pxe_http/ptelnet/pxe_telnet.c (nonexistent) +++ user/sbruno/pxe_http/ptelnet/pxe_telnet.c (revision 245442) @@ -0,0 +1,116 @@ +#include +#include + +#include "pxe_telnet.h" +#include "telnet_fsm.h" +#include "telnet_opts.h" + +/* telnet_write() - writes sequence of bytes to connected socket + * in: + * socket - socket number + * buf - buffer to write data from + * bufsize - size of buffer + * out: + * 0 - all is ok + * -1 - all is bad + * >0 - count of written bytes + */ +int +telnet_write(int socket, uint8_t *buf, size_t bufsize) +{ + return (0); +} + +/* console_write() - writes sequence of bytes to console, extracting commands + * in: + * buf - buffer to output data from + * bufsize - size of buffer + * out: + * 0 - all is ok + * -1 - all is bad + * >0 - count of written bytes + */ +int +console_write(uint8_t *buf, size_t bufsize) +{ + return (0); +} + +/* console_read() - reads sequence of bytes from console + * in: + * socket - socket number + * buf - buffer to read data to + * bufsize - size of buffer + * out: + * 0 - all is ok, read ended + * -1 - all is bad + * >0 - count of read bytes + */ +int +console_read(uint8_t *buf, size_t bufsize) +{ + return (0); +} + +/* pxe_telnet() - connects via telnet protocol to host and interacts with user + * in: + * addr - ip address of remote host + * port - remote port to connect to + * out: + * -1 - something failed + * 0 - all was ok + */ +int +pxe_telnet(PXE_IPADDR *addr, uint16_t port) +{ + uint8_t buf[PXE_TELNET_BUFSIZE]; + int byte_count = 0; + int on = 1; + int s = pxe_socket(); + + if (s == -1) /* failed to create socket */ + return (-1); + + int result = pxe_connect(s, addr, port); + + if (result == -1) { /* failed to connect */ + pxe_close(s); + return (-1); + } + + fsmbuild(); /* set up finite state machines */ + + while (1) { + /* remote server input, TODO: nonblocking socket read */ + byte_count = pxe_recv(s, buf, sizeof(buf), PXE_SOCK_NONBLOCKING); + + if (byte_count < 0) { + printf("\nerror: socket read failed\n"); + break; + } else if ((byte_count == 0) && (pxe_sock_state(s) != PXE_SOCKET_CONNECTED)) { + printf("\nconnection closed.\n"); + return (0); + } else { /* local console output */ + console_write(buf, byte_count); + } + + /* local console input */ + byte_count = console_read(buf, sizeof(buf)); + + if (byte_count < 0) { + printf("\nerror: tty read failed\n"); + break; + } else if (byte_count == 0) { + pxe_close(s); + return (0) + } else { + /* output to remote server */ + telnet_write(s, buf, byte_count); + } + } + + /* any error occured */ + pxe_close(s); + + return (-1); +} Index: user/sbruno/pxe_http/ptelnet/pxe_telnet.h =================================================================== --- user/sbruno/pxe_http/ptelnet/pxe_telnet.h (nonexistent) +++ user/sbruno/pxe_http/ptelnet/pxe_telnet.h (revision 245442) @@ -0,0 +1,56 @@ +#ifndef PXE_TELNET_INCLUDED +#define PXE_TELNET_INCLUDED + +#include +#include "../pxe_ip.h" + +/* TELNET Command Codes: */ +#define TCSB (uint8_t)250 /* Start Subnegotiation */ +#define TCSE (uint8_t)240 /* End Of Subnegotiation */ +#define TCNOP (uint8_t)241 /* No Operation */ +#define TCDM (uint8_t)242 /* Data Mark (for Sync) */ +#define TCBRK (uint8_t)243 /* NVT Character BRK */ +#define TCIP (uint8_t)244 /* Interrupt Process */ +#define TCAO (uint8_t)245 /* Abort Output */ +#define TCAYT (uint8_t)246 /* "Are You There?" Function */ +#define TCEC (uint8_t)247 /* Erase Character */ +#define TCEL (uint8_t)248 /* Erase Line */ +#define TCGA (uint8_t)249 /* "Go Ahead" Function */ +#define TCWILL (uint8_t)251 /* Desire/Confirm Will Do Option*/ +#define TCWONT (uint8_t)252 /* Refusal To Do Option */ +#define TCDO (uint8_t)253 /* Request To Do Option */ +#define TCDONT (uint8_t)254 /* Request NOT To Do Option */ +#define TCIAC (uint8_t)255 /* Interpret As Command Escape */ + +/* Telnet Option Codes: */ +#define TOTXBINARY (uint8_t) 0 /* TRANSMIT-BINARY option */ +#define TOECHO (uint8_t) 1 /* ECHO Option */ +#define TONOGA (uint8_t) 3 /* Suppress Go-Ahead Option */ +#define TOTERMTYPE (uint8_t) 24 /* Terminal-Type Option */ + +/* Network Virtual Printer Special Characters: */ +#define VPLF '\n' /* Line Feed */ +#define VPCR '\r' /* Carriage Return */ +#define VPBEL '\a' /* Bell (attention signal) */ +#define VPBS '\b' /* Back Space */ +#define VPHT '\t' /* Horizontal Tab */ +#define VPVT '\v' /* Vertical Tab */ +#define VPFF '\f' /* Form Feed */ + +/* Keyboard Command Characters: */ +#define KCESCAPE 035 /* Local escape character ('^]') */ +#define KCDCON '.' /* Disconnect escape command */ +#define KCNL '\n' /* Newline character */ + +#define KCANY (NCHRS + 1) + +/* Option Subnegotiation Constants: */ +#define TT_IS 0 /* TERMINAL_TYPE option "IS" command */ +#define TT_SEND 1 /* TERMINAL_TYPE option "SEND" command */ + +/* establishes telnet connection to server and interacts with user */ +int pxe_telnet(PXE_IPADDR *addr, uint16_t port); + +#define PXE_TELNET_BUFSIZE 1024 /* buffer size */ + +#endif /* PXE_TELNET_INCLUDED */ \ No newline at end of file Index: user/sbruno/pxe_http/ptelnet/telnet_fsm.c =================================================================== --- user/sbruno/pxe_http/ptelnet/telnet_fsm.c (nonexistent) +++ user/sbruno/pxe_http/ptelnet/telnet_fsm.c (revision 245442) @@ -0,0 +1,255 @@ +#include "pxe_telnet.h" +#include "telnet_fsm.h" +#include "telnet_opts.h" + +uint8_t option_cmd = 0; + +int substate = 0; +uint8_t subfsm[NSSTATES][NCHRS]; + +int ttstate = 0; +uint8_t ttfsm[NTSTATES][NCHRS]; + +int sostate = 0; +uint8_t sofsm[NKSTATES][NCHRS]; + +#define TINVALID 0xff /* an invalid transition index */ + +struct fsm_trans ttstab[] = { + /* State Input Next State Action */ + /* ------ ------ ----------- ------- */ + { TSDATA, TCIAC, TSIAC, no_op }, + { TSDATA, TCANY, TSDATA, ttputc }, + { TSIAC, TCIAC, TSDATA, ttputc }, + { TSIAC, TCSB, TSSUBNEG, no_op }, +/* Telnet Commands */ + { TSIAC, TCNOP, TSDATA, no_op }, +// { TSIAC, TCDM, TSDATA, tcdm }, +/* Option Negotiation */ + { TSIAC, TCWILL, TSWOPT, recopt }, + { TSIAC, TCWONT, TSWOPT, recopt }, + { TSIAC, TCDO, TSDOPT, recopt }, + { TSIAC, TCDONT, TSDOPT, recopt }, + { TSIAC, TCANY, TSDATA, no_op }, +/* Option Subnegotion */ + { TSSUBNEG, TCIAC, TSSUBIAC, no_op }, + { TSSUBNEG, TCANY, TSSUBNEG, subopt }, + { TSSUBIAC, TCSE, TSDATA, subend }, + { TSSUBIAC, TCANY, TSSUBNEG, subopt }, + + { TSWOPT, TOECHO, TSDATA, do_echo }, + { TSWOPT, TONOGA, TSDATA, do_noga }, + { TSWOPT, TOTXBINARY, TSDATA, do_txbinary }, + { TSWOPT, TCANY, TSDATA, do_notsup }, + + { TSDOPT, TOTXBINARY, TSDATA, will_txbinary }, + { TSDOPT, TCANY, TSDATA, will_notsup }, + + { FSINVALID, TCANY, FSINVALID, abort }, +}; + +struct fsm_trans sostab[] = { + /* State Input Next State Action */ + /* ------ ------ ----------- ------- */ + /* Data Input */ + { KSREMOTE, KCESCAPE, KSLOCAL, no_op }, + { KSREMOTE, KCANY, KSREMOTE, soputc }, + + /* Local Escape Commands */ + { KSLOCAL, KCESCAPE, KSREMOTE, soputc }, + { KSLOCAL, KCDCON, KSREMOTE, disconnect }, + { KSLOCAL, KCANY, KSREMOTE, sonotsup }, + + { FSINVALID, KCANY, FSINVALID, abort }, +}; + +struct fsm_trans substab[] = { + /* State Input Next State Action */ + /* ------ ------ ----------- ------- */ + { SS_START, TOTERMTYPE, SS_TERMTYPE, no_op }, + { SS_START, TCANY, SS_END, no_op }, +/* { SS_TERMTYPE, TT_SEND, SS_END, subtermtype }, + { SS_TERMTYPE, TCANY, SS_END, no_op }, */ + { SS_END, TCANY, SS_END, no_op }, + + { FSINVALID, TCANY, FSINVALID, abort }, +}; + + +/* fsmbuild() build the Finite State Machine data structures + * in/out: + * none + * NOTE: may be better to use prebuilt structure, or not use matrix to + * reduce memory usage (~1kb). + */ +int +fsmbuild() +{ + + fsminit(ttfsm, ttstab, NTSTATES); + ttstate = TSDATA; + + fsminit(sofsm, sostab, NKSTATES); + sostate = KSREMOTE; + + fsminit(subfsm, substab, NSSTATES); + substate = SS_START; +} + + + +/* fsminit() - inits Finite State Machine, actually performs build of matrix + * structure. + * in: + * fsm - storage for neded matrix + * ttab - FSM description structures + * nsatates - number of states + * out: + * 0 - all is ok + * -1 - failed + */ +int +fsminit(uint8_t fsm[][NCHRS], struct fsm_trans ttab[], int nstates) +{ + struct fsm_trans *pt; + int sn, ti, cn; + + for (cn = 0; cn < NCHRS; ++cn) + for (ti = 0; ti < nstates; ++ti) + fsm[ti][cn] = TINVALID; + + for (ti = 0; ttab[ti].ft_state != FSINVALID; ++ti) { + pt = &ttab[ti]; + sn = pt->ft_state; + + if (pt->ft_char == TCANY) { + for (cn = 0; cn < NCHRS; ++cn) + if (fsm[sn][cn] == TINVALID) + fsm[sn][cn] = ti; + } else + fsm[sn][pt->ft_char] = ti; + } + + /* set all uninitialized indices to an invalid transition */ + for (cn = 0; cn < NCHRS; ++cn) + for (ti = 0; ti < nstates; ++ti) + if (fsm[ti][cn] == TINVALID) + fsm[ti][cn] = ti; + + return (0); +} + +/* fsm_setstate() - sets state of FSM, choosen by index + * in: + * table_index - index of FSM (one of FSM_... constants) + * state - state to set current state to + * out: + * 0 - all is ok + * -1 - failed + */ +int +fsm_setstate(int table_index, int state) +{ + int *state = NULL; + + switch(table_index) { + case FSM_TERMINAL: + state = &ttstate; + break; + + case FSM_SOCKET: + state = &sostate; + break; + + case FSM_SUBS: + state = &substate; + break; + + default: + return (-1); + } + + *state = state; + + return (0); +} + +/* fsm_process() - process FSM state change if any + * in: + * table_index - index of FSM (one of FSM_... constants) + * c - incoming char to process + * socket - socket to write to + * out: + * 0 - all is ok + * -1 - failed + */ +int +fsm_process(int table_index, int socket, int c) +{ + uint8_t *fsm = NULL; + int *state = NULL; + struct fsm_trans *table = NULL; + int ti = 0; + struct fsm_trans *pt = NULL; + int result = -1; + + switch(table_index) { + case FSM_TERMINAL: + fsm = ttfsm; + state = &ttstate; + table = ttstab; + break; + + case FSM_SOCKET: + fsm = sofsm; + state = &sostate; + table = sostab; + break; + + case FSM_SUBS: + fsm = subfsm; + state = &substate; + table = substab; + break; + + default: + return (-1); + } + + ti = fsm[ (*state) * NCHRS + c]; + *pt = &table[ti]; + + result =(pt->ft_action)(socket, c); + + if (result >= 0) + *state = pt->ft_next; + + return (result); +} + +/* fsm_get_option_cmd() - return option_cmd + * in: + * none + * out: + * option_cmd (WILL/WONT & etc) + */ +uint8_t +fsm_get_option_cmd() +{ + + return (option_cmd); +} + +/* fsm_set_option_cmd() - set option_cmd to provided value + * in: + * opt - value to set option_cmd to + * out: + * none + */ + +void +fsm_set_option_cmd(uint8_t opt) +{ + + option_cmd = opt; +} Index: user/sbruno/pxe_http/ptelnet/telnet_fsm.h =================================================================== --- user/sbruno/pxe_http/ptelnet/telnet_fsm.h (nonexistent) +++ user/sbruno/pxe_http/ptelnet/telnet_fsm.h (revision 245442) @@ -0,0 +1,46 @@ +#ifndef __TELNET__FSM__ +#define __TELNET__FSM__ + +#include + +/* Telnet Socket-Input FSM States: */ +#define TSDATA 0 /* normal data processing */ +#define TSIAC 1 /* have seen IAC */ +#define TSWOPT 2 /* have seen IAC-{WILL/WONT} */ +#define TSDOPT 3 /* have seen IAC-{DO/DONT} */ +#define TSSUBNEG 4 /* have seen IAC-SB */ +#define TSSUBIAC 5 /* have seen IAC-SB-...-IAC */ + +#define NTSTATES 6 /* # of TS* states */ + +/* Telnet Keyboard-Input FSM States: */ +#define KSREMOTE 0 /* input goes to the socket */ +#define KSLOCAL 1 /* input goes to a local func. */ +#define KSCOLLECT 2 /* input is scripting-file name */ + +#define NKSTATES 2 /* # of KS* states */ + +/* Telnet Option Subnegotiation FSM States: */ +#define SS_START 0 /* initial state */ +#define SS_TERMTYPE 1 /* TERMINAL_TYPE option subnegotiation */ +#define SS_END 2 /* state after all legal input */ + +#define NSSTATES 3 /* # of SS_* states */ + +#define FSINVALID 0xff /* an invalid state number */ + +#define NCHRS 256 /* number of valid characters */ +#define TCANY (NCHRS+1) /* match any character */ + +#define FSM_TERMINAL 0 +#define FSM_SOCKET 1 +#define FSM_SUBS 2 + +struct fsm_trans { + uint8_t ft_state; /* current state */ + int16_t ft_char; /* input character */ + uint8_t ft_next; /* next state */ + int (*ft_action)(); /* action to take */ +}; + +#endif \ No newline at end of file Index: user/sbruno/pxe_http/pxe_arp.c =================================================================== --- user/sbruno/pxe_http/pxe_arp.c (nonexistent) +++ user/sbruno/pxe_http/pxe_arp.c (revision 245442) @@ -0,0 +1,387 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_arp.h" +#include "pxe_await.h" +#include "pxe_core.h" +#include "pxe_mem.h" + +/* last entry used for PXE client ip/mac */ +static PXE_ARP_ENTRY arp_table[MAX_ARP_ENTRIES + 1]; +static PXE_ARP_PACK_DATA packet_to_send; +static int arp_usage = 0; + +/* + * pxe_arp_init() - initialisation of used by this module structures + * in: + * none + * out: + * none + */ +void +pxe_arp_init() +{ +#ifdef PXE_ARP_DEBUG + printf("pxe_arp_init() started.\n"); + + if (packet_to_send.hdr.hsize != 0) { + printf("pxe_arp_init() already initialized.\n"); + return; + } +#endif + pxe_memset(&packet_to_send, 0, sizeof(PXE_ARP_PACK_DATA) ); + + pxe_memset(arp_table, 0, sizeof(arp_table)); + + /* filling packet_to_send, it will not change ever */ + packet_to_send.hdr.hwtype =htons(ETHER_TYPE); + packet_to_send.hdr.ptype = htons(PXE_PTYPE_IP); + packet_to_send.hdr.hsize = 6; /* Ethernet MAC size */ + packet_to_send.hdr.psize = 4; /* ip4 size */ + packet_to_send.hdr.operation = htons(PXE_ARPOP_REQUEST); + + /* filling source related data: client ip & MAC */ + pxe_memcpy(pxe_get_mymac(), packet_to_send.body.src_hwaddr, 6); + + const PXE_IPADDR *addr = pxe_get_ip(PXE_IP_MY);; + packet_to_send.body.src_paddr = addr->ip; + + /* filling entry for own ip/mac*/ + pxe_memcpy(pxe_get_mymac(), arp_table[MAX_ARP_ENTRIES].mac, 6); + arp_table[MAX_ARP_ENTRIES].addr.ip = addr->ip; + + /* setting broadcast target address */ + pxe_memset(packet_to_send.body.target_hwaddr, 0xff, 6); +} + +/* + * pxe_arp_table_search() - searches entry in ARP table for given ip + * in: + * ip - ip, for which to search MAC + * out: + * NULL - not found such entry in arp_table + * not NULL - pointer to MAC address + */ +const MAC_ADDR * +pxe_arp_table_search(uint32_t ip) +{ +#ifdef PXE_ARP_DEBUG_HELL + printf("pxe_arp_table_search(): started\n"); +#endif + int entry = 0; + + for (; entry < MAX_ARP_ENTRIES + 1; ++entry) { + + if (arp_table[entry].addr.ip == ip) { + + uint8_t *mac = &arp_table[entry].mac[0]; +#ifdef PXE_ARP_DEBUG_HELL + printf("pxe_arp_table_search(): %6D\n", mac, ":"); +#endif + return (const MAC_ADDR *)mac; + } + } + + return (NULL); +} + +#ifdef PXE_MORE +/* pxe_arp_stats() - show arp current table state + * in/out: + * none + */ +void +pxe_arp_stats() +{ + int entry = 0; + int limit = (arp_usage > MAX_ARP_ENTRIES) ? MAX_ARP_ENTRIES : arp_usage; + + printf("ARP updates: %d\n", arp_usage); + + for (; entry < limit; ++entry) { + + if ( (arp_table[entry].addr.ip == 0) || + (arp_table[entry].mac == NULL) ) + continue; + + printf("%s\t%6D\n", + inet_ntoa(arp_table[entry].addr.ip), + arp_table[entry].mac, ":"); + } + +} +#endif /* PXE_MORE */ + +/* + * pxe_arp_protocol() - process received arp packet, this function is called in + * style of pxe_protocol_call function type, but last + * parameter is unused + * in: + * pack - rceived packet data + * function - protocal function (will be always PXE_CORE_FRAG) + * out: + * always 0 - we are not interested in storing this packet in pxe_core queue + */ +int +pxe_arp_protocol(PXE_PACKET *pack, uint8_t function) +{ +#ifdef PXE_ARP_DEBUG_HELL + printf("pxe_arp_protocol() started.\n"); +#endif + PXE_ARP_PACK_DATA *arp_reply = (PXE_ARP_PACK_DATA *)pack->raw_data; + + if (arp_reply->hdr.operation == htons(PXE_ARPOP_REQUEST) ) { + + uint8_t *mac_src = arp_reply->body.src_hwaddr; + uint8_t *mac_dst = arp_reply->body.target_hwaddr; + PXE_IPADDR ip4_src; + PXE_IPADDR ip4_dst; + + const PXE_IPADDR *addr = pxe_get_ip(PXE_IP_MY); + + ip4_src.ip = arp_reply->body.src_paddr; + ip4_dst.ip = arp_reply->body.target_paddr; + + if (ip4_src.ip == addr->ip) { + /* got broadcast send by us */ +#ifdef PXE_ARP_DEBUG_HELL + printf("arp request from myself ignored.\n"); +#endif + return (0); + } + +#ifdef PXE_ARP_DEBUG + printf("arp request from %6D/%s\n\t", + mac_src, ":", inet_ntoa(ip4_src.ip)); + + printf("to: %6D/%s\n", + mac_dst, ":", inet_ntoa(ip4_dst.ip)); +#endif + + /* somebody is looking for us */ + if (ip4_dst.ip == arp_table[MAX_ARP_ENTRIES].addr.ip) { + + pxe_memcpy(arp_reply->body.src_hwaddr, + packet_to_send.body.target_hwaddr, 6); + + packet_to_send.body.target_paddr = + arp_reply->body.src_paddr; + + packet_to_send.hdr.operation = htons(PXE_ARPOP_REPLY); + + PXE_PACKET pack; + + pack.raw_size = sizeof(PXE_ARP_PACK_DATA); + pack.raw_data = &packet_to_send; + pack.data = &packet_to_send.hdr; + pack.data_size = + sizeof(PXE_ARP_PACK_DATA) - MEDIAHDR_LEN_ETH; + + pack.protocol = PXE_PROTOCOL_ARP; + pack.dest_mac = (const MAC_ADDR *) + &packet_to_send.body.target_hwaddr[0]; + + pack.flags = PXE_SINGLE; + + if (!pxe_core_transmit(&pack)) { + printf("pxe_arp_protocol(): reply to arp request failed.\n"); + } + + /* cleaning packet_to_send back to initiakl state */ + pxe_memset(packet_to_send.body.target_hwaddr, 0xff, 6); + packet_to_send.hdr.operation = htons(PXE_ARPOP_REQUEST); + } + + /* we may cache information about packet sender */ +#ifdef PXE_ARP_SNIFF + /* just to skip operation filter below */ + arp_reply->hdr.operation = htons(PXE_ARPOP_REPLY); +#else + return (0); +#endif + } + + /* we don't need anything except replies on that stage */ + if (arp_reply->hdr.operation != htons(PXE_ARPOP_REPLY) ) + return (0); + + /* if arp_usage exceeds MAX_ARP_ENTRIES, occurs rewriting of earlier + * placed ARP entries. MAC may be lost, so protocol must check this + * case when creating packet (cause there used pointer to MAC + * in arp_table). May be better way is to panic if arp_table is full. + * In fact, we don't need many entries. Only two: one for gateway, + * one for DNS-server or for proxy server. Default arp_table size is 8. + * It seems more than enough. + */ + + const MAC_ADDR *kmac = pxe_arp_table_search(arp_reply->body.src_paddr); + if (NULL != kmac) { +#ifdef PXE_ARP_DEBUG + uint8_t *octet = (uint8_t *)&arp_reply->body.src_paddr; + printf("MAC of %d.%d.%d.%d already known: %x:%x:%x:%x:%x:%x\n", + octet[0], octet[1], octet[2], octet[3], + (*kmac)[0], (*kmac)[1], (*kmac)[2], + (*kmac)[3], (*kmac)[4], (*kmac)[5] + ); +#endif + /* NOTE: theoretically it's possible mac != known mac. Ignore. */ + return (0); + } + + pxe_memcpy(&arp_reply->body.src_hwaddr, + &arp_table[arp_usage % MAX_ARP_ENTRIES].mac, 6); + + arp_table[arp_usage % MAX_ARP_ENTRIES].addr.ip = + arp_reply->body.src_paddr; + + ++arp_usage; + +#ifdef PXE_ARP_DEBUG_HELL + printf("pxe_arp_protocol(): arp usage = %d\n", arp_usage); +#endif + + return (0); /* inform pxe_get_packet() we don't need this packet more. */ +} + +/* + * pxe_arp_send_whois() - sends ARP request packet for given ip, received + * packets are handled in pxe_arp_protocol() + * in: + * ip - target ip, for which to find MAC + * out: + * 0 - failed + * 1 - success + */ +int +pxe_arp_send_whois(uint32_t ip) +{ + PXE_PACKET pack; + + pack.raw_size = sizeof(PXE_ARP_PACK_DATA); + pack.raw_data = &packet_to_send; + pack.data = &packet_to_send.hdr; + pack.data_size = sizeof(PXE_ARP_PACK_DATA) - MEDIAHDR_LEN_ETH; + + pack.protocol = PXE_PROTOCOL_ARP; + pack.dest_mac = (const MAC_ADDR *)&packet_to_send.body.target_hwaddr[0]; + pack.flags = PXE_BCAST; + + packet_to_send.body.target_paddr = ip; + + if (!pxe_core_transmit(&pack)) { + printf("pxe_arp_send_whois(): failed to send request.\n"); + return (0); + } + + return (1); +} + +/* pxe_arp_await() - await function for ARP replies + * in: + * function - await function + * try_number - number of try + * timeout - timeout from start of try + * data - pointer to PXE_ARP_WAIT_DATA + * out: + * PXE_AWAIT_ constants + */ +int +pxe_arp_await(uint8_t function, uint16_t try_number, uint32_t timeout, + void *data) +{ + PXE_ARP_WAIT_DATA *wait_data = (PXE_ARP_WAIT_DATA *)data; + const MAC_ADDR *res = NULL; + switch (function) { + + case PXE_AWAIT_STARTTRY: /* handle start of new try */ + if (!pxe_arp_send_whois(wait_data->addr.ip)) { + /* failed to send request, try once more + * after waiting a little + */ + delay(10000); + return (PXE_AWAIT_NEXTTRY); + } + break; + + case PXE_AWAIT_NEWPACKETS: + /* check if ARP protocol was called and + * arp_table updated + */ + res = pxe_arp_table_search(wait_data->addr.ip); + if (res != NULL) { + wait_data->mac = res; + return (PXE_AWAIT_COMPLETED); + } + + return (PXE_AWAIT_CONTINUE); + break; + + case PXE_AWAIT_FINISHTRY: + if (wait_data->mac == NULL) /* nothing got during try */ + printf("\npxe_arp_await(): ARP reply timeout.\n"); + break; + + case PXE_AWAIT_END: /* wait ended */ + default: + break; + } + + return (PXE_AWAIT_OK); +} + +/* + * pxe_arp_ip4mac() - returns MAC for given ip if it's found in arp_table, + * otherwise - performs request sending + * in: + * ip - ip, for which to search MAC + * out: + * NULL - not found such entry in arp_table + * not NULL - pointer to MAC address + */ +const MAC_ADDR * +pxe_arp_ip4mac(const PXE_IPADDR *addr) +{ + const MAC_ADDR *res = pxe_arp_table_search(addr->ip); + + if (res != NULL) + return (res); +#ifdef PXE_EXCLUSIVE + pxe_core_exclusive(PXE_PROTOCOL_ARP); +#endif + PXE_ARP_WAIT_DATA wait_data; + + wait_data.addr.ip = addr->ip; + wait_data.mac = NULL; + + pxe_await(pxe_arp_await, PXE_MAX_ARP_TRY, PXE_TIME_TO_DIE, &wait_data); +#ifdef PXE_EXCLUSIVE + pxe_core_exclusive(0); +#endif + return (wait_data.mac); +} Index: user/sbruno/pxe_http/pxe_arp.h =================================================================== --- user/sbruno/pxe_http/pxe_arp.h (nonexistent) +++ user/sbruno/pxe_http/pxe_arp.h (revision 245442) @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_ARP_H +#define PXE_ARP_H + +/* + * Handles ARP requests and ARP table + * Reference: RFC826 + */ + +#include +#include +#include + +#include "../libi386/pxe.h" +#include "pxe_core.h" +#include "pxe_ip.h" + +/* max MAC<->ip4 bindings to store */ +#define MAX_ARP_ENTRIES 4 +/* max try count to send/recieve ARP request/reply */ +#define PXE_MAX_ARP_TRY 3 +/* max timeout in millyseconds */ +#define PXE_TIME_TO_DIE 5000 + +/* define to enable caching incoming ARP packet sender information */ +#define PXE_ARP_SNIFF + +typedef struct pxe_arp_entry { + PXE_IPADDR addr; + MAC_ADDR mac; +} PXE_ARP_ENTRY; + + +/* initialisation routine */ +void pxe_arp_init(); + +/* find MAC by provided ip */ +const MAC_ADDR *pxe_arp_ip4mac(const PXE_IPADDR *addr); + +/* protocol handler for received packets */ +int pxe_arp_protocol(PXE_PACKET *pack, uint8_t function); + +/* ARP table statistics */ +void pxe_arp_stats(); + +/* ARP packet types */ +#define PXE_ARPOP_REQUEST 1 +#define PXE_ARPOP_REPLY 2 + +/* protocol types */ +#define PXE_PTYPE_IP 0x0800 /* IP4 protocol, used in ARP request */ + +/* NOTE: here will be realised ARP for Ethernet and IP4 */ +typedef struct pxe_arp_packet { + uint16_t hwtype; /* hardware type */ + uint16_t ptype; /* protocol type */ + uint8_t hsize; /* size of hardware address */ + uint8_t psize; /* size of protocol adress */ + uint16_t operation; +} __packed PXE_ARP_PACKET; + +typedef struct pxe_arp_packet_eth4 { + uint8_t src_hwaddr[6]; /* source hardware address */ + uint32_t src_paddr; /* source protocol address */ + uint8_t target_hwaddr[6]; /* target hardware address if known */ + uint32_t target_paddr; /* target protocol address if known */ +} __packed PXE_ARP_PACKET_ETH4; + +typedef struct pxe_arp_pack_data { + uint8_t media_hdr[MEDIAHDR_LEN_ETH]; + PXE_ARP_PACKET hdr; + PXE_ARP_PACKET_ETH4 body; +} __packed PXE_ARP_PACK_DATA; + +typedef struct pxe_arp_wait_data { + PXE_IPADDR addr; + const MAC_ADDR *mac; +} PXE_ARP_WAIT_DATA; + +#endif Index: user/sbruno/pxe_http/pxe_await.c =================================================================== --- user/sbruno/pxe_http/pxe_await.c (nonexistent) +++ user/sbruno/pxe_http/pxe_await.c (revision 245442) @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_await.h" +#include "pxe_core.h" + +/* pxe_await() - awaits for packets + * in: + * await_func - callback function + * trys - how much trys to make + * timeout - timeout of waiting in ms + * data - additional data to give to callback function + * out: + * 0 - failed + * 1 - success + */ +int +pxe_await(pxe_await_func await_func, uint16_t trys, uint32_t timeout, void *data) +{ + int result = 0; + uint32_t time_elapsed = 0; + uint16_t try_counter = 0; + + while (try_counter < trys) { + + /* notify about start of try */ + result = await_func(PXE_AWAIT_STARTTRY, try_counter, 0, data); + + switch (result) { + case PXE_AWAIT_NEXTTRY: + ++try_counter; + time_elapsed = 0; /* skip this try */ + continue; + + case PXE_AWAIT_BREAK: /* return failure */ + return (0); + break; + + default: /* other codes are good for us */ + break; + } + + while (time_elapsed < timeout) { +#ifdef PXE_DEBUG + twiddle(); +#endif + if (pxe_core_recv_packets()) { + /* means some packet was received */ + + result = await_func(PXE_AWAIT_NEWPACKETS, + try_counter, time_elapsed, data); + + if (result == PXE_AWAIT_COMPLETED) { + await_func(PXE_AWAIT_FINISHTRY, + try_counter, time_elapsed, data); + + return (1); + } + + if (result == PXE_AWAIT_NEXTTRY) + break; + + /* aborted waiting */ + if (result == PXE_AWAIT_BREAK) + break; + + /* continue */ + } + + delay(TIME_DELTA); + time_elapsed += TIME_DELTA_MS; + } + + /* notify about end of try */ + result = await_func(PXE_AWAIT_FINISHTRY, try_counter, + time_elapsed, data); + + if (result == PXE_AWAIT_BREAK) /* failure */ + return (0); + + ++try_counter; + time_elapsed = 0; + } + + /* notify about end of await, result is not interesting */ + await_func(PXE_AWAIT_END, try_counter, time_elapsed, data); + + /* if waiting of packet successful, + * control returned higher (PXE_AWAIT_COMPLETED) + */ + return (0); +} Index: user/sbruno/pxe_http/pxe_await.h =================================================================== --- user/sbruno/pxe_http/pxe_await.h (nonexistent) +++ user/sbruno/pxe_http/pxe_await.h (revision 245442) @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_AWAIT_H_INCLUDED +#define PXE_AWAIT_H_INCLUDED + +/* + * Implements await functions wrapper + */ + +#include + +/* await callback function type */ +typedef int (*pxe_await_func)(uint8_t function, uint16_t try_counter, + uint32_t timeout, void *data); + +#define PXE_AWAIT_NEWPACKETS 0x00 /* some packets received, check it */ +#define PXE_AWAIT_STARTTRY 0x01 /* start of new try */ +#define PXE_AWAIT_FINISHTRY 0x02 /* end of current try */ +#define PXE_AWAIT_END 0x03 /* ending of waiting */ + +/* values that may be returned by await function */ +#define PXE_AWAIT_OK 0x00 /* ok, do what you want */ +#define PXE_AWAIT_COMPLETED 0x01 /* wait ended succefully */ +#define PXE_AWAIT_CONTINUE 0x02 /* continue waiting */ +#define PXE_AWAIT_NEXTTRY 0x03 /* continue with next try */ +#define PXE_AWAIT_BREAK 0x04 /* wait ended with failure */ + +#define TIME_DELTA_MS 1 +#define TIME_DELTA 1000 + +/* universal waiting function */ +int pxe_await(pxe_await_func func, uint16_t try_counter, + uint32_t timeout, void *data); + +#endif Index: user/sbruno/pxe_http/pxe_buffer.c =================================================================== --- user/sbruno/pxe_http/pxe_buffer.c (nonexistent) +++ user/sbruno/pxe_http/pxe_buffer.c (revision 245442) @@ -0,0 +1,427 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_buffer.h" +#include "pxe_mem.h" + +#ifdef PXE_POOL_SLOTS +/* statically allocated space, used for buffer allocating */ +static uint8_t send_pool[PXE_DEFAULT_SEND_BUFSIZE * PXE_POOL_SLOTS]; +static uint8_t recv_pool[PXE_DEFAULT_RECV_BUFSIZE * PXE_POOL_SLOTS]; +/* pool slot usage 0 - unused, 1 - used */ +static uint8_t send_pool_slots[PXE_POOL_SLOTS]; +static uint8_t recv_pool_slots[PXE_POOL_SLOTS]; + +/* pxe_buffer_init() - initializes slots for statically allocated buffers + * in/ out: + * none + */ +void +pxe_buffer_init() +{ + + int slot = 0; + + for ( ; slot < PXE_POOL_SLOTS; ++slot) { + send_pool_slots[slot] = 0; + recv_pool_slots[slot] = 0; + } +} +#endif + +/* pxe_buffer_write() - write data to buffer, if possible + * in: + * buf - pointer to buffer structure + * from - pointer to data to write + * size - size of data buffer + * out: + * actual count of written bytes + */ +uint16_t +pxe_buffer_write(PXE_BUFFER *buf, const void *from, uint16_t size) +{ + + if (buf == NULL) { + printf("pxe_buffer_write(): NULL buffer\n"); + return (0); + } + + uint16_t to_write = (size < buf->bufleft) ? size : buf->bufleft; + + if (buf->data == NULL) { + printf("pxe_buffer_write(): NULL buffer data\n"); + return (0); + } + +#ifdef PXE_DEBUG_HELL + printf("pxe_buffer_write(): fstart %d, fend %d, bufleft %d (of %d)," + " to_write %d (%d)\n", buf->fstart, buf->fend, buf->bufleft, + buf->bufsize, to_write, size); +#endif + + if (to_write == 0) /* no space left*/ + return (0); + + /* check if possible to place without cycling */ + if (buf->fstart < buf->fend) { /* possible to place without cycling */ + + pxe_memcpy(from, buf->data + buf->fstart, to_write); + buf->fstart += to_write; + + } else {/* may be need to place, using two memcpy operations */ + + /* right part of buffer */ + uint16_t part1 = buf->bufsize - buf->fstart; + /* left part of buffer */ + uint16_t part2 = to_write - part1; + + if (part1) + pxe_memcpy(from, buf->data + buf->fstart, + (part1 < to_write) ? part1 : to_write); + + if (part1 >= to_write) { + buf->fstart += to_write; + } else { + pxe_memcpy(from + part1, buf->data, part2); + buf->fstart = part2; + } + } + + buf->bufleft -= to_write; + +#ifdef PXE_DEBUG + printf("pxe_buffer_write(): bufleft %d (-%d)\n", buf->bufleft, to_write); +#endif + return (to_write); +} + +/* pxe_buffer_read() - reades data from buffer, if possible + * in: + * buf - pointer to buffer structure + * to - pointer to data to read to, + * if NULL - data is read but not placed anywhere + * size - size of data buffer + * out: + * actual count of read bytes + */ +uint16_t +pxe_buffer_read(PXE_BUFFER *buf, void *to, uint16_t size) +{ + + if (buf == NULL) { + printf("pxe_buffer_read(): NULL buffer\n"); + return (0); + } + + if (buf->data == NULL) { + printf("pxe_buffer_read(): NULL buffer data\n"); + return (0); + } + + uint16_t usage = buf->bufsize - buf->bufleft; + uint16_t to_read = (size <= usage) ? size : usage; + + if (to_read == 0) /* nothing to read */ + return (0); + + uint16_t fstart = buf->fstart; + uint16_t fend = buf->fend; + uint16_t bufsize = buf->bufsize; + + if (fstart <= fend) { /* two cases handling: |*s...e**|, |***se***| */ + + /* right part of buffer */ + uint16_t part1 = bufsize - fend; + /* left part of buffer */ + uint16_t part2 = to_read - part1; + + if (part1 && (to != NULL) ) + pxe_memcpy(buf->data + fend, to, + (part1 < to_read) ? part1 : to_read); + + if (part1 >= to_read) + buf->fend += to_read; + else { + if (to != NULL) + pxe_memcpy(buf->data, to + part1, part2); + + buf->fend = part2; + } + + } else { /* third case: |..e**s...| */ + + if (to != NULL) + pxe_memcpy(buf->data + buf->fend, to, to_read); + + buf->fend += to_read; + } + + buf->bufleft += to_read; + +#ifdef PXE_DEBUG_HELL + printf("pxe_buffer_read(): bufleft %d (+%d), fstart %d, fend %d\n", + buf->bufleft, to_read, buf->fstart, buf->fend + ); +#endif + return (to_read); +} + +/* pxe_buffer_space() - returns free space in buffer + * in: + * buffer - pointer to buffer structure + * out: + * count in bytes of free space in buffer + */ +uint16_t +pxe_buffer_space(PXE_BUFFER *buffer) +{ + + if (buffer == NULL) { +#ifdef PXE_DEBUG + printf("pxe_buffer_space(): NULL buffer\n"); +#endif + return (0); + } + + return (buffer->bufleft); +} + +#ifdef PXE_POOL_SLOTS +int +alloc_free_slot(uint8_t *slots, int slot_count) +{ + int slot = 0; + + for ( ; slot < slot_count; ++slot) + if (slots[slot] == 0) { + slots[slot] = 1; + return (slot); + } + + return (-1); +} + +/* pxe_buffer_memalloc() - allocates memory for buffer + * in: + * buffer - pointer to buffer structure + * size - bytes to allocate + * out: + * 0 - failed + * 1 - success + */ +int +pxe_buffer_memalloc(PXE_BUFFER *buffer, uint16_t size) +{ + + if (buffer == NULL) { +#ifdef PXE_DEBUG + printf("pxe_buffer_memalloc(): NULL buffer\n"); +#endif + return (0); + } + + if (buffer->data != NULL) { + /* buffer has same size */ + if (buffer->bufsize == size) + return (1); + + /* theoretically we never must get here, cause of + * current method of allocating buffers for sockets. + */ + printf("pxe_buffer_memalloc(): Unhandled alloc case.\n"); + return (0); + } + + int slot = -1; + uint8_t *data = NULL; + + switch (size) { + case PXE_DEFAULT_RECV_BUFSIZE: + slot = alloc_free_slot(recv_pool_slots, PXE_POOL_SLOTS); + data = recv_pool + slot * size; + break; + + case PXE_DEFAULT_SEND_BUFSIZE: + slot = alloc_free_slot(send_pool_slots, PXE_POOL_SLOTS); + data = send_pool + slot * size; + break; + + default: + printf("pxe_buffer_memalloc(): unsupported size (%u bytes).\n", + size); + break; + } + + if (slot == -1) /* failed to find free slot */ + return (0); + + buffer->bufsize = size; + buffer->bufleft = size; + buffer->fstart = 0; + buffer->fend = size; + buffer->data = data; + +#ifdef PXE_DEBUG_HELL + printf("pxe_buffer_memalloc(): buffer 0x%x, data 0x%x, bufleft %u.\n", + buffer, buffer->data, buffer->bufleft + ); +#endif + return (1); +} + +/* pxe_buffer_memfree() - release memory used by buffer + * in: + * buffer - pointer to buffer structure + * out: + * none + */ +void +pxe_buffer_memfree(PXE_BUFFER *buffer) +{ + + if (buffer == NULL) { +#ifdef PXE_DEBUG + printf("pxe_buffer_memfree(): NULL buffer\n"); +#endif + return; + } + + if (buffer->data == NULL) { /* already released */ + printf("pxe_buffer_memfree(): already released.\n"); + return; + } + +#ifdef PXE_DEBUG_HELL + printf("pxe_buffer_memfree(): buffer 0x%x, data 0x%x, bufleft: %d.\n", + buffer, buffer->data, buffer->bufleft + ); +#endif + int slot = -1; + uint8_t *slots = NULL; + + switch (buffer->bufsize) { + case PXE_DEFAULT_RECV_BUFSIZE: + slot = (buffer->data - (void *)recv_pool) / + PXE_DEFAULT_RECV_BUFSIZE; + + slots = recv_pool_slots; + break; + + case PXE_DEFAULT_SEND_BUFSIZE: + slot = (buffer->data - (void *)send_pool) / + PXE_DEFAULT_SEND_BUFSIZE; + + slots = send_pool_slots; + break; + default: + printf("pxe_buffer_memfree(): unsupported size (%u bytes).\n", + buffer->bufsize); + break; + } + + if (slots && (slot > -1) && (slot < PXE_POOL_SLOTS)) { + slots[slot] = 0; + } + + buffer->data = NULL; +} +#endif /* #ifdef PXE_POOL_SLOTS */ + +/* pxe_buffer_memalloc() - allocates memory for buffer + * in: + * buffer - pointer to buffer structure + * size - bytes to allocate + * out: + * 0 - failed + * 1 - success + */ +int +pxe_buffer_memalloc(PXE_BUFFER *buffer, uint16_t size) +{ + + if (buffer == NULL) { +#ifdef PXE_DEBUG + printf("pxe_buffer_memalloc(): NULL buffer\n"); +#endif + return (0); + } + + if (buffer->data == NULL) { /* alloc if not already allocated */ + buffer->data = pxe_alloc(size); + + if (buffer->data == NULL) + return (0); + } else { + printf("pxe_buffer_memalloc(): already %u bytes, asked %u.\n", + buffer->bufsize, size); + } + + buffer->bufsize = size; + buffer->bufleft = size; + buffer->fstart = 0; + buffer->fend = size; + +#ifdef PXE_DEBUG_HELL + printf("pxe_buffer_memalloc(): buffer 0x%x, data 0x%x, bufleft %u.\n", + buffer, buffer->data, buffer->bufleft + ); +#endif + return (1); +} + +/* pxe_buffer_memfree() - release memory used by buffer + * in: + * buffer - pointer to buffer structure + * out: + * none + */ +void +pxe_buffer_memfree(PXE_BUFFER *buffer) +{ + + if (buffer == NULL) { +#ifdef PXE_DEBUG + printf("pxe_buffer_memfree(): NULL buffer\n"); +#endif + return; + } + + if (buffer->data == NULL) { /* already released */ + printf("pxe_buffer_memfree(): already released.\n"); + return; + } + +#ifdef PXE_DEBUG_HELL + printf("pxe_buffer_memfree(): buffer 0x%x, data 0x%x, bufleft: %d.\n", + buffer, buffer->data, buffer->bufleft + ); +#endif + pxe_free(buffer->data); + buffer->data = NULL; +} Index: user/sbruno/pxe_http/pxe_buffer.h =================================================================== --- user/sbruno/pxe_http/pxe_buffer.h (nonexistent) +++ user/sbruno/pxe_http/pxe_buffer.h (revision 245442) @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_BUFFER_H_INCLUDED +#define PXE_BUFFER_H_INCLUDED + +/* + * Implements cyclic buffer routines + */ + +#include + +/* slot count in buffer pool, define this for statical buffer allocation */ +/* #define PXE_POOL_SLOTS 2 */ + +/* buffer size choosed by default for sending/recieving */ +#define PXE_DEFAULT_RECV_BUFSIZE 16384 +#define PXE_DEFAULT_SEND_BUFSIZE 4096 + +/* pxe_buffer - buffer related information */ +typedef struct pxe_buffer { + + void *data; /* pointer to memory block, used for buffer */ + + uint16_t fstart; /* start of free space part in buffer */ + uint16_t fend; /* end of free space part in buffer */ + + uint16_t bufsize; /* size of memory block */ + uint16_t bufleft; /* left buffer space */ + +} PXE_BUFFER; + +/* allocates memory for buffer */ +int pxe_buffer_memalloc(PXE_BUFFER *buffer, uint16_t size); + +/* releases buffer memory */ +void pxe_buffer_memfree(PXE_BUFFER *buffer); + +/* writes data to buffer */ +uint16_t pxe_buffer_write(PXE_BUFFER *buffer, const void* data, uint16_t size); + +/* returns free space size in buffer */ +uint16_t pxe_buffer_space(PXE_BUFFER *buffer); + +/* performs initialization of buffer pool */ +#ifdef PXE_POOL_SLOTS +void pxe_buffer_init(); +#endif + +#endif // PXE_BUFFER_H_INCLUDED Index: user/sbruno/pxe_http/pxe_connection.c =================================================================== --- user/sbruno/pxe_http/pxe_connection.c (nonexistent) +++ user/sbruno/pxe_http/pxe_connection.c (revision 245442) @@ -0,0 +1,691 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_await.h" +#include "pxe_connection.h" +#include "pxe_core.h" +#include "pxe_filter.h" +#include "pxe_ip.h" +#include "pxe_segment.h" +#include "pxe_sock.h" +#include "pxe_tcp.h" + +/* connection structs storage */ +static PXE_TCP_CONNECTION tcp_connections[PXE_MAX_TCP_CONNECTIONS]; +/* currently allocated connections */ +static int all_connections = 0; + +/* filter_to_connection() - returns connections, + * associated with provided filter + * in: + * filter - pointer to filter entry structure, + * for which connection is searched + * out: + * NULL - failed to find + * not NULL- searched connections + */ +PXE_TCP_CONNECTION * +filter_to_connection(PXE_FILTER_ENTRY *filter) +{ + int con_index = 0; + + for ( ; con_index < PXE_MAX_TCP_CONNECTIONS; ++con_index) { + + if (tcp_connections[con_index].filter == filter) + return (&tcp_connections[con_index]); + } + + return (NULL); +} + +/* alloc_connection() - returns pointer to free connection structure + * in: + * none + * out: + * NULL - failed to alloc + * non NULL- pointer to allocated structure + */ +PXE_TCP_CONNECTION * +alloc_connection() +{ + + if (all_connections == PXE_MAX_TCP_CONNECTIONS) + return (NULL); + + uint16_t index = 0; + + for ( ; index < PXE_MAX_TCP_CONNECTIONS; ++index) { + + if (tcp_connections[index].state == PXE_TCP_CLOSED) { + /* if state is closed, it's free structure*/ + all_connections += 1; + return &tcp_connections[index]; + } + } + + /* NOTE: we must not ever get here */ + return (NULL); +} + +/* force_alloc_connection() - returns pointer to free connection structure + * forces connection structures in TIME_WAIT state to + * be allocated if there are no free connection + * structure. + * in: + * none + * out: + * NULL - failed to alloc + * non NULL- pointer to allocated structure + */ +PXE_TCP_CONNECTION * +force_alloc_connection() +{ + + if (all_connections < PXE_MAX_TCP_CONNECTIONS) + return alloc_connection(); + + uint16_t index = 0; + + for ( ; index < PXE_MAX_TCP_CONNECTIONS; ++index) { + + if (tcp_connections[index].state == PXE_TCP_TIME_WAIT) { + + tcp_connections[index].state = PXE_TCP_CLOSED; + + /* release filter */ + PXE_FILTER_ENTRY *filter = tcp_connections[index].filter; + + if (filter != NULL) /* it must always be non NULL */ + pxe_filter_remove(filter); +#ifdef PXE_TCP_DEBUG + printf("force_alloc_connection(): forced allocation\n"); +#endif + return &tcp_connections[index]; + } + } + + return (NULL); +} + +/* pxe_force_filter_release() - releases filter if used by connections + * in TIME_WAIT state. Needed when filters table + * is full, but there are no really active connections. + * in/out: + * none + */ +void +pxe_force_filter_release() +{ + uint16_t index = 0; + + for ( ; index < PXE_MAX_TCP_CONNECTIONS; ++index) { + + if (tcp_connections[index].state == PXE_TCP_TIME_WAIT) { + /* free also connection structure */ + tcp_connections[index].state = PXE_TCP_CLOSED; + + /* release filter */ + PXE_FILTER_ENTRY *filter = tcp_connections[index].filter; + + if (filter != NULL) /* it must always be non NULL */ + pxe_filter_remove(filter); + + all_connections -= 1; +#ifdef PXE_TCP_DEBUG + printf("pxe_force_filter_release(): filter released.\n"); +#endif + break; + } + } +} + +/* free_connection() - releases connections + * in: + * connection - pointer to connection to release + * (assuming it's valid connection) + * out: + * none + */ +void +free_connection(PXE_TCP_CONNECTION *connection) +{ + + connection->state = PXE_TCP_CLOSED; + all_connections -= 1; +#ifdef PXE_TCP_DEBUG_HELL + printf("free_connection(): %d connections used\n", all_connections); +#endif +} + +/* tcp_await() - await function for some TCP protocol functions (handshaking, + * breaking connection). + * NOTE: + * main work is done in pxe_tcp_callback() + */ +int +tcp_await(uint8_t function, uint16_t try_number, uint32_t timeout, void *data) +{ + PXE_TCP_WAIT_DATA *wait_data = (PXE_TCP_WAIT_DATA *)data; + PXE_TCP_CONNECTION *conn = wait_data->connection; + + switch(function) { + case PXE_AWAIT_NEWPACKETS: + /* check current state with needed to wait for */ + + if (wait_data->state <= conn->state) + return (PXE_AWAIT_COMPLETED); + + /* CLOSED at waiting means connection was breaked */ + if (conn->state == PXE_TCP_CLOSED) + return (PXE_AWAIT_BREAK); + + break; + + case PXE_AWAIT_FINISHTRY: + if (conn->state == PXE_TCP_CLOSED) + return (PXE_AWAIT_BREAK); + + pxe_resend_check(wait_data->connection); + break; + + case PXE_AWAIT_STARTTRY: /* nothing to do */ + case PXE_AWAIT_END: + default: + break; + } + + return (PXE_AWAIT_OK); +} + +/* pxe_tcp_connect() - connects TCP socket (performs handshaking). + * Blocks until handshaking is done. + * in: + * socket - socket + * out: + * 0 - failed to connect + * 1 - handshaking successful + */ +int +pxe_tcp_connect(PXE_SOCKET *sock) +{ + +/* if (all_connections == PXE_MAX_TCP_CONNECTIONS) { + printf("pxe_tcp_connect(): too many connections.\n"); + return (0); + } +*/ + PXE_FILTER_ENTRY *filter = sock->filter; + PXE_TCP_CONNECTION *connection = force_alloc_connection(); + + if (connection == NULL) { + printf("pxe_tcp_connect(): too many connections.\n"); + return (0); + } + + pxe_memset(connection, 0, sizeof(PXE_TCP_CONNECTION)); + + connection->dst_port = filter->src_port; + connection->src_port = filter->dst_port; + connection->dst.ip = filter->src.ip; + connection->next_recv = 0; + + /* NOTE: need to make more correct initial number */ + connection->iss = (filter->src.ip + filter->dst.ip) + + (uint32_t)pxe_get_secs(); + + connection->next_send = connection->iss; + + connection->filter = filter; + connection->recv = &sock->recv_buffer; + connection->send = &sock->send_buffer; + + pxe_resend_init(connection); + + if (!pxe_tcp_syssend(connection, PXE_TCP_SYN)) { + printf("pxe_tcp_connect(): failed to send SYN.\n"); + free_connection(connection); + return (0); + } + + connection->state = PXE_TCP_SYN_SENT; + connection->next_send = connection->iss + 1; +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_connect(): new state - SYN_SENT\n"); +#endif + PXE_TCP_WAIT_DATA wait_data; + wait_data.connection = connection; + + wait_data.state = PXE_TCP_ESTABLISHED; + + /* await ESTABLISHED state. + * connection will fell in this state in pxe_tcp_callback(), + * after receiving SYN ACK and sending ACK to remote host + */ + if (!pxe_await(tcp_await, 5, PXE_TCP_MSL / 5, &wait_data)) { + /* failed to get SYN/ACK */ + free_connection(connection); + return (0); + } + +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_connect(): connection established.\n"); +#endif + return (1); +} + +/* pxe_tcp_disconnect() - interrupts TCP connection. Blocks until is done. + * in: + * socket - socket + * out: + * 0 - failed to disconnect (timeout) + * 1 - disconnect successful + */ +int +pxe_tcp_disconnect(PXE_SOCKET *sock) +{ +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_disconnect(): started.\n"); +#endif + PXE_FILTER_ENTRY *filter = sock->filter; + + if (filter == NULL) { + /* NULL filters means there are no connection for socket */ + printf("pxe_tcp_disconnect(): NULL filter\n"); + return (1); + } + + PXE_TCP_CONNECTION *connection = filter_to_connection(filter); + + if (connection == NULL) { + printf("pxe_tcp_disconnect(): NULL connection\n"); + return (0); + } + + /* process recieved, queued but not processed packets. + * This is useful if server requested breaking of connection + * (passive closing) and our disconnect just finishes initiated + * by server sequence, no need to send initial FIN (active closing) + */ + pxe_core_recv_packets(); + + if ( connection->state == PXE_TCP_CLOSED) { /* already closed */ +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_disconnect(): connection already is closed.\n"); +#endif + return (1); + } + + if (!pxe_tcp_syssend(connection, PXE_TCP_FIN | PXE_TCP_ACK)) { + printf("pxe_tcp_disconnect(): failed to send FIN.\n"); + free_connection(connection); + return (0); + } + /* update sequence number */ + connection->next_send += 1; + + PXE_TCP_WAIT_DATA wait_data; + wait_data.connection = connection; + + if (connection->state == PXE_TCP_ESTABLISHED) { + /* active closing by our host */ + connection->state = PXE_TCP_FIN_WAIT1; +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_disconnect(): new state - FIN_WAIT_1\n"); +#endif + wait_data.state = PXE_TCP_TIME_WAIT; + + } else { /* if connection breaked by remote host */ + connection->state = PXE_TCP_LAST_ACK; + wait_data.state = PXE_TCP_CLOSED; + } + + connection->state_out = PXE_TCP_FIN; + + /* awaiting expected state to close connection + * connection will fell in this state in pxe_tcp_callback() + */ + if (!pxe_await(tcp_await, 5, PXE_TCP_MSL / 5, &wait_data)) { + /* failed to get expected state */ + free_connection(connection); + + if (connection->state != PXE_TCP_CLOSED) { +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_disconnect(): felt to wrong state.\n"); +#endif + return (0); + } + } + + if (connection->state == PXE_TCP_CLOSED) { + pxe_filter_remove(filter); + free_connection(connection); + } + + pxe_resend_free(connection); + +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_disconnect(): connection closed.\n"); +#endif + return (1); +} + +/* pxe_connection_init() - inits connections related structures + * in/out: + * none + */ +void +pxe_connection_init() +{ + + /* clear connections data */ + pxe_memset(tcp_connections, 0, sizeof(tcp_connections)); +} + +/* pxe_tcp_write() - transmit data via TCP protocol + * in: + * sock - TCP socket to write to + * data - pointer to data to send + * size_to_send - data size + * out: + * -1 - failed + * >=0 - actual bytes written + */ +int +pxe_tcp_write(PXE_SOCKET *sock, void *data, uint16_t size_to_send) +{ + PXE_TCP_CONNECTION *connection = filter_to_connection(sock->filter); + + if (connection == NULL) { + printf("pxe_tcp_write(): no connection for filter 0x%x " + "(socket: 0x%x).\n", sock->filter, sock); + return (-1); + } + + if ( (connection->state != PXE_TCP_ESTABLISHED) && + (connection->state != PXE_TCP_CLOSE_WAIT) ) + { + return (-1); /* cannot write, incorrect state */ + } + + /* trying current segment */ + PXE_TCP_QUEUED_SEGMENT *segment = connection->segment; + + uint16_t sent_data = 0; + uint16_t bufleft = 0; + uint16_t send_now = 0; + void *segment_data = (void *)(segment + 1); + + while (sent_data < size_to_send) { + + /* have no allocated segment for writing data, try allocate it */ + if (segment == NULL) { + /* allocating new segment */ + segment = tcp_segment_alloc(connection, PXE_SEGMENT_BIG); + + if (segment == NULL) { + printf("pxe_tcp_write(): failed to allocate segment.\n"); + return (sent_data == 0) ? (-1) : sent_data; + } + + connection->segment = segment; + segment_data = (void *)(segment + 1); + + tcp_start_segment(connection, segment, + PXE_SEGMENT_OPTS_NO); + } + + /* calculating free space in segment packet */ + bufleft = connection->chunk_size * PXE_TCP_CHUNK_COUNT; + bufleft -= sizeof(PXE_TCP_QUEUED_SEGMENT) + segment->size; + /* how much left to send */ + send_now = size_to_send - sent_data; + + if (send_now < bufleft) { + /* copy data to segment space, actually there is no send, + * till segment is fully filled or called pxe_tcp_push() + */ + pxe_memcpy(data + sent_data, + segment_data + segment->size, send_now); + + segment->size += send_now; + sent_data += send_now; + + return (sent_data); + } + + /* if we got here, then we need to finish current segment + * and alloc new segment + */ + pxe_memcpy(data + sent_data, + segment_data + segment->size, bufleft); + + segment->size += bufleft; + sent_data += bufleft; + + /* finish segment */ + tcp_finish_segment(connection, segment, PXE_TCP_ACK); + /* updating next_send counter */ + connection->next_send += segment->size - sizeof(PXE_TCP_PACKET); + + segment->resend_at = pxe_get_secs() + PXE_RESEND_TIME; + + if (!pxe_tcp_send_segment(connection, segment)) { + printf("pxe_tcp_write(): failed to send segment.\n"); + /* this segment will be resent later, + * so continue normal processing + */ + } + + pxe_core_recv_packets(); + segment = NULL; + connection->segment = NULL; + } + + return (sent_data); +} + +/* pxe_tcp_read() - wrapper to read data from TCP socket + * in: + * sock - TCP socket to read from + * data - buffer to read data + * size_to_read - buffer size + * out: + * -1 - failed + * >=0 - actual bytes read + */ +int +pxe_tcp_read(PXE_SOCKET *sock, void *data, uint16_t size_to_read) +{ + PXE_TCP_CONNECTION *connection = filter_to_connection(sock->filter); + + if (connection == NULL) { + printf("pxe_tcp_read(): no connection for filter 0x%x " + "(socket: 0x%x).\n", sock->filter, sock); + return (-1); + } + + PXE_BUFFER *recv_buffer = connection->recv; + + if ( (connection->state != PXE_TCP_ESTABLISHED) && + (recv_buffer->bufleft == recv_buffer->bufsize) ) + { +#ifdef PXE_DEBUG + printf("pxe_tcp_read(): state %u, no data in buffer\n", + connection->state); +#endif + return (-1); /* connection closed and no data in buffer */ + } + + int result = pxe_buffer_read(recv_buffer, data, size_to_read); + + if (result != 0) { + + /* if receive window was zero and now is big enough, + * notify remote host + */ + if ( (connection->winlock == 1) && + (recv_buffer->bufleft > PXE_DEFAULT_RECV_BUFSIZE / 4)) + { + if (!pxe_tcp_syssend(connection, PXE_TCP_ACK)) + printf("pxe_tcp_read(): failed to notify " + "remote host about window.\n"); + else + connection->winlock = 0; + } + } + + /* process new packets if too low data in buffer */ + if (recv_buffer->bufleft > recv_buffer->bufsize / 2) + pxe_core_recv_packets(); + + return (result); +} + +/* pxe_tcp_push() - flushes send buffer (actually current send segment) + * in: + * filter - filter of socket, which buffers need to flush + * out: + * 0 - failed + * 1 - success + */ +int +pxe_tcp_push(PXE_FILTER_ENTRY *filter) +{ + PXE_TCP_CONNECTION *connection = filter_to_connection(filter); + + if (connection == NULL) { + printf("pxe_tcp_push(): no connection for filter 0x%x.\n", + filter); + + return (0); + } + + if ( (connection->state != PXE_TCP_ESTABLISHED) && + (connection->state != PXE_TCP_CLOSE_WAIT) ) + { + printf("pxe_tcp_push(): connection 0x%x is in wrong state %d.\n", + connection, connection->state); + /* connection not in established state, ignore available data */ + return (0); + } + + PXE_TCP_QUEUED_SEGMENT *segment = connection->segment; + + if (segment == NULL) /* nothing to push */ + return (1); + + /* finish segment */ + tcp_finish_segment(connection, segment, PXE_TCP_ACK | PXE_TCP_PSH); + + segment->resend_at = pxe_get_secs() + PXE_RESEND_TIME; + connection->next_send += segment->size - sizeof(PXE_TCP_PACKET); + + if (!pxe_tcp_send_segment(connection, segment)) { + printf("pxe_tcp_push(): failed to send segment.\n"); + /* this segment will be resent later, + * so continue normal processing + */ + } + + segment = NULL; + connection->segment = NULL; + + return (1); +} + +/* pxe_tcp_check_connection() - checks connections state by sending ACK, + * used e.g. to notify remote host about + * enough window to recv + * in: + * sock - TCP socket to check connection for + * out: + * 0 - failed + * 1 - success + */ +int +pxe_tcp_check_connection(PXE_SOCKET *sock) +{ +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_check_connection(): started.\n"); +#endif + PXE_TCP_CONNECTION *connection = filter_to_connection(sock->filter); + + if (connection == NULL) { + printf("pxe_tcp_check_connection(): no connection for filter " + "0x%x (socket: 0x%x).\n", sock->filter, sock); + return (0); + } + + if (connection->state != PXE_TCP_ESTABLISHED) { + printf("pxe_tcp_check_connection(): connection 0x%x " + "is not in established state(%d).\n", + connection, connection->state); + /* connection not in established state, ignore available data */ + return (0); + } + + PXE_BUFFER *buffer = connection->recv; + + /* send ACK ony if we place enough space */ + if (buffer->bufleft < buffer->bufsize / 3) + return (0); + + if (!pxe_tcp_syssend(connection, PXE_TCP_ACK)) { + printf("pxe_tcp_check_connection(): failed to send ACK.\n"); + return (0); + } + + return (1); +} + +#ifdef PXE_MORE +/* pxe_connection_stats() - shows brief information about connections + * in/out: + * none + */ +void +pxe_connection_stats() +{ + printf("pxe_connection_stats(): %d connections\n", all_connections); + + int con_index = 0; + PXE_TCP_CONNECTION *connection = NULL; + + for ( ; con_index < PXE_MAX_TCP_CONNECTIONS; ++con_index) { + + connection = &tcp_connections[con_index]; + + printf("%d: filter: 0x%x, state: %d\n" + " nxt_snd: %lu, nxt_rcv: %lu, iss: %lu, irs: %lu\n", + con_index, connection->filter, connection->state, + connection->next_send, connection->next_recv, + connection->iss, connection->irs); + } +} +#endif /* PXE_MORE */ Index: user/sbruno/pxe_http/pxe_connection.h =================================================================== --- user/sbruno/pxe_http/pxe_connection.h (nonexistent) +++ user/sbruno/pxe_http/pxe_connection.h (revision 245442) @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_CONNECTION_INCLUDED +#define PXE_CONNECTION_INCLUDED + +/* + * Provides TCP connection related routines + */ + +#include + +#include "pxe_buffer.h" +#include "pxe_filter.h" +#include "pxe_sock.h" + +/* maximum existing connections at one time */ +#define PXE_MAX_TCP_CONNECTIONS 8 + +/* connection states */ +#define PXE_TCP_STATE_MASK 0x0f + +#define PXE_TCP_CLOSED 0x00 /* closed */ + +#define PXE_TCP_SYN_SENT 0x01 /* active */ +#define PXE_TCP_SYN_RECEIVED 0x02 /* sent & received SYN */ +#define PXE_TCP_ESTABLISHED 0x03 /* established connection */ +#define PXE_TCP_CLOSE_WAIT 0x04 /* got FIN, waiting to close */ +#define PXE_TCP_LAST_ACK 0x05 /* got FIN, closing & waiting FIN ACK */ + +#define PXE_TCP_FIN_WAIT1 0x06 /* CLOSE, sent FIN */ +#define PXE_TCP_CLOSING 0x07 /* got FIN, sent ACK, waiting FIN ACK */ +#define PXE_TCP_FIN_WAIT2 0x08 /* got FIN ACK */ +#define PXE_TCP_TIME_WAIT 0x09 /* closed, waiting 2MSL*/ +#define PXE_TCP_ALL_STATES 10 + +#define PXE_TCP_BLOCK_COUNT 8 +#define PXE_TCP_CHUNK_COUNT 8 + +typedef struct pxe_tcp_connecton { + + uint8_t state; /* current TCP conenction state */ + uint8_t state_out; /* show latest acked packet flags + * (e.g. we sent FIN and it was ACKed, + * here will be PXE_TCP_FIN. + */ + uint8_t winlock; /* flag becomes 1 when recieve window is zero*/ + uint32_t next_recv; /* next sequence number to accept */ + uint32_t next_send; /* next sequence number to send */ + uint32_t una; /* unaccepted sequence number */ + + uint32_t iss; /* initial send sequence */ + uint32_t irs; /* initial recv sequence */ + uint16_t remote_window; /* remote host window size */ + + uint16_t src_port; /* source port */ + uint16_t dst_port; /* destination port */ + PXE_IPADDR dst; /* destination ip */ + + PXE_BUFFER *recv; /* recieve buffer */ + PXE_BUFFER *send; /* send buffer */ + + PXE_FILTER_ENTRY* filter; /* filter, associated with connection */ + + /* current segment to fill, NULL - if unknown */ + /* PXE_TCP_QUEUED_SEGMENT *segment; */ + void *segment; + + /* send buffer usage map */ + uint8_t buf_blocks[PXE_TCP_BLOCK_COUNT]; + uint16_t chunk_size; /* buffer chunk size */ + + /* TODO: check if two members below needed */ + time_t last_sent; /* timestamp of last sending event */ + time_t last_recv; /* timestamp of last received event */ +} PXE_TCP_CONNECTION; + +/* initialisztion routine */ +void pxe_connection_init(); + +/* statistics */ +void pxe_connection_stats(); + +/* returns associated connection by filter */ +PXE_TCP_CONNECTION * filter_to_connection(PXE_FILTER_ENTRY *filter); + +/* initates handshaking */ +int pxe_tcp_connect(PXE_SOCKET *sock); + +/* initates connection break */ +int pxe_tcp_disconnect(PXE_SOCKET* sock); + +/* sends user data */ +int pxe_tcp_write(PXE_SOCKET *sock, void *data, uint16_t size); + +/* receives user data */ +int pxe_tcp_read(PXE_SOCKET *sock, void *data, uint16_t size); + +/* pushes current segment data */ +int pxe_tcp_push(PXE_FILTER_ENTRY *entry); + +/* checks connection, by sending ACK */ +int pxe_tcp_check_connection(PXE_SOCKET *sock); + +/* forces release of unused filters */ +void pxe_force_filter_release(); + +#endif Index: user/sbruno/pxe_http/pxe_core.c =================================================================== --- user/sbruno/pxe_http/pxe_core.c (nonexistent) +++ user/sbruno/pxe_http/pxe_core.c (revision 245442) @@ -0,0 +1,1122 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include +#include + +#include + +#include "btxv86.h" +#include "pxe.h" + +#include "pxe_arp.h" +#include "pxe_core.h" +#include "pxe_dhcp.h" +#ifdef PXE_MORE +#include "pxe_icmp.h" +#endif +#include "pxe_ip.h" +#include "pxe_isr.h" +#include "pxe_mem.h" +#include "pxe_udp.h" + +/* PXE API calls here will be made in same way as in pxeboot. + * the only difference - installation of isr, that was not needed in pxe.c. + */ + +/* stores data in packet */ +static int pxe_core_recieve(PXE_PACKET *pack, void *data, size_t size); + +uint8_t *scratch_buffer = NULL; +uint8_t *data_buffer = NULL; + +#ifdef PXE_CORE_STATIC_BUFFERS +static uint8_t static_scratch_buffer[PXE_BUFFER_SIZE]; +static uint8_t static_data_buffer[PXE_BUFFER_SIZE]; +#endif + +#ifdef PXE_EXCLUSIVE +static uint8_t exclusive_protocol = 0; +#endif +static pxenv_t *pxenv = NULL; /* PXENV+ */ +static pxe_t *pxe = NULL; /* !PXE */ + +/* pxe core structures*/ +/* current processing packet */ +static PXE_PACKET core_packet; +/* protocol's callback fuctions */ +static pxe_protocol_call core_protocol[256]; + +/* NIC info */ +static MAC_ADDR nic_mac; +/* frequently used IP's: server's IP, client's ip and etc */ +static PXE_IPADDR core_ips[PXE_IP_MAX]; + +static int pxe_state = PXE_DOWN; + +/* pxe_core_update_bootp() - updates core_ips and etc, after + * receving of rootpath + * in/out: + * none + */ +void +pxe_core_update_bootp() +{ + const PXE_IPADDR *paddr = pxe_get_ip(PXE_IP_ROOT); + int i = 0; + char temp[20]; + + if (paddr->ip == 0) + pxe_set_ip(PXE_IP_ROOT, pxe_get_ip(PXE_IP_SERVER)); + + struct in_addr tmp_in; + + tmp_in.s_addr = pxe_get_ip(PXE_IP_GATEWAY)->ip; + setenv("boot.netif.gateway", inet_ntoa(tmp_in), 1); + + /* initing route tables, using DHCP reply data */ + pxe_ip_route_init(pxe_get_ip(PXE_IP_GATEWAY)); + +#ifdef PXE_DEBUG + printf("pxe_open: gateway ip: %s\n", inet_ntoa(tmp_in)); +#endif + + tmp_in.s_addr = pxe_get_ip(PXE_IP_MY)->ip; + setenv("boot.netif.ip", inet_ntoa(tmp_in), 1); + + tmp_in.s_addr = pxe_get_ip(PXE_IP_NETMASK)->ip; + setenv("boot.netif.netmask", inet_ntoa(tmp_in), 1); + + sprintf(temp, "%6D", pxe_get_mymac(), ":"); + setenv("boot.netif.hwaddr", temp, 1); + + if (!rootpath[1]) + strcpy(rootpath, PXENFSROOTPATH); + + for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) + if (rootpath[i] == ':') + break; + + if (i && i != FNAME_SIZE && rootpath[i] == ':') { + + rootpath[i++] = '\0'; + + const PXE_IPADDR *root_addr = pxe_gethostbyname(rootpath); + pxe_set_ip(PXE_IP_ROOT, root_addr); + + pxe_memcpy(rootpath, servername, i); + pxe_memcpy(&rootpath[i], &rootpath[0], + strlen(&rootpath[i]) + 1); + } + + tmp_in.s_addr = pxe_get_ip(PXE_IP_ROOT)->ip; + +#ifdef PXE_DEBUG + printf("pxe_open: server addr: %s\n", inet_ntoa(tmp_in)); + printf("pxe_open: server path: %s\n", rootpath); +#endif +#ifdef LOADER_NFS_SUPPORT + setenv("boot.nfsroot.server", inet_ntoa(tmp_in), 1); + setenv("boot.nfsroot.path", rootpath, 1); +#endif + + /* removing '/' at tail of rootpath */ + size_t rlen = strlen(rootpath); + + if ( (rlen > 0) && (rootpath[rlen - 1] == '/')) + rootpath[rlen - 1] = '\0'; + + /* check if Web server option specified, + * if not, make it equal to root ip + */ + if (pxe_get_ip(PXE_IP_WWW)->ip == 0) { + pxe_set_ip(PXE_IP_WWW, pxe_get_ip(PXE_IP_ROOT)); + } +} + +/* pxe_core_init() - performs initialization of all PXE related code + * in: + * pxenv_p - pointer to PXENV+ structure + * pxe_p - pointer to !PXE + * out: + * 0 - failed + * 1 - success + */ +int +pxe_core_init(pxenv_t *pxenv_p, pxe_t* pxe_p) +{ +#ifdef PXE_CORE_DEBUG + printf("pxe_core_init(): started (pxenv_p = 0x%x, pxe_p = 0x%x).\n", + pxenv_p, pxe_p); +#endif + int counter = 0; + uint8_t checksum = 0; + uint8_t *checkptr = NULL; + +#ifdef PXE_CORE_DEBUG + printf("pxe_core_init(): initing structures....\n"); +#endif + t_PXENV_GET_CACHED_INFO *gci_p = NULL; + + pxe_memset(&core_packet, 0, sizeof(core_packet)); + pxe_memset(core_protocol, 0, sizeof(core_protocol)); + pxe_memset(core_ips, 0, sizeof(core_ips)); + + pxenv = pxenv_p; + pxe = pxe_p; + +#ifndef PXE_CORE_STATIC_BUFFERS + /* 0. initing scratch and data buffers */ + data_buffer = pxe_alloc(PXE_BUFFER_SIZE); + + if (data_buffer == NULL) { + return (0); + } + + scratch_buffer = pxe_alloc(PXE_BUFFER_SIZE); + + if (scratch_buffer == NULL) { + pxe_free(data_buffer); + return (0); + } +#else + data_buffer = static_data_buffer; + scratch_buffer = static_scratch_buffer; +#endif + /* 1. determine PXE API entry point */ + if(pxenv_p == NULL) + return (0); + + /* look for "PXENV+" */ + if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) { + pxenv_p = NULL; + return (0); + } + + /* make sure the size is something we can handle */ + if (pxenv_p->Length > sizeof(*pxenv_p)) { + printf("PXENV+ structure too large, ignoring\n"); + pxenv_p = NULL; + return (0); + } + + /* + * do byte checksum: + * add up each byte in the structure, the total should be 0 + */ + checksum = 0; + checkptr = (uint8_t *) pxenv_p; + + for (counter = 0; counter < pxenv_p->Length; counter++) + checksum += *checkptr++; + + if (checksum != 0) { + printf("PXENV+ structure failed checksum, ignoring\n"); + pxenv_p = NULL; + return (0); + } + +#ifdef PXE_CORE_DEBUG + printf("pxe_core_init(): PXENV+ checked.\n"); +#endif + + /* + * PXENV+ passed, so use that if !PXE is not available or + * the checksum fails. + */ + if (pxenv_p->Version >= 0x0200) { + + for (;;) { + if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) { + pxe_p = NULL; + break; + } + + checksum = 0; + checkptr = (uint8_t *)pxe_p; + + for (counter = 0; counter < pxe_p->StructLength; + counter++) + checksum += *checkptr++; + + if (checksum != 0) { + pxe_p = NULL; + } + + break; + } + } + + /* show version and entry point */ + printf("\nPXE v.%d.%d", + (uint8_t) (pxenv_p->Version >> 8), + (uint8_t) (pxenv_p->Version & 0xFF)); + + printf(" @ %04x:%04x\n", + pxe_p->EntryPointSP.segment, + pxe_p->EntryPointSP.offset); + + /* setting entry point in tramp code */ + __pxe_entry_seg = pxe->EntryPointSP.segment; + __pxe_entry_off = pxe->EntryPointSP.offset; + + pxe_state = PXE_INITING; + + /* 2. getting cached info */ + gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer; + pxe_memset(gci_p, 0, sizeof(*gci_p)); + + /* getting Boot Server Discovery reply */ + + /* pointer to PXE Cached information. */ + BOOTPLAYER* bootplayer = (BOOTPLAYER *)data_buffer; + + gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; + gci_p->BufferSize = sizeof(BOOTPLAYER); + gci_p->Buffer.segment = VTOPSEG(bootplayer); + gci_p->Buffer.offset = VTOPOFF(bootplayer); + + if ( (!pxe_core_call(PXENV_GET_CACHED_INFO)) || + (gci_p->Status != 0) ) + { +#ifdef PXE_CORE_DEBUG + printf("pxe_core_init(): error status = 0x%x\n", gci_p->Status); +#endif + pxe_p = NULL; + pxe_state = PXE_DOWN; + return (0); + } + +#ifdef PXE_CORE_DEBUG + printf("pxe_core_init(): copied %d (%d)bytes of cached packet.\n", + gci_p->BufferSize, gci_p->BufferLimit); +#endif + + /* 3. install isr */ + pxe_core_install_isr(); + pxe_state = PXE_READY; + + /* 4. open connection to network */ + t_PXENV_UNDI_OPEN *undi_open = (t_PXENV_UNDI_OPEN *)scratch_buffer; + + pxe_memset(undi_open, 0, sizeof(t_PXENV_UNDI_OPEN)); + undi_open->PktFilter = FLTR_DIRECTED | FLTR_BRDCST; + undi_open->R_Mcast_Buf.MCastAddrCount = 0; + + if (!pxe_core_call(PXENV_UNDI_OPEN)) { + printf("pxe_core_init(): failed to open network connection.\n"); + return (0); + } + + /* showing information about NIC */ + PXE_IPADDR addr; + addr.ip = bootplayer->yip; /* my ip */ + + printf("my ip: %s\n", inet_ntoa(addr.ip)); + + /* my MAC */ + pxe_memcpy(&bootplayer->CAddr, &nic_mac, MAC_ADDR_LEN); + printf("my MAC: %6D\n", nic_mac, ":"); + + /* setting default ips*/ + pxe_set_ip(PXE_IP_MY, &addr); /* nic ip */ + + addr.ip = bootplayer->sip; /* boot server ip */ + pxe_set_ip(PXE_IP_SERVER, &addr); + + /* setting next to default ip (boot server ip) */ + /* nameserver ip*/ + pxe_set_ip(PXE_IP_NAMESERVER, &addr); + /* gateway ip */ + pxe_set_ip(PXE_IP_GATEWAY, &addr); + + /* web server */ + addr.ip = 0; + pxe_set_ip(PXE_IP_WWW, &addr); + + addr.ip = 0xffffffff; + /* netmask, default to 255.255.255.0 */ + pxe_set_ip(PXE_IP_NETMASK, &addr); + /* broadcast address, default to 255.255.255.255 */ + pxe_set_ip(PXE_IP_BROADCAST, &addr); + + /* initing modules */ + pxe_arp_init(); + pxe_filter_init(); +#ifdef PXE_MORE + pxe_icmp_init(); +#endif +#ifdef PXE_POOL_SLOTS + pxe_buffer_init(); +#endif + pxe_socket_init(); + pxe_udp_init(); + pxe_tcp_init(); + +#ifndef PXE_BOOTP_USE_LIBSTAND + /* trying to get gateway/nameserver info from DHCP server */ + pxe_dhcp_query(bootplayer->ident); + pxe_core_update_bootp(); +#endif + +#ifdef PXE_CORE_DEBUG + printf("pxe_core_init(): ended.\n"); +#endif + + return (1); +} + +/* pxe_core_install_isr() - installs ISR for NIC + * in/out: + * none + */ +void +pxe_core_install_isr() +{ + t_PXENV_UNDI_GET_INFORMATION *undi_info = + (t_PXENV_UNDI_GET_INFORMATION *)scratch_buffer; + +#ifdef PXE_CORE_DEBUG + printf("pxe_isr_install() called\n"); +#endif + pxe_memset(undi_info, 0, sizeof(t_PXENV_UNDI_GET_INFORMATION)); + + if (!pxe_core_call(PXENV_UNDI_GET_INFORMATION)) { + printf("pxe_core_install_isr(): failed get NIC information.\n"); + return; + } + + if (undi_info->Status != 0) + return; + + __pxe_nic_irq = (uint16_t)(undi_info->IntNumber); + + uint8_t int_num = (__pxe_nic_irq < 8) ? + __pxe_nic_irq + 0x08 : __pxe_nic_irq + 0x68; + +#ifdef PXE_CORE_DEBUG + printf("pxe_core_install_isr() info:\n"); + printf("\tIRQ (int): %d (%d)\n", undi_info->IntNumber, int_num); + printf("\tMTU: %d\n", undi_info->MaxTranUnit); + printf("\tRX/TX buffer queue: %d/%d\n", + undi_info->RxBufCt, undi_info->TxBufCt); +#endif + __pxe_entry_seg2 = pxe->EntryPointSP.segment; + __pxe_entry_off2 = pxe->EntryPointSP.offset; + + pxe_memset(&v86, 0, sizeof(v86)); + + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.addr = (VTOPSEG(__isr_install) << 16) | VTOPOFF(__isr_install); + v86.eax = int_num; + v86.ebx = VTOPSEG(__pxe_isr); + v86.edx = VTOPOFF(__pxe_isr); + v86int(); + v86.ctl = V86_FLAGS; + + printf("\tchained handler @ 0x%x:0x%x\n", v86.ebx, v86.edx); + + __chained_irq_seg = v86.ebx; + __chained_irq_off = v86.edx; + +#ifdef PXE_CORE_DEBUG + printf("pxe_core_install_isr(): success (isr @ 0x%x:0x%x)\n", + VTOPSEG(__pxe_isr), VTOPOFF(__pxe_isr)); +#endif +} + +#ifdef PXE_MORE +/* pxe_core_copy() - calls __mem_copy() to copy data in real mode + * to data buffer, usefull if data is in addresses inaccessible + * from user space. TODO!: Check, if really needed. + * in: + * seg_from - segment of source buffer + * off_from - offset of source buffer + * seg_to - segment of destination buffer + * off_to - offset of destination buffer + * size - number of bytes to copy + * out: + * none + */ +void +pxe_core_copy(uint16_t seg_from, uint16_t off_from, + uint16_t seg_to, uint16_t off_to, uint16_t size) +{ + + pxe_memset(&v86, 0, sizeof(v86)); + + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.addr = (VTOPSEG(__mem_copy) << 16) | VTOPOFF(__mem_copy); + v86.eax = (seg_from << 16 ) | off_from; + v86.ebx = (seg_to << 16 ) | off_to; + v86.ecx = size; + v86int(); + v86.ctl = V86_FLAGS; +} +#endif /* PXE_MORE */ + +/* pxe_core_remove_isr() - restores default handler for interrupt + * in/out: + * none + */ +void +pxe_core_remove_isr() +{ + + pxe_memset(&v86, 0, sizeof(v86)); + + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.addr = (VTOPSEG(__isr_install) << 16) | VTOPOFF(__isr_install); + + uint8_t int_num = (__pxe_nic_irq < 8) ? + __pxe_nic_irq + 0x08 : __pxe_nic_irq + 0x68; + + v86.eax = int_num; + v86.ebx = __chained_irq_seg; + v86.edx = __chained_irq_off; + v86int(); + v86.ctl = V86_FLAGS; +} + +/* pxe_core_shutdown() - shutdown all modules. TODO: add needed modules shutdown. + * in: + * none + * out: + * 0 - failed + * 1 - success + */ +int +pxe_core_shutdown() +{ +#ifdef PXE_CORE_DEBUG + printf("pxe_core_shutdown(): shutdown started.\n"); +#endif + if (core_packet.data) + pxe_free(core_packet.data); + + /* 1. uninstall isr */ + pxe_core_remove_isr(); + + pxe_udp_shutdown(); + + /* 2. shutdown PXE */ + t_PXENV_UNLOAD_STACK *unload_stack_p = + (t_PXENV_UNLOAD_STACK *)scratch_buffer; + + t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p = + (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer; +/* + pxe_core_call(PXENV_UNDI_SHUTDOWN); + pxe_core_call(PXENV_UNLOAD_STACK); +*/ +#ifndef PXE_CORE_STATIC_BUFFERS + pxe_free(scratch_buffer); + pxe_free(data_buffer); +#endif + /* make pxe_core_call() unavailable */ + pxe_state = PXE_DOWN; + + return (1); +} + +/* + * function code is taken from bangpxe_call(), /sys/boot/libi386/pxe.c + * needs pxe_isr.s wrapper and vm86int() support. + * in: + * func - PXE function number + * out: + * 1 - success + * 0 - failed + */ +int +pxe_core_call(int func) +{ +#ifdef PXE_CORE_DEBUG_HELL + printf("pxe_core_call(): func = 0x%x...", func); +#endif + if (pxe_state == PXE_DOWN) { + printf("pxe_core_call(): internal error, PXE shutdowned.\n"); + return (0); + } + + pxe_memset(&v86, 0, sizeof(v86)); + + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.edx = VTOPSEG(scratch_buffer); + v86.eax = VTOPOFF(scratch_buffer); + v86.addr = (VTOPSEG(__pxe_call) << 16) | VTOPOFF(__pxe_call); + v86.ebx = func; + v86int(); + v86.ctl = V86_FLAGS; + + int call_status = v86.eax; + int status = *((uint16_t *)scratch_buffer); + +#ifdef PXE_CORE_DEBUG_HELL + printf("%s (0x%x)\n", (call_status == 0) ? "?OK" : "?NOK", status ); +#endif + return (status == 0) ? 1 : 0; +} + +/* pxe_core_transmit() - transmits packet to network + * in: + * pack - packet definition structure. + * out: + * 0 - failed + * 1 - success + */ +int +pxe_core_transmit(PXE_PACKET *pack) +{ + t_PXENV_UNDI_TRANSMIT *undi_send = + (t_PXENV_UNDI_TRANSMIT *)scratch_buffer; + + pxe_memset(undi_send, 0, sizeof(t_PXENV_UNDI_TRANSMIT)); + + t_PXENV_UNDI_TBD tbd; + pxe_memset(&tbd, 0, sizeof(t_PXENV_UNDI_TBD)); + + tbd.ImmedLength = pack->data_size; /* packet length */ + tbd.Xmit.segment = VTOPSEG(pack->data); /* immediate transmit buffer */ + tbd.Xmit.offset = VTOPOFF(pack->data); /* segment & offset */ + tbd.DataBlkCount = 0 ; /* only immediate data */ + + undi_send->Protocol = pack->protocol; + + undi_send->TBD.segment = VTOPSEG(&tbd); /* SEGOFF16 to xmit block data */ + undi_send->TBD.offset = VTOPOFF(&tbd); + + /* if not broadcast packet, specify destination media address */ + undi_send->XmitFlag = + (pack->flags & PXE_BCAST) ? XMT_BROADCAST : XMT_DESTADDR; + + if (undi_send->XmitFlag == XMT_DESTADDR) { + undi_send->DestAddr.segment = VTOPSEG(pack->dest_mac); + undi_send->DestAddr.offset = VTOPOFF(pack->dest_mac); + } + +#ifdef PXE_CORE_DEBUG_HELL + printf("pxe_core_transmit(): %s %6D, proto = %d, %d bytes\n", + (undi_send->XmitFlag == XMT_DESTADDR) ? "to" : "bcast", + pack->dest_mac, ":", undi_send->Protocol, pack->data_size); +#endif + +/* NOTE: it is not needed, we use only immediate block */ +/* we've inited undi_info with zero, so two lines below are not needed */ +/* tbd.DataBlk[0].TDRsvdByte = 0; /* reserved */ +/* tbd.DataBlk[1].TDRsvdByte = 0; /* reserved */ +/* tbd.DataBlock[0].TDDataLen=tbd.ImmedLength; /* size of packet*/ +/* tbd.DataBlock[0].TDPtrType = 1; /* segment:offset type */ +/* segment and offset to data */ +/* tbd.DataBlock[0].TDDataPtr.segment = VTOPSEG(pack->data); + * tbd.DataBlock[0].TDDataPtr.offset = VTOPOFF(pack->data); */ + + int status = 0; /* PXE call status */ + int tryCount = 0; /* tryCount for packet resending */ + + for (; tryCount < 5; ++tryCount) { + status = pxe_core_call(PXENV_UNDI_TRANSMIT); + + if (undi_send->Status != 0) { + printf("%d: pxe_core_transmit(): failed with status 0x%x\n", + tryCount, undi_send->Status); + delay(100); + continue; + } + + if (status != 0) + break; + } + + return (status); +} + +/* pxe_core_get_packet() - checks, if there are any new packets in receive queue + * in: + * func - function to fill in FuncFlag of t_PXENV_UND_ISR structure + * undi_isr- pointer to t_PXENV_UND_ISR, used to return data (sizes and etc) + * out: + * 0 - failed + * 1 - success + */ +static int +pxe_core_get_packet(int func, t_PXENV_UNDI_ISR *undi_isr ) +{ +#ifdef PXE_CORE_DEBUG_HELL + printf("get_packet(): started with func %d\n", func); +#endif + + undi_isr->FuncFlag = func; + int count = 0; + + while(1) { /* cycle to handle busy flag */ + + undi_isr->Status = 0; + + if (!pxe_core_call(PXENV_UNDI_ISR)) { +#ifdef PXE_CORE_DEBUG_HELL + printf("get_packet(): failed.\n"); +#endif + } + + if (undi_isr->Status != 0) { + /* something gone wrong */ +#ifdef PXE_CORE_DEBUG_HELL + printf("get_packet(): fail status = 0x%x.\n", + undi_isr->Status); +#endif + return (0); + } + + if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_DONE) { + /* nothing to do */ +#ifdef PXE_CORE_DEBUG_HELL + printf("get_packet(): all is already done.\n"); +#endif + return (0); + } + + if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) { + /* NIC is busy, wait */ +#ifdef PXE_CORE_DEBUG_HELL + printf("get_packet(): device is busy.\n"); +#endif + ++count; + if (count == 10) + return (0); + + delay(10); /* wait, may be it will be not busy later */ + + continue; + } + + if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_RECIEVE) { + /* that's what we are waiting for */ +#ifdef PXE_CORE_DEBUG_HELL + printf("get_packet(): got packet!\n"); +#endif + break; + } + + if (undi_isr->FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) { + /* transmitted packet */ +#ifdef PXE_CORE_DEBUG_HELL + printf("get_packet(): transmit packet.\n"); +#endif + return (0); + } + } + + return (1); +} + +/* pxe_core_recv_packets() - recieves all packets, if there is any waiting + * in receiving queue, and gives it to protocol + * callback functions. + * in: + * none + * out: + * 0 - there is no packets in receiving queue, + * or it's not interesting for us. + * positive - there were packets in queue and some + * protocol handler was interested in it. + */ +int +pxe_core_recv_packets() +{ + /* + * TODO: make it simplier to understand, too many ifs, many lines. + */ + int buffer_size = 0; /* total size of packet*/ + int protocol = 0; /* protocol */ + int received = 0; /* bytes received to buffer */ + + int frame_size = 0; /* size of frame */ + int drop_flag = 0; /* 1 if current packet must be dropped */ + /* total count of processed packets during call*/ + int processed_packets = 0; + + PXE_PACKET *pack=NULL; /* allocated packet */ + PXE_PACKET dummy_pack; /* temporary struct, used to mimic + * real packet struct + */ + +/* if (__pxe_isr_occured == 0) /* there are no packets for us to handle */ +/* return (0); +*/ + __pxe_isr_occured = 0; /* reset flag */ + + t_PXENV_UNDI_ISR *undi_isr = + (t_PXENV_UNDI_ISR *)scratch_buffer; + + /* starting packet receive cycle */ + + int func = PXENV_UNDI_ISR_IN_PROCESS; + +packet_start: + + drop_flag = 0; + pxe_memset(undi_isr, 0, sizeof(t_PXENV_UNDI_ISR)); + + if (0 == pxe_core_get_packet(func, undi_isr)) + return (processed_packets); + + buffer_size = undi_isr->BufferLength; + protocol = undi_isr->ProtType; + frame_size = undi_isr->FrameLength; + + /* check if no packet, it seems 'all is done' */ + if ( (frame_size == 0) && (buffer_size == 0)) + return (processed_packets); + +#ifdef PXE_CORE_DEBUG_HELL + printf("pxe_core_recv_packets(): size = %d/%d, proto = %d.\n", + frame_size, buffer_size, protocol); +#endif + + /* we are interested in ARP & IP packets */ + + if ( (protocol == PXE_PROTOCOL_UNKNOWN) || + (protocol == PXE_PROTOCOL_RARP) ) + { +#ifdef PXE_CORE_DEBUG + printf("recv_packets(): not interesting protocol.\n"); +#endif + drop_flag = 1; /* clear queue, receiving frames of packet */ + } + +#ifdef PXE_EXCLUSIVE + /* experimental: to avoid resendings of ip packets for unknown MAC */ + if (exclusive_protocol && (protocol != exclusive_protocol)) { +#ifdef PXE_CORE_DEBUG + printf("recv_packets(): not exclusive protocol (%d != %d).\n", + protocol, exclusive_protocol); +#endif + drop_flag = 1; /* clear queue, receiving frames of packet */ + } +#endif + +#ifdef PXE_CORE_DEBUG + if (frame_size != buffer_size) { + printf("recv_packets(): fragmented packet %u/%u\n", + frame_size, buffer_size); + } +#endif + /* sanity check */ + if (frame_size < PXE_BUFFER_SIZE) { +/* pxe_core_copy( undi_isr->Frame.segment, undi_isr->Frame.offset, + VTOPSEG(data_buffer), VTOPOFF(data_buffer), frame_size); + */ + pxe_memcpy(PTOV(undi_isr->Frame.segment * 16 + + undi_isr->Frame.offset), + data_buffer, frame_size); + + } else { + printf("pxe_core_recv_packets(): not enough buffer (%d bytes) " + "for frame size %d bytes\n", PXE_BUFFER_SIZE, frame_size); + + drop_flag = 1; /* drop this packet */ + } + + /* checking first fragment, this may help to avoid memory allocation + * and memblock copy in main cycle below + */ + + if (!drop_flag) { + + PXE_IP_HDR *iphdr = + (PXE_IP_HDR *)(data_buffer + MEDIAHDR_LEN_ETH); + + dummy_pack.protocol = protocol; + dummy_pack.state = PXE_PACKET_STATE_USING; + + dummy_pack.raw_data = data_buffer; + dummy_pack.raw_size = frame_size; + dummy_pack.data = data_buffer + MEDIAHDR_LEN_ETH; + dummy_pack.data_size = frame_size - MEDIAHDR_LEN_ETH; + + + dummy_pack.user_data = NULL; + + if (protocol == PXE_PROTOCOL_ARP) { + + pxe_arp_protocol(&dummy_pack, PXE_CORE_HANDLE); + ++processed_packets; + + /* aasume ARP packet always in one fragment */ + + func = PXENV_UNDI_ISR_IN_GET_NEXT; + + goto packet_start; + } + + /* TODO: calc ip checksum */ + + if ( (!core_protocol[iphdr->protocol]) || + (!core_protocol[iphdr->protocol]( + &dummy_pack, + (buffer_size == frame_size) ? + PXE_CORE_HANDLE : PXE_CORE_FRAG)) ) + { + drop_flag = 1; + } else { + + pack = pxe_core_alloc_packet(buffer_size); + + if (pack == NULL) + drop_flag = 1; + else { + + /* pointing user_data to beginning of data. + * It's used by pxe_core_receive() + * during receiving packet. + */ + pack->user_data = pack->data; + } + } + } + + received = frame_size; + + while (received < buffer_size) { + + if (!pxe_core_get_packet(PXENV_UNDI_ISR_IN_GET_NEXT, undi_isr)) + break; + + frame_size = undi_isr->FrameLength; + + if (frame_size < PXE_BUFFER_SIZE) { +/* pxe_core_copy( undi_isr->Frame.segment, undi_isr->Frame.offset, + VTOPSEG(data_buffer), VTOPOFF(data_buffer), frame_size); + */ + pxe_memcpy(PTOV(undi_isr->Frame.segment * 16 + + undi_isr->Frame.offset), + data_buffer, frame_size); + } else { + printf("pxe_core_recv_packets(): not enough buffer (%d bytes)" + " for frame size %d bytes.", + PXE_BUFFER_SIZE, frame_size); + + drop_flag = 1; /* drop this packet */ + } + + if (!drop_flag) + pxe_core_recieve(pack, data_buffer, frame_size); + + received += frame_size; + } + + if (received < buffer_size) { /* pxe_core_get_packet() in cycle failed */ + + if (!drop_flag) { + pack->state = PXE_PACKET_STATE_FREE; + } + + return (processed_packets); /* it's failed, finish receive cycle */ + } + + if (!drop_flag) { + + pack->user_data = NULL; + + PXE_IP_HDR *iphdr=(PXE_IP_HDR *)pack->data; + + /* TODO: calc ip checksum */ + pack->protocol = protocol; + + if ( (!core_protocol[iphdr->protocol]) || + (!core_protocol[iphdr->protocol](pack, PXE_CORE_HANDLE))) + { + /* protocol not interested in it */ + pack->state = PXE_PACKET_STATE_FREE; + } + } + + ++processed_packets; + /* received one or more packets, need check if there are any others */ + + func = PXENV_UNDI_ISR_IN_GET_NEXT; + + goto packet_start; + + /* never getting here */ + return (0); +} + +/* pxe_core_recieve() - recieves sequentially fragments data in packet buffer + * in: + * pack - packet with buffer to receive in + * frame_data - fragment data buffer + * frame_size - frag,ent buffer size + * out: + * 0 - failed + * 1 - success + */ +static int +pxe_core_recieve(PXE_PACKET *pack, void *frame_data, size_t frame_size) +{ + + /* check to be sure */ + if (pack->user_data == NULL) + pack->user_data = pack->data; + + /* sanity check */ + if ( (pack->user_data - pack->data) + frame_size > pack->data_size) + return (0); /* This must not ever be*/ + + pxe_memcpy(pack->user_data, frame_data, frame_size); + + return (1); +} + +/* TODO: think if this function is needed + * allocates packet, creates buffer for data if necessary + */ +PXE_PACKET * +pxe_core_alloc_packet(size_t packet_size) +{ + + if (core_packet.state == PXE_PACKET_STATE_FREE) { + /* packet structure seems to be free */ + /* mark it busy */ + core_packet.state = PXE_PACKET_STATE_USING; + + if (core_packet.data_size < packet_size) { + /* packet contains less memmory than needed */ + + void *data = pxe_alloc(packet_size + MEDIAHDR_LEN_ETH); + pxe_free(core_packet.data); + core_packet.raw_data = data; + + /* failed to allocate enough memory for packet */ + if (data == NULL) { + core_packet.data_size = 0; + core_packet.raw_size = 0; + core_packet.data = NULL; + + return (NULL); + } + + core_packet.data_size = packet_size; + core_packet.raw_size = packet_size + MEDIAHDR_LEN_ETH; + core_packet.data = data + MEDIAHDR_LEN_ETH; + } + + return (&core_packet); + } + + return (NULL); +} + +/* pxe_core_register() - registers protocol in protocols table + * in: + * proto - IP protocol number + * proc - callback + * out: + * none + */ +void +pxe_core_register(uint8_t proto, pxe_protocol_call proc) +{ + + core_protocol[proto]=proc; +} + +#ifdef PXE_EXCLUSIVE +/* pxe_core_exclusive() - sets protocol exclusive when receiving packets + * in: + * proto - protocol number (PXE_PROTOCOL_...) + * out: + * none + */ +void +pxe_core_exclusive(uint8_t proto) +{ +#ifdef PXE_CORE_DEBUG_HELL + printf("pxe_core_exlusive(): %d protocol.\n", proto); +#endif + exclusive_protocol = proto; +} +#endif + +/* pxe_get_mymac() - returns NIC MAC + * in: + * none + * out: + * non NULL pointer to MAC_ADDR + */ +const MAC_ADDR* +pxe_get_mymac() +{ + return (const MAC_ADDR *)&nic_mac; +} + +/* pxe_get_ip() - returns ip related data, specified by id parameter + * in: + * id - id of needed data (PXE_IP_ constants) + * out: + * associated with this id value + */ +const PXE_IPADDR * +pxe_get_ip(uint8_t id) +{ + if (id < PXE_IP_MAX) + return (&core_ips[id]); + + return (0); +} + +/* pxe_set_ip() - sets ip related data, specified by id parameter + * in: + * id - id of needed data (PXE_IP_ constants) + * new_ip - new uint32_t data + * out: + * none + */ +void +pxe_set_ip(uint8_t id, const PXE_IPADDR *new_ip) +{ + if (id < PXE_IP_MAX) { + pxe_memcpy(new_ip, &core_ips[id], sizeof(PXE_IPADDR)); + } +} + +/* getsecs() - returns time in seconds + * in: + * none + * out: + * elapsed time in seconds + */ +time_t +getsecs() +{ + time_t secs = 0; + + time(&secs); + + return (secs); +} Index: user/sbruno/pxe_http/pxe_core.h =================================================================== --- user/sbruno/pxe_http/pxe_core.h (nonexistent) +++ user/sbruno/pxe_http/pxe_core.h (revision 245442) @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_CORE_H_INCLUDED +#define PXE_CORE_H_INCLUDED + +/* + * contains wrappers for PXE API functions + */ + +#include +#include +#include + +#include "../libi386/pxe.h" +#include "pxe_ip.h" + +#define PXE_BUFFER_SIZE 0x0800 + +/* define to use statically allocated buffers */ +#define PXE_CORE_STATIC_BUFFERS + +/* packet states for packets, used by pxe_core. + * Currently (only one packet at any time) - is unused. + */ +#define PXE_PACKET_STATE_FREE 0 +#define PXE_PACKET_STATE_USING 1 + +#define PXE_DOWN 0 +#define PXE_INITING 1 +#define PXE_READY 2 + +/* size of media header, used in allocating memmory for packet */ +#define MEDIAHDR_LEN_ETH 14 +/* packet type: broadcast and directed */ +#define PXE_BCAST 1 +#define PXE_SINGLE 0 +/* + * structure, used to provide information about packet in pxe_core + */ +typedef struct pxe_packet { + + uint8_t protocol; /* protocol, used in packet */ + uint8_t state; /* state of packet (PXE_PACKET_STATE_ ... ) */ + uint8_t flags; /* flags if it is broadcast packet */ + + void* raw_data; /* pointer to data, including media header */ + size_t raw_size; /* real size of packet */ + + void* data; /* pointer to buffer with packet data */ + size_t data_size; /* size of packet data */ + + const MAC_ADDR *dest_mac; /* destination media address */ + + void* user_data; /* pointer to user data. + * used by higher level protocols + */ +} PXE_PACKET; + +#define PXE_PROTOCOL_UNKNOWN 0 +#define PXE_PROTOCOL_IP 1 +#define PXE_PROTOCOL_ARP 2 +#define PXE_PROTOCOL_RARP 3 +#define PXE_PROTOCOL_OTHER 4 + +/* init of PXE core structures. */ +int pxe_core_init(pxenv_t* pxenv_p, pxe_t* pxe_p); + +/* cleanup */ +int pxe_core_shutdown(); + +/* sends packet to a network */ +int pxe_core_transmit(PXE_PACKET *pack); + +/* allocates buffer for packet */ +PXE_PACKET *pxe_core_alloc_packet(size_t packet_size); + +/* recieves all packets waiting in queue, and calls protocols if needed */ +int pxe_core_recv_packets(); + +/* copies in real mode from one segment to another. */ +void pxe_core_copy(uint16_t seg_from, uint16_t off_from, uint16_t seg_to, + uint16_t off_to, uint16_t size); + +/* installs irq handler*/ +void pxe_core_install_isr(); + +/* removes irq handler*/ +void pxe_core_remove_isr(); + +/* call to PXE API */ +int pxe_core_call(int func); + +#define PXE_CORE_HANDLE 0x0 +#define PXE_CORE_FRAG 0x1 +/* protocol callback function type */ +typedef int (*pxe_protocol_call)(PXE_PACKET *pack, uint8_t function); + +/* registers protocol */ +void pxe_core_register(uint8_t ip_proto, pxe_protocol_call proc); + +/* set this protocol exclusive, other packets are ignored */ +#ifdef PXE_EXCLUSIVE +void pxe_core_exclusive(uint8_t proto); +#endif + +/* returns NIC MAC */ +const MAC_ADDR *pxe_get_mymac(); + +#define PXE_IP_MY 0 +#define PXE_IP_NET 1 +#define PXE_IP_NETMASK 2 +#define PXE_IP_NAMESERVER 3 +#define PXE_IP_GATEWAY 4 +#define PXE_IP_BROADCAST 5 +#define PXE_IP_SERVER 6 +#define PXE_IP_WWW 7 +#define PXE_IP_ROOT 8 +#define PXE_IP_MAX 9 +const PXE_IPADDR *pxe_get_ip(uint8_t id); +void pxe_set_ip(uint8_t id, const PXE_IPADDR *ip); + +/* returns time in seconds */ +time_t pxe_get_secs(); + +#define pxe_get_secs getsecs + +/* updates IPs after getting them via DHCP/BOOTP */ +void pxe_core_update_bootp(); + +#ifndef FNAME_SIZE +#define FNAME_SIZE 128 +#endif +extern char rootpath[FNAME_SIZE]; +extern char servername[256]; + +#endif // PXE_CORE_H_INCLUDED Index: user/sbruno/pxe_http/pxe_dhcp.c =================================================================== --- user/sbruno/pxe_http/pxe_dhcp.c (nonexistent) +++ user/sbruno/pxe_http/pxe_dhcp.c (revision 245442) @@ -0,0 +1,456 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_core.h" +#include "pxe_dhcp.h" +#include "pxe_ip.h" + +#ifdef PXE_BOOTP_USE_LIBSTAND +#include +#include +#include +#include +#else +#include "pxe_await.h" +#include "pxe_mem.h" +#include "pxe_sock.h" +#include "pxe_udp.h" +#endif + +#ifndef PXE_BOOTP_USE_LIBSTAND +/* adds option to provided buffer + * in: + * opt - current pointer in options section of DHCP packet + * option - option id + * opt_data- pointer to related to option data + * opt_len - size of data, pointed by opt_data + * out: + * new pointer in options sections + */ +uint8_t * +add_option(uint8_t *opt, uint8_t option, const void *opt_data, uint8_t opt_len) +{ + PXE_DHCP_OPT_HDR *opt_hdr = (PXE_DHCP_OPT_HDR *)opt; + + opt_hdr->option = option; + opt_hdr->len = opt_len; + + if ( (opt_data != NULL) && (opt_len != 0) ) + pxe_memcpy(opt_data, opt + sizeof(PXE_DHCP_OPT_HDR), opt_len); + + return (opt + sizeof(PXE_DHCP_OPT_HDR) + opt_len); +} + +/* parses options section of packet + * in: + * opts - pointer to options section + * max_size - size of option section data + * result - pointer to result return structure + * out: + * result - result of parsing options + */ +void +pxe_dhcp_parse_options(uint8_t *opts, uint16_t max_size, + PXE_DHCP_PARSE_RESULT *result) +{ + uint8_t *p=opts; + uint8_t code = opts[0]; + uint8_t len = 0; + + printf("DHCP options:\n"); + + while (code != PXE_DHCP_OPT_END) { + ++p; + len = 1 + (*p); + + switch (code) { + case 0: /* pad */ + len = 0; + break; + + case PXE_DHCP_OPT_NETMASK: + printf("netmask: %d.%d.%d.%d\n", + *(p + 1), *(p + 2), *(p + 3), *(p + 4)); + result->netmask.ip = *((uint32_t *)(p + 1)); + break; + + case PXE_DHCP_OPT_ROUTER: + printf("first router: %d.%d.%d.%d\n", + *(p + 1), *(p + 2), *(p + 3), *(p + 4)); + result->gw.ip = *((uint32_t *)(p + 1)); + break; + + case PXE_DHCP_OPT_NAMESERVER: + printf("first nameserver: %d.%d.%d.%d\n", + *(p + 1), *(p + 2), *(p + 3), *(p + 4)); + result->ns.ip = *((uint32_t *)(p + 1)); + break; + + case PXE_DHCP_OPT_TYPE: + result->message_type = *(p + 1); +#ifdef PXE_DEBUG + printf("message type: 0x%x\n", + result->message_type); +#endif + break; + + case PXE_DHCP_OPT_WWW_SERVER: + printf("www server ip: %d.%d.%d.%d\n", + *(p + 1), *(p + 2), *(p + 3), *(p + 4)); + result->www.ip = *((uint32_t *)(p + 1)); + break; + + case PXE_DHCP_OPT_ROOTPATH: + pxe_memcpy((p + 1), result->rootpath, len - 1); + printf("root path: %s\n", result->rootpath); + break; +#ifdef PXE_MORE + case PXE_DHCP_OPT_LEASE_TIME: +#ifdef PXE_DEBUG + printf("lease time: %d secs\n", + ntohl( *((uint32_t *)(p + 1)) )); +#endif + break; + + case PXE_DHCP_OPT_RENEWAL_TIME: +#ifdef PXE_DEBUG + printf("renewal in: %d secs\n", + ntohl( *((uint32_t *)(p + 1)) )); +#endif + break; + + case PXE_DHCP_OPT_REBINDING_TIME: +#ifdef PXE_DEBUG + printf("rebinding in: %d secs\n", + ntohl( *((uint32_t *)(p + 1)) )); +#endif + break; + + case PXE_DHCP_OPT_BROADCAST_IP: + printf("broadcast: %d.%d.%d.%d\n", + *(p + 1), *(p + 2), *(p + 3), *(p + 4)); + result->bcast_addr.ip = *((uint32_t *)(p + 1)); + break; + + case PXE_DHCP_OPT_ID: +#ifdef PXE_DEBUG + printf("server id: %d.%d.%d.%d\n", + *(p + 1), *(p + 2), *(p + 3), *(p + 4)); +#endif + break; + + case PXE_DHCP_OPT_DOMAIN_NAME: +#ifdef PXE_DEBUG + printf("domain name: %s\n", (p + 1)); +#endif + break; +#endif /* PXE_MORE */ + default: +#ifdef PXE_DEBUG + printf("DHCP Option %d (%d bytes) ignored\n", + code, len); +#endif + break; + }; + + p += len; + code = *p; + len = 0; + + if (p - opts > max_size) + break; + } +} + +/* create_dhcp_packet() - fills header of request packet + * in: + * wait_data - pointer to filled PXE_DHCP_WAIT_DATA + * out: + * none + */ +void +create_dhcp_packet(PXE_DHCP_WAIT_DATA *wait_data) +{ + uint8_t *buf = wait_data->data; + PXE_DHCP_HDR *dhcp_hdr = (PXE_DHCP_HDR *)buf; + + dhcp_hdr->op = PXE_DHCP_REQUEST; + dhcp_hdr->htype = ETHER_TYPE; + dhcp_hdr->hlen = 6; + dhcp_hdr->hops = 0; + dhcp_hdr->secs = 0; + dhcp_hdr->xid = wait_data->xid; + + const PXE_IPADDR *my = pxe_get_ip(PXE_IP_MY); + dhcp_hdr->ciaddr = my->ip; + dhcp_hdr->magic = htonl(PXE_MAGIC_DHCP); + + pxe_memcpy(pxe_get_mymac(), dhcp_hdr->chaddr, dhcp_hdr->hlen); +} + +/* dhcp_send_request() - creates socket, sends DHCP request + * in: + * wait_data - pointer to filled PXE_DHCP_WAIT_DATA + * out: + * 0 - failed + * 1 - success + */ +int +dhcp_send_request(PXE_DHCP_WAIT_DATA *wait_data) +{ + uint8_t *options = wait_data->data + sizeof(PXE_DHCP_HDR); +/* uint8_t message_type = PXE_DHCPREQUEST; */ + uint8_t message_type = PXE_DHCPDISCOVER; + + /* cleaning up packet data */ + pxe_memset(wait_data->data, 0, wait_data->size); + + create_dhcp_packet(wait_data); + + /* setting INFORM type */ + options = add_option(options, PXE_DHCP_OPT_TYPE, &message_type, 1); + + /* requesting for my ip */ + const PXE_IPADDR *client_ip = pxe_get_ip(PXE_IP_MY); + + options = add_option(options, PXE_DHCP_OPT_REQUEST_IP, + &(client_ip->ip), sizeof(client_ip->ip)); + + /* end of options */ + options = add_option(options, PXE_DHCP_OPT_END, NULL, 0); + + /* send */ + uint16_t send_size = options - wait_data->data; + int socket = pxe_socket(); + + if (socket == -1) { + printf("dhcp_send_request(): failed to create socket.\n"); + return (0); + } + + if (pxe_bind(socket, client_ip, PXE_DHCP_CLIENT_PORT, + PXE_UDP_PROTOCOL) == -1) + { + printf("dhcp_send_request(): failed bind client DHCP port.\n"); + pxe_close(socket); + return (0); + } + + PXE_IPADDR bcast; + bcast.ip = PXE_IP_BCAST; + + if (send_size != pxe_sendto(socket, &bcast, PXE_DHCP_SERVER_PORT, + wait_data->data, send_size)) + { + printf("dhcp_send_request(): failed to send DHCP request.\n"); + pxe_close(socket); + return (0); + } + + wait_data->socket = socket; + + return (1); +} + +/* dhcp_parse() - parses received packet, drops if it is invalid + * in: + * data - pointer to buffer with data + * size - szie of buffer + * xid - client/transaction id + * out: + * 0 - failed + * 1 - success + */ +int +dhcp_parse(void *data, int size, uint32_t xid) +{ + PXE_DHCP_HDR *dhcp_hdr = (PXE_DHCP_HDR *)data; + + if (dhcp_hdr->magic != htonl(PXE_MAGIC_DHCP) ) /* unknown magic */ + return (0); + + if (dhcp_hdr->op != PXE_DHCP_REPLY) { + printf("dhcp_parse(): got request, not reply.\n"); + return (0); + } + + if (dhcp_hdr->xid != xid) { + printf("dhcp_parse(): wrong xid 0x%x, need 0x%x.\n", + dhcp_hdr->xid, xid); + return (0); + } + + PXE_DHCP_PARSE_RESULT opts_result; + pxe_memset(&opts_result, 0, sizeof(PXE_DHCP_PARSE_RESULT)); + + /* parsing options section */ + pxe_dhcp_parse_options(data + sizeof(PXE_DHCP_HDR), + size - sizeof(PXE_DHCP_HDR), &opts_result); + + if ( (opts_result.message_type != PXE_DHCPOFFER) && + (opts_result.message_type != PXE_DHCPACK) ) + { + /* not our packet */ + return (0); + } + + /* if successfuly parsed, setting appropriate ip data */ + if (opts_result.ns.ip) + pxe_set_ip(PXE_IP_NAMESERVER, &opts_result.ns); + + if (opts_result.gw.ip) + pxe_set_ip(PXE_IP_GATEWAY, &opts_result.gw); + + if (opts_result.netmask.ip) + pxe_set_ip(PXE_IP_NETMASK, &opts_result.netmask); + + if (opts_result.bcast_addr.ip) + pxe_set_ip(PXE_IP_BROADCAST, &opts_result.bcast_addr); + + if (opts_result.www.ip) + pxe_set_ip(PXE_IP_WWW, &opts_result.www); + + if (opts_result.rootpath[0]) + strcpy(PXENFSROOTPATH, opts_result.rootpath); + + return (1); +} + +/* dhcp_await() - await function for DHCP replies + * in: + * function - await function + * try_number - number of try + * timeout - timeout from start of try + * data - pointer to PXE_DHCP_WAIT_DATA + * out: + * PXE_AWAIT_ constants + */ +int +dhcp_await(uint8_t function, uint16_t try_number, uint32_t timeout, void *data) +{ + PXE_DHCP_WAIT_DATA *wait_data = (PXE_DHCP_WAIT_DATA *)data; + + int size = 0; + + switch (function) { + + case PXE_AWAIT_STARTTRY: + + if (!dhcp_send_request(wait_data)) + return (PXE_AWAIT_NEXTTRY); + + break; + + case PXE_AWAIT_NEWPACKETS: + /* some packets were received, need checking our socket */ + size = pxe_recv(wait_data->socket, wait_data->data, + wait_data->size, PXE_SOCK_NONBLOCKING); + + if ( size > 0) { + /* something felt to socket */ + if (dhcp_parse(wait_data->data, size, wait_data->xid)) + return (PXE_AWAIT_COMPLETED); + } + + return (PXE_AWAIT_CONTINUE); + break; + + case PXE_AWAIT_FINISHTRY: + /* close socket if it is valid */ + if (wait_data->socket != -1) + pxe_close(wait_data->socket); + + break; + + case PXE_AWAIT_END: + default: + break; + } + + return (PXE_AWAIT_OK); +} + +/* pxe_dhcp_query() - sends DHCP query, using provided client id + * in: + * xid - client/transaction id, used to differ packets + * out: + * none + */ +void +pxe_dhcp_query(uint32_t xid) +{ + uint8_t dhcp_pack[PXE_MAX_DHCPPACK_SIZE]; + PXE_DHCP_WAIT_DATA wait_data; + + printf("pxe_dhcp_query(): getting parameters using DHCP.\n"); + + wait_data.data = dhcp_pack; + wait_data.socket = -1; + wait_data.size = PXE_MAX_DHCPPACK_SIZE; + wait_data.xid = xid; + + if (!pxe_await(dhcp_await, 3, 60000, &wait_data)) { + printf("pxe_dhcp_query(): failed to get parameters via DHCP\n"); + } +} +#else /* defined(PXE_BOOTP_USE_LIBSTAND) */ + +extern int pxe_sock; + +void +pxe_dhcp_query(uint32_t xid) +{ + + printf("pxe_dhcp_query(): starting libstand bootp()\n"); + bootp(pxe_sock, BOOTP_PXE); + + /* setting pxe_core variables */ + PXE_IPADDR addr; + + addr.ip = nameip.s_addr; + pxe_set_ip(PXE_IP_NAMESERVER, &addr); + + addr.ip = netmask; + pxe_set_ip(PXE_IP_NETMASK, &addr); + + addr.ip = rootip.s_addr; + pxe_set_ip(PXE_IP_ROOT, &addr); + pxe_set_ip(PXE_IP_WWW, &addr); + + /* "network route". direct connect for those addresses */ + pxe_ip_route_add(pxe_get_ip(PXE_IP_MY), netmask, NULL); + + addr.ip = gateip.s_addr; + pxe_set_ip(PXE_IP_GATEWAY, &addr); + + /* need update gateway information, cause it's already set to default */ + pxe_ip_route_default(&addr); +} + +#endif /* PXE_BOOTP_USE_LIBSTAND */ Index: user/sbruno/pxe_http/pxe_dhcp.h =================================================================== --- user/sbruno/pxe_http/pxe_dhcp.h (nonexistent) +++ user/sbruno/pxe_http/pxe_dhcp.h (revision 245442) @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_DHCP_H_INCLUDED +#define PXE_DHCP_H_INCLUDED + +/* Implements simple DHCP client, able to retrieve nameserver + * and gateway ip data from DHCP-server. + * Reference: RFC 2131 + */ + +#include + +/* define if want use bootp() instead of functions, provided by + * pxe_dhcp module + * NOTE: bootp() doesn't sets nameserver + */ +/* #define PXE_BOOTP_USE_LIBSTAND */ + + +/* DHCP request/reply packet header */ +typedef struct pxe_dhcp_hdr { + uint8_t op; /* request or reply */ + uint8_t htype; /* harsware type */ + uint8_t hlen; /* hardware address length */ + uint8_t hops; /* used by relay agents, zero for client */ + uint32_t xid; /* transaction id */ + uint16_t secs; /* time elapsed after renewal process */ + uint16_t flags; + uint32_t ciaddr; /* client ip, filled in BOUND, RENEW, + * or REBINDING */ + uint32_t yiaddr; /* client ip addr */ + uint32_t siaddr; /* next server ip */ + uint32_t giaddr; /* relay agent ip */ + uint8_t chaddr[16]; /* client hardware address */ + uint8_t sname[64]; /* optional server hostname */ + uint8_t file[128]; /* boot file name */ + uint32_t magic; /* DHCP magic cookie */ +} __packed PXE_DHCP_HDR; + +/* options structure */ +typedef struct pxe_dhcp_opt_hdr { + uint8_t option; /* option id */ + uint8_t len; /* size of data, + * followed after this member */ +} __packed PXE_DHCP_OPT_HDR; + +/* dhcp packet types */ +#define PXE_DHCP_REQUEST 0x01 +#define PXE_DHCP_REPLY 0x02 +/* maximal size of buffer for packet */ +#define PXE_MAX_DHCPPACK_SIZE 1024 +/* broadcast packet flag */ +#define PXE_DHCP_BROADCAST 0x8000 +/* magic */ +#ifdef VM_RFC1048 +/* it's defined in pxe.h */ + #define PXE_MAGIC_DHCP VM_RFC1048 +#else + #define PXE_MAGIC_DHCP 0x63825363 +#endif + +/* DHCP server port*/ +#define PXE_DHCP_SERVER_PORT 67 +/* local port to listen replies */ +#define PXE_DHCP_CLIENT_PORT 68 + +#define PXE_DHCPDISCOVER 0x01 +#define PXE_DHCPOFFER 0x02 +#define PXE_DHCPREQUEST 0x03 +#define PXE_DHCPACK 0x05 +#define PXE_DHCPINFORM 0x08 + +/* theese are unused in this DHCP client +#define PXE_DHCPDECLINE 0x04 +#define PXE_DHCPNAK 0x06 +#define PXE_DHCPRELEASE 0x07 +*/ + +/* DHCP options */ +#define PXE_DHCP_OPT_NETMASK 1 +#define PXE_DHCP_OPT_ROUTER 3 +#define PXE_DHCP_OPT_NAMESERVER 6 +#define PXE_DHCP_OPT_DOMAIN_NAME 15 +#define PXE_DHCP_OPT_ROOTPATH 17 +#define PXE_DHCP_OPT_BROADCAST_IP 28 +#define PXE_DHCP_OPT_REQUEST_IP 50 +#define PXE_DHCP_OPT_LEASE_TIME 51 +#define PXE_DHCP_OPT_TYPE 53 +#define PXE_DHCP_OPT_ID 54 +#define PXE_DHCP_OPT_RENEWAL_TIME 58 +#define PXE_DHCP_OPT_REBINDING_TIME 59 +#define PXE_DHCP_OPT_WWW_SERVER 72 +#define PXE_DHCP_OPT_END 255 + +/* used in await function */ +typedef struct pxe_dhcp_wait_data { + int socket; /* current socket to check replies */ + uint8_t *data; /* query packet data */ + uint16_t size; /* max size of packet */ + uint32_t xid; /* session id */ +} PXE_DHCP_WAIT_DATA; + +typedef struct pxe_dhcp_parse_result { + PXE_IPADDR netmask; + PXE_IPADDR bcast_addr; + PXE_IPADDR ns; + PXE_IPADDR gw; + PXE_IPADDR www; + char rootpath[256]; + uint8_t message_type; +} PXE_DHCP_PARSE_RESULT; + +/* sends DHCPINFORM packet and updates nameserver + * and gateway data + */ +void pxe_dhcp_query(uint32_t xid); + +/* prints out known DHCP options */ +void pxe_dhcp_parse_options(uint8_t *opts, uint16_t max_size, + PXE_DHCP_PARSE_RESULT *res); + +#endif Index: user/sbruno/pxe_http/pxe_dns.c =================================================================== --- user/sbruno/pxe_http/pxe_dns.c (nonexistent) +++ user/sbruno/pxe_http/pxe_dns.c (revision 245442) @@ -0,0 +1,589 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_await.h" +#include "pxe_core.h" +#include "pxe_dns.h" +#include "pxe_ip.h" +#include "pxe_sock.h" + +static PXE_DNS_WAIT_DATA static_wait_data; + +/* write_question_for()- writes labels for provided domain name + * in: + * question - where to write + * name - domain name + * out: + * NULL - if failed + * non NULL- ponits to the next byte after labeled name. + */ +char * +write_question_for(uint8_t *question, const char *name) +{ + size_t len = strlen(name); + + if (len > 255) /* oversize */ + return (NULL); + + size_t ind = len; + uint8_t symbol_count = 0; + uint8_t *res = question + len; + const char *np = name + len - 1; + question[len + 1] = 0; /* label end of question */ + + /* placing from the end, replacing dots with symbol counter */ + for ( ; ind != 0; --ind) { + + *res = *np; + + if ( *res == '.') { + + if (symbol_count == 0) { /* example..of.error */ + return (NULL); + } + + *res = symbol_count; + symbol_count = 0; + + } else { + ++symbol_count; + } + + --res; + --np; + } + + *res = symbol_count; /* length for first label */ + + /* +1 for first length, +1 for \0 */ + return (question + len + 2); +} + +/* create_dns_packet()- creates DNS request packet + * in: + * wd - pointer to wait data structure + * id - request id to distinguish requests + * out: + * 0 - failed + * >0 - size of created packet + */ +int +create_dns_packet(PXE_DNS_WAIT_DATA *wd, uint16_t id, uint16_t query_type) +{ + char *name = wd->name; + void *data = wd->data; + int max_size = wd->size; + + PXE_DNS_REQUEST_HDR *request = (PXE_DNS_REQUEST_HDR *)data; + pxe_memset(request, 0, sizeof(PXE_DNS_REQUEST_HDR)); + + uint8_t *question = + (uint8_t *)(data + sizeof(PXE_DNS_REQUEST_HDR)); + + /* header set with zeroes, so fill only needed values */ + request->id = htons(id); + request->flags = htons(PXE_DNS_DEFAULT_FLAGS); + request->qdcount = htons(1); + + question = write_question_for(question, name); + + if (question == NULL) /* failed to write question section */ + return (0); /* may be, name size is to big */ + + PXE_DNS_REQUEST_FOOT *foot = (PXE_DNS_REQUEST_FOOT *)question; + + /* finishing creating of packet */ + foot->qtype = htons(query_type); + foot->qclass = htons(PXE_DNS_CLASS_IN); + + question += sizeof(PXE_DNS_REQUEST_FOOT); + + /* return total size of packet */ + return (((void *)question) - data); +} + +/* skip_name() - gets name from answers + * in: + * org - pointer to packet data start + * off - offset to name or part of name to get + * to_place - where to place name. NULL, if not interesting for us + * out: + * bytes, read from offset (name definition length) + */ +int +skip_name(uint8_t *org, uint16_t off, uint8_t *to_place) +{ + uint8_t label[64]; + label[0] = 0; + + int res =0 ; + uint8_t *data = org + off; + + while (*data != 0) { + + if (*data < 64) { /* just a label */ + pxe_memcpy(data + 1, label, *data); + label[*data] = 0; + + if (to_place != 0) { + /* updating to_place, add dot, if there is + * part of name in buffer */ + if (to_place[0] != 0) + strcat((char *)to_place, "."); + + strcat((char *)to_place, (const char*)label); + } + + res += (1 + *data); + data += (1 + *data); + + } else {/* compression enabled, this is part of pointer */ + uint16_t off = (((*data) & 0x3f) << 8) + *(data + 1); + skip_name(org, off, to_place); + + res += 1; + break; + } + } + + res += 1; /* ending zero skip */ + return (res); +} + +/* parse_dns_reply() - parses reply from DNS server + * in: + * wd - pointer to waiting data structure + * out: + * 0 - parsing failed, or packet has no information about our domain + * 1 - success, wait_data->result contains ip + */ +int +parse_dns_reply(PXE_DNS_WAIT_DATA *wd) +{ + uint8_t *data = wd->data; + int size = wd->size; + char *name = wd->name; + uint16_t id = wd->id; + uint8_t *cname = wd->cname; + + cname[0] = 0; + + if (size < sizeof(PXE_DNS_REQUEST_HDR) + 8) { + /* too small packet to be with data */ +#ifdef PXE_DEBUG + printf("parse_dns_reply(): too small packet.\n"); +#endif + return (0); + } + + PXE_DNS_REQUEST_HDR *hdr = (PXE_DNS_REQUEST_HDR *)data; + uint8_t *answer = data + sizeof(PXE_DNS_REQUEST_HDR); + + if ( hdr->id != htons(id)) { /* wrong id */ +#ifdef PXE_DEBUG + printf("parse_dns_reply(): wrong id %d, expected %d.\n", + ntohs(hdr->id), id); +#endif + return (0); + } + + uint16_t flags = ntohs(hdr->flags); + + if ( (flags & 0xf800) != 0x8000) { /* QR != 1 */ +#ifdef PXE_DEBUG + printf("parse_dns_reply(): got request. Ignoring it.\n"); +#endif + return (0); + } + +#ifdef PXE_DEBUG + printf("parse_dns_reply(): query/answer/ns/additional = %d/%d/%d/%d\n", + ntohs(hdr->qdcount), ntohs(hdr->ancount), + ntohs(hdr->nscount), ntohs(hdr->arcount)); +#endif + /* getting server return code */ + int rcode = (flags & 0x000f); + + switch(rcode) { + case 0: /* good */ + break; + case 1: + printf("parse_dns_reply(): server said format error.\n"); + return (0); + break; + case 2: + printf("parse_dns_reply(): server failed.\n"); + return (0); + break; + case 3: + printf("parse_dns_reply(): name error, domain not exists?\n"); + return (0); + break; + case 4: + printf("parse_dns_reply(): operation not implemented.\n"); + return (0); + break; + case 5: + printf("parse_dns_reply(): access refused.\n"); + return (0); + break; + default: + printf("parse_dns_reply(): unknown rcode = %d.\n", rcode); + return (0); + break; + } + + /* server reported success */ + + if (hdr->ancount == 0) { /* there is no answers */ + printf("parse_dns_reply(): there are no answers in DNS reply.\n"); + return (0); + } + + uint8_t aname[256]; /* storage for domain names in answers */ + + switch (ntohs(hdr->qdcount)) { + case 0: /* best case, nothing must be skipped to get answer data */ + break; + case 1: + + aname[0] = 0; + answer += skip_name(data, answer - data, aname); +#ifdef PXE_DEBUG + printf("question: %s\n", aname); +#endif + /* answer points qclass/qtypr, skipping it */ + answer += sizeof(PXE_DNS_REQUEST_FOOT); + break; + + default: /* error */ + printf("parse_dns_reply(): me sent only one query, " + "but server says %d.\n", ntohs(hdr->qdcount)); + return (0); + } + + + /* parsing answers, authorative section and additional section, + * hoping to find A resource record + */ + uint16_t index = ntohs(hdr->ancount) + ntohs(hdr->nscount) + + ntohs(hdr->arcount); + + while (index) { + + aname[0] = 0; + answer += skip_name(data, answer - data, aname); + +#ifdef PXE_DEBUG + printf("answer: %s", aname); +#endif + PXE_DNS_REQUEST_FOOT *ans_foot = + (PXE_DNS_REQUEST_FOOT *)answer; + + if (ntohs(ans_foot->qclass) != PXE_DNS_CLASS_IN) { + printf("parse_dns_reply(): IN expected, got 0x%x.\n", + ntohs(ans_foot->qclass)); + + return (0); + } + + answer += sizeof(PXE_DNS_REQUEST_FOOT); + + PXE_DNS_REQUEST_FOOT2 *ans_foot2 = + (PXE_DNS_REQUEST_FOOT2 *)answer; + + answer += sizeof(PXE_DNS_REQUEST_FOOT2); + + uint16_t qtype = ntohs(ans_foot->qtype); + uint16_t rdlength = ntohs(ans_foot2->rdlength); + + if (qtype == PXE_DNS_QUERY_A) { + /* successfully got A record */ + +/* A for our address */ if ( (!strcmp(aname, name)) || +/* A for our CNAME */ ((cname[0]) && (!strcmp(aname, cname))) ) + { + /* sanity check */ + if (rdlength != 4) { + /* wrong length of ip4 adrress length*/ + return (0); + } + + /* answer points to rdata = ip4 */ + + wd->result.octet[0] = answer[0]; + wd->result.octet[1] = answer[1]; + wd->result.octet[2] = answer[2]; + wd->result.octet[3] = answer[3]; +#ifdef PXE_DEBUG + printf(" = %s\n", inet_ntoa(wd->result.ip)); +#endif + return (1); + } + +#ifdef PXE_DEBUG + printf("parse_dns_reply(): A resource record '%s' " + "is strange. Ignoring it.\n", aname); +#endif + } + + if (qtype == PXE_DNS_QUERY_CNAME) { + + cname[0] = 0; + skip_name(data, answer - data, cname); +#ifdef PXE_DEBUG + printf(" is alias to %s\n", (char *)cname); +#endif + + } else { + printf("parse_dns_reply(): A or CNAME expected, " + "but got 0x%x, rdlength: %d.\n", qtype, rdlength); + } + + answer += rdlength; + --index; + } + + /* have not found anything good */ + return (0); +} + +/* converts provided string representation of of address to uint32_t + * in: + * str - string to convert + * out: + * 0 - failed + * not 0 - ip4 addr + */ +uint32_t +pxe_convert_ipstr(char* str) +{ + PXE_IPADDR ip; + ip.ip = 0; + + int octet_index = 0; + int accum = 0; + int ch_index = 0; + + for ( ; ch_index < strlen(str); ++ch_index) { + + if (str[ch_index] == '.') { + ip.octet[octet_index] = accum; + accum = 0; + ++octet_index; + + if (octet_index == 4) + break; + + continue; + } + + if (!isdigit(str[ch_index])) + return (0); + + accum *= 10; + accum += (str[ch_index] - 0x30); + } + + if (octet_index < 4) + ip.octet[octet_index] = accum; + + return ip.ip; +} + +/* dns_request() - creates and sends request + * in: + * wait_data - DNS waiting data + * out: + * 0 - failed + * 1 - success + */ +int +dns_request(PXE_DNS_WAIT_DATA *wait_data) +{ + int socket = pxe_socket(); + + if (socket == -1) { + printf("dns_request(): failed to create socket.\n"); + return (0); + } + + uint16_t size = create_dns_packet(wait_data, wait_data->id, + PXE_DNS_QUERY_A); + + if (size == 0) { + printf("dns_request(): failed to create request.\n"); + pxe_close(socket); + return (0); + } + + if (size != pxe_sendto(socket, pxe_get_ip(PXE_IP_NAMESERVER), 53, + wait_data->data, size)) + { + printf("dns_request(): failed to send DNS request.\n"); + pxe_close(socket); + return (0); + } + + wait_data->socket = socket; + + return (1); +} + +/* dns_await() - await callback function for DNS requests/replies + * in: + * function - await function + * try_number - current number of try + * timeout - current timeout from start of try + * data - pointer to PXE_DNS_WAIT_DATA + * out: + * PXE_AWAIT_ constants + */ +int +dns_await(uint8_t function, uint16_t try_number, uint32_t timeout, void *data) +{ + PXE_DNS_WAIT_DATA *wait_data = (PXE_DNS_WAIT_DATA *)data; + int size = -1; + + switch(function) { + + case PXE_AWAIT_STARTTRY: + if (!dns_request(wait_data)) { + return (PXE_AWAIT_NEXTTRY); + } + break; + + case PXE_AWAIT_FINISHTRY: + if (wait_data->socket != -1) + pxe_close(wait_data->socket); + + wait_data->id += 1; + break; + + case PXE_AWAIT_NEWPACKETS: + size = pxe_recv(wait_data->socket, wait_data->data, + wait_data->size, PXE_SOCK_NONBLOCKING); + + if (size > 0) { +#ifdef PXE_DEBUG + printf("dns_await(): Received DNS reply (%d bytes).\n", + size); +#endif + parse_dns_reply(wait_data); + + if (wait_data->result.ip != 0) { + return (PXE_AWAIT_COMPLETED); + } + + if (wait_data->cname[0] != 0) { + /* failed to get A, but found CNAME, + * need to send other request + * with CNAME as name to resolve + */ + strcpy(wait_data->name, wait_data->cname); + + size = create_dns_packet(wait_data, + wait_data->id, + PXE_DNS_QUERY_A); + + if (size == 0) { + printf("dns_await(): failed to create request.\n"); + return (PXE_AWAIT_NEXTTRY); /* next try */ + } + + if (size != pxe_send(wait_data->socket, + wait_data->data, size)) + { + printf("dns_await(): failed to send DNS request.\n"); + return (PXE_AWAIT_NEXTTRY); + } + } + + } + return (PXE_AWAIT_CONTINUE); + break; + + case PXE_AWAIT_END: + default: + break; + } + + return (PXE_AWAIT_OK); +} + +/* pxe_gethostbyname() - returns ip4 address by domain name + * in: + * name - domain name to resolve + * out: + * NULL - if failed + * ip addr - if success + */ +const PXE_IPADDR * +pxe_gethostbyname(char *name) +{ + /* sanity check */ + if (name == NULL) + return (0); + + uint32_t res = pxe_convert_ipstr(name); + + if (res != 0) { + static_wait_data.result.ip = res; + return (&static_wait_data.result); + } + + /* 512 bytes is limit for packet, sent via UDP */ + uint8_t dns_pack[PXE_DNS_MAX_PACKET_SIZE]; + uint8_t cname[256]; + char tname[256]; + + size_t len = strlen(name); + + if (len < 256) + strcpy(tname, name); + else { + strncpy(name, tname, 255); + tname[255] = 0; + } + + pxe_memset(dns_pack, 0, sizeof(dns_pack)); + + static_wait_data.socket = -1; + static_wait_data.id = 1; + static_wait_data.data = dns_pack; + static_wait_data.cname = cname; + static_wait_data.name = tname; + static_wait_data.size = PXE_DNS_MAX_PACKET_SIZE; + static_wait_data.result.ip = 0; + + if (!pxe_await(dns_await, 4, 20000, &static_wait_data)) + return (NULL); + + return (&static_wait_data.result); +} Index: user/sbruno/pxe_http/pxe_dns.h =================================================================== --- user/sbruno/pxe_http/pxe_dns.h (nonexistent) +++ user/sbruno/pxe_http/pxe_dns.h (revision 245442) @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_DNS_H_INCLUDED +#define PXE_DNS_H_INCLUDED + +/* Implements DNS-client for getting A and CNAME records + * Reference: RFC 1035 + */ + +#include + +/* max seconds to wait DNS reply in milliseconds */ +#define PXE_MAX_DNS_TIMEOUT 10000 +/* how many times to try, if there is no reply */ +#define PXE_MAX_DNS_TRYS 3 +/* query flags, set only RecursionDesired bit */ +#define PXE_DNS_DEFAULT_FLAGS 0x0100 +/* query A and CNAME records */ +#define PXE_DNS_QUERY_A 0x0001 +#define PXE_DNS_QUERY_CNAME 0x0005 +/* query class */ +#define PXE_DNS_CLASS_IN 0x0001 +/* maximum UDP packet size */ +#define PXE_DNS_MAX_PACKET_SIZE 512 + +/* returns ip address by name, or 0 if failed */ +const PXE_IPADDR *pxe_gethostbyname(char *name); + +/* converts string value of ip to uint32_t value */ +uint32_t pxe_convert_ipstr(char *str); + +typedef struct pxe_dns_request_hdr { + uint16_t id; /* query identifier */ + uint16_t flags; + + + uint16_t qdcount; /* number of entries in the question section */ + uint16_t ancount; /* number of RRs in the answer section */ + uint16_t nscount; /* name server resource records in the + * authority records section. + */ + uint16_t arcount; /* number of resource records in the additional + * records section. + */ +} __packed PXE_DNS_REQUEST_HDR; + +/* flags are (copied from RFC 1035): + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * QR - 0 for query, 1 for reply + * OPCODE - kind of query + * 0 - a standard query (QUERY) + * 1 - an inverse query (IQUERY) + * 2 - a server status request (STATUS) + * AA - set if authorative + * TC - set if message truncated + * RD - set if recursion desired + * RA - set if recursion available + * Z - reserved, must be zeroed + * RCODE - return code: + * 0 - no error + * 1 - format error + * 2 - server failed + * 3 - name error + * 4 - not implemented + * 5 - refused + */ + +/* RCODE values */ +#define PXE_RCODE_NOERROR 0x0 +#define PXE_RCODE_FORMAT_ERROR 0x1 +#define PXE_RCODE_SERVER_FAILED 0x2 +#define PXE_RCODE_NAME_ERROR 0x3 +#define PXE_RCODE_NOT_IMPLEMENTED 0x4 +#define PXE_RCODE_REFUSED 0x5 + +typedef struct pxe_dns_request_foot { + uint16_t qtype; /* type of query, e.g. A */ + uint16_t qclass; /* class of query, e.g. IN */ +} __packed PXE_DNS_REQUEST_FOOT; + +typedef struct pxe_dns_request_foot2 { + uint32_t ttl; /* seconds answer will be valid to cache */ + uint16_t rdlength; /* length of data, followed by this struct */ +} __packed PXE_DNS_REQUEST_FOOT2; + +typedef struct pxe_dns_wait_data { + int socket; /* socket, to send/recv data */ + uint16_t id; /* id, used to differ packets */ + uint8_t *data; /* pointer to buffer */ + uint16_t size; /* size of buffer */ + uint8_t *cname; /* not NULL when resolved to CNAME */ + char *name; /* name to resolve */ + PXE_IPADDR result; /* result of resolving */ +} PXE_DNS_WAIT_DATA; +#endif Index: user/sbruno/pxe_http/pxe_filter.c =================================================================== --- user/sbruno/pxe_http/pxe_filter.c (nonexistent) +++ user/sbruno/pxe_http/pxe_filter.c (revision 245442) @@ -0,0 +1,438 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_ip.h" +#include "pxe_filter.h" + +/* table with all filters */ +static PXE_FILTER_ENTRY filters_table[MAX_PXE_FILTERS]; +static int all_filters = 0; /* used count of filters */ +static PXE_FILTER_ENTRY *filters_head = NULL; /* head of filters list */ +static PXE_FILTER_ENTRY *free_head = NULL; /* head of free filters list */ + +/* pxe_filter_init() - init of filter module, filter lists + * in/out: + * none + */ +void +pxe_filter_init() +{ + + if (all_filters) /* already was and inited and is used */ + return; + + printf("pxe_filter_init(): initing socket ip packet filters.\n"); + + pxe_memset(filters_table, 0, sizeof(filters_table)); + + /* init 2 linked list */ + int index = 0; + + for ( ; index < MAX_PXE_FILTERS; ++index) { + + filters_table[index - 1].next = &filters_table[index]; + filters_table[index].prev = &filters_table[index - 1]; + } + + free_head = filters_table; + filters_head = NULL; +} + +/* filter_alloc() - allocates filter entry from free filters list + * in: + * none + * out: + * NULL - if failed + * not NULL- pointer to filter entry if success + */ +PXE_FILTER_ENTRY * +filter_alloc() +{ + PXE_FILTER_ENTRY *res = NULL; + +#ifdef PXE_DEBUG_HELL + printf("filter_alloc(): head = 0x%x, filters = %d.\n", + free_head, all_filters); +#endif + + if (free_head != NULL) { + + res = free_head; + + free_head = free_head->next; + free_head->prev = NULL; + ++all_filters; + } + +#ifdef PXE_DEBUG_HELL + printf("filter_alloc(): entry = 0x%x, head = 0x%x, filters = %d.\n", + res, free_head, all_filters); +#endif + return (res); +} + +/* filter_free() - releases filter entry + * in: + * entry - filter entry to release + * out: + * none + */ +void +filter_free(PXE_FILTER_ENTRY *entry) +{ + + entry->next = free_head; + entry->prev = NULL; + + if (free_head != NULL) + free_head->prev = entry; + + free_head = entry; + +#ifdef PXE_DEBUG_HELL + printf("filter_free(): entry = 0x%x, head = 0x%x, filters = %d.\n", + entry, free_head, all_filters); +#endif + + --all_filters; +} + +/* pxe_filter_add() - installs new filter + * in: + * src_ip - source IP address + * src_port- source port + * dst_ip - destination IP address + * dst_port- destination port + * socket - pointer to socket + * proto - IP stack protocol (e.g. UDP) + * out: + * NULL - if failed + * not NULL- pointer to new installed entry + */ +PXE_FILTER_ENTRY * +pxe_filter_add(const PXE_IPADDR *src, uint16_t src_port, const PXE_IPADDR *dst, + uint16_t dst_port, void *socket, uint8_t proto) +{ + + if (socket == NULL) { +#ifdef PXE_DEBUG + printf("pxe_filter_add(): NULL socket.\n"); +#endif + return (NULL); + } + + if (free_head == NULL) { +#ifdef PXE_DEBUG + printf("pxe_filter_add(): filter table is full (used = %d).\n", + all_filters); +#endif + return (NULL); /* there is no space for filters */ + } + + PXE_FILTER_ENTRY *new_filter = filter_alloc(); + + if (new_filter == NULL) { + printf("pxe_filter_add(): cannot alloc filter entry.\n"); + return (NULL); + } + + /* fillling data */ + new_filter->src.ip = (src != NULL) ? src->ip : 0; + new_filter->dst.ip = dst->ip; + new_filter->src_port = src_port; + new_filter->dst_port = dst_port; + + /* default mask allows pckets specified source and port + * to specified ip and port + */ + new_filter->src_mask = 0xffffffff; + new_filter->dst_mask = 0xffffffff; + new_filter->src_port_mask = 0xffff; + new_filter->dst_port_mask = 0xffff; + + new_filter->socket = socket; + new_filter->protocol = proto; + + /* updating list, may be rewrite all using some default list + * implementations? + * list is growing LIFO: last added filter become first + */ + new_filter->prev = NULL; + + if (filters_head != NULL) { + + new_filter->next = filters_head; + filters_head->prev = new_filter; + + } else /* means, adding first filter */ + new_filter->next = NULL; + + filters_head = new_filter; + + return (new_filter); +} + +/* pxe_filter_mask() - fills filter masks + * in: + * filter - filter, for which masks are changed + * src_ip_mask - source IP address mask + * src_port_mask - source port mask + * dst_ip_mask - destination IP address mask + * dst_port_mask - destination port mask + * out: + * 0 - failed + * 1 - success + */ +int +pxe_filter_mask(PXE_FILTER_ENTRY *filter, uint32_t src_ip_mask, + uint16_t src_port_mask, uint32_t dst_ip_mask, + uint16_t dst_port_mask) +{ + + if (filter == NULL) { /* sanity check */ +#ifdef PXE_DEBUG + printf("pxe_filter_mask(): NULL filter.\n"); +#endif + return (0); + } + + + filter->src_mask = src_ip_mask; + filter->dst_mask = dst_ip_mask; + filter->src_port_mask = src_port_mask; + filter->dst_port_mask = dst_port_mask; + + return (1); +} + +#ifdef PXE_MORE +/* pxe_filter_before() - adds new filter before provided + * in: + * filter - pointer to filter to add before + * def - pointer to definition of new filter + * out: + * NULL - if failed + * not NULL- pointer to newly added filter, if success + */ +PXE_FILTER_ENTRY * +pxe_filter_before(PXE_FILTER_ENTRY *filter, const PXE_FILTER_ENTRY* def) +{ + + if ((def == NULL) ) { /* sanity check */ +#ifdef PXE_DEBUG + printf("pxe_filter_before(): invalid filter.\n"); +#endif + return (NULL); + } + + PXE_FILTER_ENTRY *res = NULL; + + if (filter == NULL) { /* handle it as usual filter_add with masking */ + + res = pxe_filter_add( &def->src, def->src_port, + &def->dst, def->dst_port, + def->socket, def->protocol ); + + if (res == NULL) + return (NULL); + + if (!pxe_filter_mask(res, def->src_mask, def->src_port_mask, + def->dst_mask, def->dst_port_mask)) + { + pxe_filter_remove(res); + + return (NULL); + } + + return(res); + } + + /* allocating new filter entry */ + res = filter_alloc(); + + if (res == NULL) + return (NULL); + + /* copy needded data*/ + pxe_memcpy(def, res, sizeof(PXE_FILTER_ENTRY)); + + if (filter == filters_head) { /* special case, must change head */ + + filter->prev = res; + res->next = filters_head; + res->prev = NULL; + filters_head = res; + + } else { /* adding to list */ + + res->prev = filter->prev; + res->next = filter; + + if (res->prev) { /* sanity check, must be always + * not NULL anyway (if not head) + */ + res->prev->next = res; + } + } + + return (res); +} +#endif /* PXE_MORE */ + +/* pxe_filter_remove() -removes filter from filter_table + * in: + * filter - filter to remove + * out: + * 0 - failed + * 1 - success + */ +int +pxe_filter_remove(PXE_FILTER_ENTRY *filter) +{ +#ifdef PXE_DEBUG + if (filter == NULL) { + printf("pxe_filter_remove(): NULL filter.\n"); + return (0); + } + + printf("pxe_filter_remove(): removing filter 0x%x.\n", filter); + +#endif + + if (filter != filters_head) { /* non head filter */ + + PXE_FILTER_ENTRY *prev = filter->prev; + PXE_FILTER_ENTRY *next = filter->next; + + if (prev) /* it must be always non NULL*/ + prev->next = next; + + if (next) /* may be NULL for tail */ + next->prev = prev; + + } else { /* removing head filter */ + + filters_head = filter->next; + + if (filters_head) + filters_head->prev = NULL; + } + + filter_free(filter); + + return (1); +} + +/* pxe_filter_check() - returns pointer to socket, if parameters matches filter + * in: + * src_ip - source IP address + * src_port- source port + * dst_ip - destination IP address + * dst_port- destination port + * proto - IP stack protocol + * out: + * NULL - if no filter matches this parameters + * not NULL- pointer to socket structure + */ +void * +pxe_filter_check(const PXE_IPADDR *src, uint16_t src_port, + const PXE_IPADDR *dst, uint16_t dst_port, uint8_t proto) +{ + int filter_index = 0; + PXE_FILTER_ENTRY *entry = filters_head; + PXE_FILTER_ENTRY *filter = NULL; + + while (entry != NULL) { + + filter = entry; + entry = entry->next; + + /* checking conditions */ + if (filter->protocol != proto) + continue; + + if ( (filter->src.ip & filter->src_mask) != + (src->ip & filter->src_mask) ) + continue; + + if ( (filter->src_port & filter->src_port_mask) != + (src_port & filter->src_port_mask) ) + continue; + + if ( (filter->dst.ip & filter->dst_mask) != + (dst->ip & filter->dst_mask) ) + continue; + + if ( (filter->dst_port & filter->dst_port_mask) != + (dst_port & filter->dst_port_mask) ) + continue; + + /* filter triggered */ + + /* sanity check */ + if (filter->socket == NULL) + continue; + + return filter->socket; + } + + return (NULL); +} + +#ifdef PXE_MORE +/* pxe_filter_stats() - shows active filter stats + * in/out: + * none + */ +void +pxe_filter_stats() +{ + PXE_FILTER_ENTRY *entry = filters_head; + PXE_IPADDR src; + PXE_IPADDR dst; + + printf("pxe_filter_stats(): %d/%d filters\n", + all_filters, MAX_PXE_FILTERS); + + while (entry != NULL) { + + printf("\t0x%x: %s/%x %u/%x ->", + entry->protocol, + inet_ntoa(entry->src.ip), ntohl(entry->src_mask), + entry->src_port, ntohs(entry->src_port_mask)); + + printf("%s/%x %u/%x\tsocket: 0x%x\n", + inet_ntoa(entry->dst.ip), ntohl(entry->dst_mask), + entry->dst_port, ntohs(entry->dst_port_mask), + entry->socket); + + entry = entry->next; + } +} +#endif /* PXE_MORE */ Index: user/sbruno/pxe_http/pxe_filter.h =================================================================== --- user/sbruno/pxe_http/pxe_filter.h (nonexistent) +++ user/sbruno/pxe_http/pxe_filter.h (revision 245442) @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_FILTER_H_INCLUDED +#define PXE_FILTER_H_INCLUDED + +/* + * Packet filters for sockets. + */ +#include + +#include "pxe_ip.h" + +#define PXE_FILTER_ACTIVE 0x01 /* filter is active (entry is used) */ +#define PXE_FILTER_PARENT 0x02 /* forks subfilters and creates sockets + * for them. */ +#define PXE_FILTER_CONSUME 0x04 /* may send recved data to buffer */ + +#define PXE_FILTER_LISTEN (PXE_FILTER_PARENT | PXE_FILTER_ACTIVE) +#define PXE_FILTER_ROOT 0x80 + +typedef struct pxe_filter_entry { + + uint16_t src_port; /* source port */ + uint16_t src_port_mask; /* source port mask */ + uint16_t dst_port; /* destination port */ + uint16_t dst_port_mask; /* destination port mask */ + + PXE_IPADDR src; /* source IP address */ + uint32_t src_mask; /* source IP address mask */ + PXE_IPADDR dst; /* destination IP address */ + uint32_t dst_mask; /* destination IP address mask */ + + void *socket; /* socket, which receives data, + * passed through this filter + * NULL - if unknown. + */ + uint8_t protocol; /* IP based protocol */ + + struct pxe_filter_entry *next; /* next filter */ + struct pxe_filter_entry *prev; /* previous filter */ + +} PXE_FILTER_ENTRY; + +/* number of filter is must be at least equal to number of sockets */ +#define MAX_PXE_FILTERS 8 + +/* init filter module */ +void pxe_filter_init(); + +/* show active filters */ +void pxe_filter_stats(); + +/* installs new filter*/ +PXE_FILTER_ENTRY *pxe_filter_add(const PXE_IPADDR *src_ip, uint16_t src_port, + const PXE_IPADDR *dst_ip, uint16_t dst_port, void *socket, + uint8_t proto); + +/* install filter earlier provided filter */ +PXE_FILTER_ENTRY *pxe_filter_before(PXE_FILTER_ENTRY *filter, + const PXE_FILTER_ENTRY *def); + +/* fills filter masks */ +int pxe_filter_mask(PXE_FILTER_ENTRY *filter, uint32_t src_ip_mask, + uint16_t src_port_mask, uint32_t dst_ip_mask, uint16_t dst_port_mask); + +/* removes filter from filter_table*/ +int pxe_filter_remove(PXE_FILTER_ENTRY *filter); + +/* returns socket, if found trigerred filter */ +void *pxe_filter_check(const PXE_IPADDR *src_ip, uint16_t src_port, + const PXE_IPADDR *dst_ip, uint16_t dst_port, uint8_t proto); + +#endif Index: user/sbruno/pxe_http/pxe_http.c =================================================================== --- user/sbruno/pxe_http/pxe_http.c (nonexistent) +++ user/sbruno/pxe_http/pxe_http.c (revision 245442) @@ -0,0 +1,876 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_await.h" +#include "pxe_core.h" +#include "pxe_dns.h" +#include "pxe_http.h" +#include "pxe_ip.h" +#include "pxe_tcp.h" + +/* #ifndef FNAME_SIZE +#define FNAME_SIZE 128 +#endif +*/ +/* for testing purposes, used by pxe_fetch() */ +#ifdef PXE_MORE +static char http_data[PXE_MAX_HTTP_HDRLEN]; +#endif + +/* extern char rootpath[FNAME_SIZE]; */ + +/* parse_size_t() - converts zero ended string to size_t value + * in: + * str - string to parse + * result - where store result + * out: + * NULL - failed, ignore result value + * not NULL- pointer to next character after last parsed + */ +char * +parse_size_t(char *str, size_t *result) +{ + char *p = str; + + while ( (*p != '\0') && (!isdigit(*p)) ) { + ++p; + } + + if (!isdigit(*p)) /* nothing to parse */ + return (NULL); + + size_t accum = 0; + + while ( (*p) && (isdigit(*p))) { + accum *= 10; + accum += (*p - '0'); + ++p; + } + + *result = accum; + + return (p); +} + +/* http_reply_parse() - parses http reply, gets status code and length + * in: + * data - pointer to reply data + * count - max bytes to process [now ignored] + * parse_data - where to store result of parsing + * out: + * 0 - failed, ignore parse_data + * 1 - parsed successfully + */ +int +http_reply_parse(char *data, int count, PXE_HTTP_PARSE_DATA *parse_data) +{ + if (strncmp(data, "HTTP/1.1", 8) != 0) /* wrong header */ + return (0); + + size_t result = 0; + + char *found = parse_size_t(data + 8, &result); + parse_data->code = (uint16_t) result; + + if (found == NULL) + return (0); /* failed to parse response code */ + + parse_data->isKeepAlive = 1; +#ifdef PXE_HTTP_AUTO_KEEPALIVE + found = strstr(data, "Connection: close"); + + if (found != NULL) + parse_data->isKeepAlive = 0; +#endif + found = strstr(data, "Content-Length:"); + + parse_data->size = PXE_HTTP_SIZE_UNKNOWN; + + if (found != NULL) /* parsing message body size */ + found = parse_size_t(found + strlen("Content-Length:"), + &parse_data->size); + + return (1); +} + +/* http_get_header() - gets from socket data related to http header + * in: + * socket - socket descriptor + * data - pointer to working buffer + * maxsize - buffer size + * found_result - if not NULL, there stored pointer to end of header + * count_result - if not NULL, received count stored + * out: + * -1 - failed + * >=0 - success + */ +int +http_get_header(int socket, char *data, size_t maxsize, + char **found_result, size_t *count_result) +{ + int result = -1; + size_t count = 0; + char *found = NULL; + char ch = '\0'; + + while (count < maxsize - 1) { + result = pxe_recv(socket, &data[count], maxsize - 1 - count, + PXE_SOCK_BLOCKING); + + if (result == -1) { /* failed to recv */ +#ifdef PXE_HTTP_DEBUG_HELL + printf("http_get_header(): pxe_recv() failed\n"); +#endif + break; + } + + if (result == 0) /* nothing received yet */ + continue; + + /* make string ended with '\0' */ + ch = data[count + result]; + data[count + result] = '\0'; + + /* searching end of reply */ + found = strstr(&data[count], "\r\n\r\n"); + + /* restore char replaced by zero */ + data[count + result] = ch; + + count += result; + +#ifdef PXE_HTTP_DEBUG_HELL + if (found != NULL) + printf("%s", data); +#endif + + if (found != NULL) + break; + } + + if (found_result) + *found_result = found; + + if (count_result) + *count_result = count; + + return (result); +} + +#ifdef PXE_HTTPFS_CACHING +/* http_get_header2() - gets from socket data related to http header + * byte by byte. + * in: + * socket - socket descriptor + * data - pointer to working buffer + * maxsize - buffer size + * found_result - if not NULL, there stored pointer to end of header + * count_result - if not NULL, received count stored + * out: + * -1 - failed + * >=0 - success + */ +int +http_get_header2(int socket, char *data, size_t maxsize, + char **found_result, size_t *count_result) +{ + int result = -1; + size_t count = 0; + char *found = NULL; + char ch = '\0'; + + while (count < maxsize - 1) { + result = pxe_recv(socket, &data[count], 1, PXE_SOCK_BLOCKING); + + if (result == -1) { /* failed to recv */ +#ifdef PXE_HTTP_DEBUG_HELL + printf("http_get_header2(): pxe_recv() failed\n"); +#endif + break; + } + + if (result == 0) /* nothing received yet */ + continue; + + count += 1; + + if (count < 4) /* wait at least 4 bytes */ + continue; + + /* make string ended with '\0' */ + ch = data[count]; + data[count] = '\0'; + + /* searching end of reply */ + found = strstr(&data[count - 4], "\r\n\r\n"); + +#ifdef PXE_HTTP_DEBUG_HELL + if (found != NULL) + printf("%s", data); +#endif + /* restore char replaced by zero */ + data[count] = ch; + + if (found != NULL) + break; + } + + if (found_result) + *found_result = found; + + if (count_result) + *count_result = count; + + return (result); +} + +/* http_await() - await callback function for filling buffer + * in: + * function - await function + * try_number - current number of try + * timeout - current timeout from start of try + * data - pointer to PXE_DNS_WAIT_DATA + * out: + * PXE_AWAIT_ constants + */ +int +http_await(uint8_t function, uint16_t try_number, uint32_t timeout, void *data) +{ + PXE_HTTP_WAIT_DATA *wait_data = (PXE_HTTP_WAIT_DATA *)data; + uint16_t space = 0; + + switch(function) { + + case PXE_AWAIT_NEWPACKETS: + space = pxe_buffer_space(wait_data->buf); + + /* check, have we got enough? */ + if (wait_data->start_size - space >= + wait_data->wait_size) + return (PXE_AWAIT_COMPLETED); + + /* check, is socket still working? */ + if (pxe_sock_state(wait_data->socket) != + PXE_SOCKET_ESTABLISHED) + return (PXE_AWAIT_BREAK); + + return (PXE_AWAIT_CONTINUE); + default: + break; + } + + return (PXE_AWAIT_OK); +} + +#endif /* PXE_HTTPFS_CACHING */ + +#ifdef PXE_MORE +/* pxe_fetch() - testing function, if size = from = 0, retrieve full file, + * otherwise partial + * in: + * server_name - web server name + * filename - path to file to fetch + * from - offset in file (if supported by server) + * size - size of part to receive + * out: + * 0 - failed + * 1 - success + */ +int +pxe_fetch(char *server_name, char *filename, off_t from, size_t size) +{ + const PXE_IPADDR *server = NULL; + + printf("pxe_fetch(): fetching http://%s:80/%s (%llu+%lu)\n", + server_name, filename, from, size); + + server = pxe_gethostbyname(server_name); + + if (server == NULL) { + printf("pxe_fetch(): cannot resolve server name.\n"); + return (0); + } else + printf("pxe_fetch(): resolved as: %s\n", inet_ntoa(server->ip)); + + int socket = pxe_socket(); + + int result = pxe_connect(socket, server, 80, PXE_TCP_PROTOCOL); + + if (result == -1) { + printf("pxe_fetch(): failed to connect.\n"); + pxe_close(socket); + return (0); + } + + if ( (from == 0) && (size == 0) ) + snprintf(http_data, PXE_MAX_HTTP_HDRLEN, + "GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n" + "User-Agent: pxe_http/0\r\n\r\n", filename, server_name); + else + snprintf(http_data, PXE_MAX_HTTP_HDRLEN, + "GET /%s HTTP/1.1\r\nHost: %s\r\nRange: bytes=%llu-%llu\r\n" + "Connection: Close\r\nUser-Agent: pxe_http/0\r\n\r\n", + filename, server_name, from, from + size - 1); + + size_t len = strlen(http_data); + + if (len != pxe_send(socket, http_data, len)) { + printf("pxe_fetch(): failed to send request.\n"); + pxe_close(socket); + return (0); + } + + if (pxe_flush(socket) == -1) { + printf("pxe_fetch(): failed to push request.\n"); + pxe_close(socket); + return (0); + } + + size_t count = 0; + char *found = NULL; + + /* retrieve header */ + result = http_get_header(socket, http_data, PXE_MAX_HTTP_HDRLEN - 1, + &found, &count); + + if (found == NULL) { /* haven't found end of header */ + pxe_close(socket); + return (0); + } + + /* parse header */ + PXE_HTTP_PARSE_DATA parse_data; + pxe_memset(&parse_data, 0, sizeof(PXE_HTTP_PARSE_DATA)); + + if (!http_reply_parse(http_data, count, &parse_data)) { + pxe_close(socket); + return (0); + } + + printf("pxe_fetch(): response %u, length = %lu\n", + parse_data.code, parse_data.size); + + delay(2000000); + + if ( (parse_data.code < 200) || + (parse_data.code >= 300) ) + { + printf("pxe_fetch(): failed to fetch.\n"); + pxe_close(socket); + return (0); + } + + http_data[count] = '\0'; + + /* update counter, substruct header size */ + count -= (found - http_data) + 4; + + /* process body data */ + printf("%s", found + 4); + + while (1) { + result = pxe_recv(socket, http_data, PXE_MAX_HTTP_HDRLEN - 1, + PXE_SOCK_BLOCKING); + + if (result == -1) + break; + + if (result == 0) + continue; + + http_data[result] = '\0'; + + printf("%s", http_data); + + count += result; + } + + pxe_close(socket); + printf("\npxe_fetch(): %lu of %lu byte(s) received.\n", + count, parse_data.size); + + return (1); +} +#endif + +/* pxe_get() - gets portion of file + * in: + * hh - descriptor of file to read data from + * size - size of part to read starting at from hh->offset + * out: + * -1 - failed + * >=0 - actual bytes read + */ +int +pxe_get(PXE_HTTP_HANDLE *hh, size_t size, void *buffer) +{ + + size_t size_to_get = (size > 0) ? size : hh->size; + + if (hh->isKeepAlive == 0) { +#ifdef PXE_HTTP_AUTO_KEEPALIVE + /* if connection is not keep-alived, then try pxe_get_close() */ + return pxe_get_close(hh, size_to_get, buffer); +#endif + printf("pxe_get(): auto keep-alive feature not enabled " + "during compile time. Connection is closed.\n"); + + return (-1); + } + + +#ifdef PXE_HTTP_DEBUG_HELL + printf("pxe_get(): %s:%s:%llu+%lu(%lu:%lu) to 0x%x\n", + inet_ntoa(hh->addr.ip), hh->filename, hh->offset, + size_to_get, size, hh->size, hh->buf); +#endif + + if (hh->socket == -1) { + printf("pxe_get(): invalid socket.\n"); + return (-1); + } + + if (pxe_sock_state(hh->socket) != PXE_SOCKET_ESTABLISHED) { + /* means connection was closed, due e.g. for Apache + * - MaxKeepAliveRequests exceeds for that connection + * - Waited between read attempts more than KeepAliveTimeout + * or + * some other problem + * need to reestablish connection + */ + + /* close socket gracefully */ + pxe_close(hh->socket); + hh->socket = -1; + + if (!pxe_exists(hh)) { +#ifdef PXE_HTTP_DEBUG + printf("pxe_get(): connection breaked.\n"); +#endif + return (-1); + } + /* reestablished, continue normal work */ + } + + if ( (size_to_get < PXE_HTTP_SIZE_UNKNOWN) && + (size_to_get > 0)) + { + snprintf(hh->buf, hh->bufsize, "GET %s%s HTTP/1.1\r\nHost: %s\r\n" + "Range: bytes=%llu-%llu\r\nConnection: keep-alive\r\n" + "Keep-Alive: 300\r\nUser-Agent: pxe_http/0\r\n\r\n", + rootpath, hh->filename, hh->servername, hh->offset, + hh->offset + size - 1); + } else { + /* asked zero bytes, or size of file is unknown */ + printf("pxe_get(): internal error\n"); + return (-1); + } + + size_t len = strlen(hh->buf); + +#ifdef PXE_HTTPFS_CACHING + PXE_HTTP_WAIT_DATA wait_data; + wait_data.buf = pxe_sock_recv_buffer(hh->socket); + /* assuming recv_buffer always is not NULL */ + wait_data.start_size = pxe_buffer_space(wait_data.buf); + wait_data.wait_size = (uint16_t)size; + wait_data.socket = hh->socket; +#endif + if (len != pxe_send(hh->socket, hh->buf, len)) { + printf("pxe_get(): failed to send request.\n"); + return (-1); + } + + if (pxe_flush(hh->socket) == -1) { + printf("pxe_get(): failed to push request.\n"); + return (-1); + } + + size_t count = 0; + char *found = NULL; + + /* retrieve header */ +#ifndef PXE_HTTPFS_CACHING + int result = http_get_header(hh->socket, hh->buf, hh->bufsize - 1, + &found, &count); +#else + int result = http_get_header2(hh->socket, hh->buf, hh->bufsize - 1, + &found, &count); +#endif + + if (found == NULL) { /* haven't found end of header */ + printf("pxe_get(): cannot find reply header.\n"); + return (-1); + } + + /* parse header */ + PXE_HTTP_PARSE_DATA parse_data; + pxe_memset(&parse_data, 0, sizeof(PXE_HTTP_PARSE_DATA)); + + if (!http_reply_parse(hh->buf, count, &parse_data)) { + printf("pxe_get(): cannot parse reply header.\n"); + return (-1); + } + + if ( (parse_data.code < 200) || + (parse_data.code >= 300) ) + { + printf("pxe_get(): failed to get (status: %u).\n", + parse_data.code); + + return (-1); + } + + /* update counter, substruct header size */ + count -= (found - hh->buf) + 4; + + /* process body data */ + if (count > size_to_get) { /* sanity check, never must be */ +#ifdef PXE_HTTP_DEBUG + printf("pxe_get(): warning:1, count: %lu, size_to_get: %lu\n", + count, size); +#endif + count = size_to_get; + } + +#ifndef PXE_HTTPFS_CACHING + pxe_memcpy((char *)found + 4, buffer, count); + + while (count < size_to_get) { + + result = pxe_recv(hh->socket, buffer + count, + size_to_get - count, PXE_SOCK_BLOCKING); + + if (result == -1) + break; + + if (result == 0) + continue; + + count += result; + } + +#ifdef PXE_HTTP_DEBUG_HELL + printf("\npxe_get(): %lu of %lu byte(s) received.\n", count, size); +#endif + + if (count > size_to_get) { /* sanity check, never must be */ +#ifdef PXE_HTTP_DEBUG + printf("pxe_get(): warning:2, count: %lu, size_to_get: %lu\n", + count, size); +#endif + count = size_to_get; + } +#else + /* waiting buffer space become filled by our data, + * main difference with normal processing, that we don't need read + * received data here. Main trick is just receive it, and store + * in buffer, httpfs code will read it when needed. + */ + + if (wait_data.start_size - pxe_buffer_space(wait_data.buf) < size) + /* receiving data, maximum wait 1 minute */ + pxe_await(http_await, 1, 60000, &wait_data); + + count = wait_data.start_size - + pxe_buffer_space(wait_data.buf); + + hh->cache_size += count; + +#ifdef PXE_HTTP_DEBUG + printf("%lu read, cache: %lu \n", count, hh->cache_size); +#endif + +#endif /* PXE_HTTPFS_CACHING */ + return (count); +} + +#if defined(PXE_MORE) || defined(PXE_HTTP_AUTO_KEEPALIVE) +/* pxe_get_close() - gets portion of file, closing socket after getting + * in: + * hh - descriptor of file to read data from + * size - size of part to read starting at from offset + * out: + * -1 - failed + * >=0 - actual bytes read + */ +int +pxe_get_close(PXE_HTTP_HANDLE *hh, size_t size, void *buffer) +{ + size_t size_to_get = (size > 0) ? size : hh->size; + +#ifdef PXE_HTTP_DEBUG_HELL + printf("pxe_get_close(): %s:%s:%llu+%lu(%lu:%lu) to 0x%x\n", + inet_ntoa(hh->addr.ip), hh->filename, hh->offset, + size_to_get, size, hh->size, hh->buf); +#endif + int socket = pxe_socket(); + + if (socket == -1) { + printf("pxe_get_close(): failed to create socket.\n"); + return (-1); + } + + int result = pxe_connect(socket, &hh->addr, 80, PXE_TCP_PROTOCOL); + + if (result == -1) { +#ifdef PXE_HTTP_DEBUG + printf("pxe_get_close(): failed to connect.\n"); +#endif + pxe_close(socket); + return (-1); + } + + if ( (size_to_get < PXE_HTTP_SIZE_UNKNOWN) && + (size_to_get > 0)) + { + snprintf(hh->buf, hh->bufsize, "GET %s%s HTTP/1.1\r\nHost: %s\r\n" + "Range: bytes=%llu-%llu\r\nConnection: Close\r\n" + "User-Agent: pxe_http/0\r\n\r\n", + rootpath, hh->filename, hh->servername, + hh->offset, hh->offset + size - 1); + } else { + snprintf(hh->buf, hh->bufsize, + "GET %s%s HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n" + "User-Agent: pxe_http/0\r\n\r\n", + rootpath, hh->filename, hh->servername); + } + + size_t len = strlen(hh->buf); + +#ifdef PXE_HTTPFS_CACHING + PXE_HTTP_WAIT_DATA wait_data; + wait_data.buf = pxe_sock_recv_buffer(socket); + /* assuming recv_buffer always is not NULL */ + wait_data.start_size = pxe_buffer_space(wait_data.buf); + wait_data.wait_size = (uint16_t)size; + wait_data.socket = socket; +#endif + if (len != pxe_send(socket, hh->buf, len)) { + printf("pxe_get_close(): failed to send request.\n"); + pxe_close(socket); + return (-1); + } + + if (pxe_flush(socket) == -1) { + printf("pxe_get_close(): failed to push request.\n"); + pxe_close(socket); + return (-1); + } + + size_t count = 0; + char *found = NULL; + + /* retrieve header */ + +#ifndef PXE_HTTPFS_CACHING + result = http_get_header(socket, hh->buf, hh->bufsize - 1, + &found, &count); +#else + result = http_get_header2(socket, hh->buf, hh->bufsize - 1, + &found, &count); +#endif + + if (found == NULL) { /* haven't found end of header */ + printf("pxe_get_close(): cannot find reply header\n"); + pxe_close(socket); + return (-1); + } + + /* parse header */ + PXE_HTTP_PARSE_DATA parse_data; + pxe_memset(&parse_data, 0, sizeof(PXE_HTTP_PARSE_DATA)); + + if (!http_reply_parse(hh->buf, count, &parse_data)) { + printf("pxe_get_close(): cannot parse reply header\n"); + pxe_close(socket); + return (-1); + } + + if ( (parse_data.code < 200) || + (parse_data.code >= 300) ) + { + printf("pxe_get_close(): failed to get (status: %u).\n", + parse_data.code); + + pxe_close(socket); + return (-1); + } + + /* update counter, substruct header size */ + count -= (found - hh->buf) + 4; + + /* process body data */ + if (count > size_to_get) { /* sanity check, never must be */ +#ifdef PXE_HTTP_DEBUG + printf("pxe_get_close(): warning:1, count: %lu, " + "size_to_get: %lu\n", count, size); +#endif + count = size_to_get; + } + +#ifndef PXE_HTTPFS_CACHING + pxe_memcpy((char *)found + 4, buffer, count); + + while (count < size_to_get) { + result = pxe_recv(socket, buffer + count, size_to_get - count, + PXE_SOCK_BLOCKING); + + if (result == -1) + break; + + if (result == 0) + continue; + + count += result; + } +#ifndef PXE_HTTP_AUTO_KEEPALIVE + pxe_close(socket); +#endif + +#ifdef PXE_HTTP_DEBUG + printf("\npxe_get_close(): %lu of %lu byte(s) received.\n", + count, size); +#endif + + if (count > size_to_get) { /* sanity check, never must be */ +#ifdef PXE_HTTP_DEBUG + printf("pxe_get_close(): warning:2, count: %lu, " + "size_to_get: %lu\n", count, size); +#endif + count = size_to_get; + } +#else /* PXE_HTTPFS_CACHING */ + + if (wait_data.start_size - pxe_buffer_space(wait_data.buf) < size) + /* receiving data, maximum wait 1 minute */ + pxe_await(http_await, 1, 60000, &wait_data); + + count = wait_data.start_size - + pxe_buffer_space(wait_data.buf); + + hh->cache_size += count; + + hh->socket = socket; + +#ifdef PXE_HTTP_DEBUG + printf("%lu read, cache: %lu \n", count, hh->cache_size); +#endif + +#endif /* PXE_HTTPFS_CACHING */ + return (count); +} +#endif /* PXE_MORE || PXE_HTTP_AUTO_KEEPALIVE */ + +/* pxe_exists() - checks if file exists and gets it's size + * in: + * hh - descriptor of file to read data from + * out: + * 0 - failed, not exists + * 1 - ok, file exists + */ +int +pxe_exists(PXE_HTTP_HANDLE *hh) +{ + int socket = pxe_socket(); + + int result = pxe_connect(socket, &hh->addr, 80, PXE_TCP_PROTOCOL); + + if (result == -1) { + pxe_close(socket); + return (0); + } + + snprintf(hh->buf, hh->bufsize, + "HEAD %s%s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n" + "User-Agent: pxe_http/0\r\n\r\n", rootpath, hh->filename, + hh->servername); + + size_t len = strlen(hh->buf); + + if (len != pxe_send(socket, hh->buf, len)) { + printf("pxe_exists(): failed to send request.\n"); + pxe_close(socket); + return (0); + } + + if (pxe_flush(socket) == -1) { + printf("pxe_exists(): failed to push request.\n"); + pxe_close(socket); + return (0); + } + + size_t count = 0; + char *found = NULL; + + /* retrieve header */ + result = http_get_header(socket, hh->buf, hh->bufsize, &found, &count); + + if (found == NULL) { /* haven't found end of header */ + pxe_close(socket); + return (0); + } + + + /* parse header */ + PXE_HTTP_PARSE_DATA parse_data; + pxe_memset(&parse_data, 0, sizeof(PXE_HTTP_PARSE_DATA)); + + if (!http_reply_parse(hh->buf, count, &parse_data)) { + pxe_close(socket); + return (0); + } + + if ( (parse_data.code < 200) || + (parse_data.code >= 300) ) + { +#ifdef PXE_HTTP_DEBUG + printf("pxe_exists(): failed to get header (status: %u).\n", + parse_data.code); +#endif + pxe_close(socket); + return (0); + } + + /* server doesn't support keep-alive connections */ + if (parse_data.isKeepAlive == 0) { + printf("pxe_exists(): Server denied keep-alive connection.\n"); + pxe_close(socket); + socket = -1; + } + + hh->socket = socket; + hh->size = parse_data.size; + hh->isKeepAlive = parse_data.isKeepAlive; + +#ifdef PXE_HTTP_DEBUG + printf("pxe_exists(): size = %lu bytes\n", hh->size); +#endif + return (1); +} Index: user/sbruno/pxe_http/pxe_http.h =================================================================== --- user/sbruno/pxe_http/pxe_http.h (nonexistent) +++ user/sbruno/pxe_http/pxe_http.h (revision 245442) @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_HTTP_INCLUDED +#define PXE_HTTP_INCLUDED + +/* + * http downloading functions. + */ + +#include +#include + +#ifdef PXE_HTTPFS_CACHING +#include "pxe_buffer.h" +#endif + +/* default buffer size for generating/getting http header */ +#define PXE_MAX_HTTP_HDRLEN 1024 +/* testing function, outputs received data to screen */ +int pxe_fetch(char *server, char *filename, off_t from, size_t size); + +typedef struct pxe_http_handle { + + char *filename; /* filename including path on server */ + char *servername; /* server name */ + + int socket; /* opened socket, or -1 */ + + char *buf; /* buffer for creating requests */ + uint16_t bufsize; /* size of buffer */ + + PXE_IPADDR addr; /* web server ip */ + off_t offset; /* current offset in bytes from + * beginning of file */ +#ifdef PXE_HTTPFS_CACHING +/* off_t cache_start; /* cached block, to reduce http requests */ + uint16_t cache_size; /* size of cached block */ +#endif + size_t size; /* file size if known */ + int isKeepAlive; /* if connection keep-alive? */ +} PXE_HTTP_HANDLE; + +/* gets requested data from server */ +int pxe_get(PXE_HTTP_HANDLE *hh, size_t size, void *buffer); + +/* gets requested data from server, closing connection after */ +int pxe_get_close(PXE_HTTP_HANDLE *hh, size_t size, void *buffer); + +/* checks if file exists and fills filesize if known */ +int pxe_exists(PXE_HTTP_HANDLE *hh); + +#define PXE_HTTP_SIZE_UNKNOWN -1 + +typedef struct pxe_http_parse_data { + uint16_t code; /* response code */ + size_t size; /* size of data if known */ + int isKeepAlive; /* positive if server supports + * keep-alive connections + */ +} PXE_HTTP_PARSE_DATA; + +#ifdef PXE_HTTPFS_CACHING +/* used in waiting function */ +typedef struct pxe_http_wait_data { + PXE_BUFFER *buf; /* buffer, waiting to fill */ + int socket; /* socket, which buffer is above */ + uint16_t wait_size; /* how much must be filled */ + uint16_t start_size; /* how much were in buffer before waiting */ +} PXE_HTTP_WAIT_DATA; +#endif + +#endif Index: user/sbruno/pxe_http/pxe_httpls.c =================================================================== --- user/sbruno/pxe_http/pxe_httpls.c (nonexistent) +++ user/sbruno/pxe_http/pxe_httpls.c (revision 245442) @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_httpls.h" +#include "pxe_sock.h" + +/* fgetch() - returns one char from opened file + * in: + * fd - file descriptor + * out: + * -1 - if failed + * >0 - read char + */ +int +fgetch(int fd) +{ + char ch = 0; + ssize_t result = read(fd, &ch, 1); + + return (result != -1) ? ch : -1; +} + +/* http_parse_index() - parses index file generated by server for directory, + * print result data to screen. + * in: + * fd - descriptor of file to parse + * out: + * none + */ +void +http_parse_index(int fd) +{ + char ch = 0; + int stream_state = TAG_EXPECT_OPEN; + char tag_body[TAG_MAX_BODY] = {0}; + int tag_size = 0; + int dir_listing = 0; + + while( (ch = fgetch(fd)) != -1) { + + switch(ch) { + case '<': + if (stream_state == TAG_EXPECT_OPEN) { + stream_state = TAG_EXPECT_BODY; + tag_size = 0; + /* printf("{TEB}"); */ + continue; + } + break; + + case '>': + if ( (stream_state == TAG_EXPECT_CLOSE) || + (stream_state == TAG_EXPECT_BODY)) + { + stream_state = TAG_EXPECT_OPEN; + /* printf("{TEO}");*/ + + /* check for
*/ + if (tag_size == 2) { + + if ( ((tag_body[0] == 'h') || + (tag_body[0] == 'H')) && + ((tag_body[1] == 'r') || + (tag_body[1] == 'R'))) + { /* it's
, inverting dir_listing + * for apache1.3 directory listing is + * between
tags. + */ + dir_listing = 1 - dir_listing; + + if (dir_listing == 0) + return; + } + } + + continue; + } + break; + + case ' ': case '\t': // whitespace + if (stream_state == TAG_EXPECT_BODY) { + stream_state = TAG_EXPECT_CLOSE; + /* printf("{TEC}"); */ + continue; + } + break; + + default: + break; + } + + if ( (stream_state == TAG_EXPECT_OPEN) && (dir_listing == 1)) + printf("%c", ch); + + if (stream_state == TAG_EXPECT_BODY) { + if (tag_size < TAG_MAX_BODY) { + tag_body[tag_size] = ch; + tag_size += 1; + } else { + stream_state = TAG_EXPECT_CLOSE; + } + } + } +} Index: user/sbruno/pxe_http/pxe_httpls.h =================================================================== --- user/sbruno/pxe_http/pxe_httpls.h (nonexistent) +++ user/sbruno/pxe_http/pxe_httpls.h (revision 245442) @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_HTTPLS_INCLUDED +#define PXE_HTTPLS_INCLUDED + +/* stream state flags during parsing of html */ +/* expecting opening of tag: ..*/ +#define TAG_EXPECT_OPEN 0 +/* expecting tag body: tag.. */ +#define TAG_EXPECT_BODY 1 +/* expecting tag closing: .. > */ +#define TAG_EXPECT_CLOSE 2 +/* max characters of tag body to store during parsing */ +#define TAG_MAX_BODY 4 + +/* parses autogenerated index for directory, it's assumed that file descriptor + provides data in html format */ +void http_parse_index(int fd); + +#endif /* PXE_HTTPLS_INCLUDED */ Index: user/sbruno/pxe_http/pxe_icmp.c =================================================================== --- user/sbruno/pxe_http/pxe_icmp.c (nonexistent) +++ user/sbruno/pxe_http/pxe_icmp.c (revision 245442) @@ -0,0 +1,259 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ +#ifdef PXE_MORE +#include + +#include "pxe_arp.h" +#include "pxe_core.h" +#include "pxe_icmp.h" +#include "pxe_ip.h" + +/* used in echo replying */ +static PXE_IPADDR pinging; /* ip to accept replies from */ +static uint16_t seq_number; /* next sequence number to accept */ +/* last sequence number accepted */ +static uint16_t last_accepted = 0xffff; +/* 1 - show messages on screen while ping, 0 - not */ +static int echo_flags = 0; + +/* pxe_icmp_callback() - callback function, executed by pxe_core + * in: + * pack - packet describing data + * function- function, which must be performed + * out: + * always 0 + */ +int +pxe_icmp_callback(PXE_PACKET *pack, uint8_t function) +{ + + if (function == PXE_CORE_FRAG) + return (1); + + /* icmp header */ + PXE_IP_HDR *iphdr = (PXE_IP_HDR *)pack->data; + size_t iphdr_len = (iphdr->ver_ihl & 0x0f) * 4; + size_t data_size = ntohs(iphdr->length) - + iphdr_len - sizeof(PXE_ICMP_HDR); + PXE_ICMP_HDR *icmphdr = (PXE_ICMP_HDR *)(pack->data + iphdr_len); + +#ifdef PXE_DEBUG + printf("pxe_icmp_callback(): data size %d (of %d) bytes, type: %d\n", + data_size, pack->data_size, icmphdr->type); +#endif + /* TODO: verify checksum */ + + /* reply */ + PXE_IP_HDR *reply_iphdr = NULL; + PXE_ICMP_HDR *reply_icmphdr = NULL; + size_t reply_size = sizeof(PXE_IP_HDR) + sizeof(PXE_ICMP_HDR) + + data_size; + + uint16_t reply_number = ntohl(icmphdr->seq_num); + + /* we are interested only in echo related packets*/ + switch(icmphdr->type) { + case PXE_ICMP_ECHO_REQUEST: + case PXE_ICMP_ECHO_REPLY: + /* case PXE_ICMP_DEST_UNREACHABLE: + case PXE_ICMP_REDIRECT_MESSAGE: + */ + break; + default: + return (0); /* instruct pxe core to drop packet*/ + }; + + if (icmphdr->type == PXE_ICMP_ECHO_REPLY) { + + if ( (reply_number != seq_number) && (icmphdr->code != 0)) { +#ifdef PXE_DEBUG + printf("pxe_icmp_callback(): seq %d != %d expected\n", + reply_number, seq_number); +#endif + return (0); /* ignore this packet */ + } + + uint16_t id = (uint16_t)(seq_number*seq_number); + if (icmphdr->packet_id != id) { + if (echo_flags) + printf("pxe_icmp_callback(): skipping id 0x%x, " + "0x%x expected\n", icmphdr->packet_id, id); + + return (0); + } + + if (pinging.ip == iphdr->src_ip) { + + if (echo_flags) { + printf("pxe_ping(): echo reply from %d.%d.%d.%d," + " seq=%ld ", + pinging.octet[0], pinging.octet[1], + pinging.octet[2], pinging.octet[3], + seq_number); + } + + /* notify pxe_ping() code that we received reply */ + last_accepted = seq_number; + } + + return (0); + } + + /* all we need now is echo reply */ + + /* using buffer of recieved packet to avoid additional + * memory copy operations */ + + reply_iphdr = (PXE_IP_HDR *)pack->data; + reply_icmphdr = (PXE_ICMP_HDR *)(pack->data + iphdr_len); + + reply_icmphdr->type = PXE_ICMP_ECHO_REPLY; + reply_icmphdr->checksum = 0; + reply_icmphdr->checksum = + ~pxe_ip_checksum(reply_icmphdr, sizeof(PXE_ICMP_HDR) + data_size); + + PXE_IPADDR addr; + addr.ip = iphdr->src_ip; + + if (!pxe_ip_send(pack->data, &addr, PXE_ICMP_PROTOCOL, + pack->data_size) && echo_flags) + { + printf("pxe_ping(): failed to send echo reply.\n"); + } + + return (0); /* drop it, we don't need this packet more. + * this is a little bit ugly, may be + * using of more return codes will be more flexible + */ +} + +/* pxe_icmp_init() - register ICMP protocol in pxe_core protocols table + * in: + * none + * out: + * always 1. TODO: think about making this function void + */ +int +pxe_icmp_init() +{ + /* register protocol in pxe_core protocols table. */ + pxe_core_register(PXE_ICMP_PROTOCOL, pxe_icmp_callback); + + return (1); +} + +/* pxe_ping() - pings choosed ip with 32 bytes of data packets + * in: + * ip - ip to send echo requests + * count - count of requests + * flags - 0 to hide output, 1 to show + * out: + * number of successfull pings + */ +int +pxe_ping(const PXE_IPADDR *ip, int count, int flags) +{ + + seq_number = 0; + last_accepted = 0xffff; + echo_flags = flags; + + /* creating data storage for packet */ + uint8_t data[sizeof(PXE_IP_HDR) + sizeof(PXE_ICMP_HDR) + 32]; + + size_t pack_size = + sizeof(PXE_IP_HDR) + sizeof(PXE_ICMP_HDR) + 32; + PXE_IP_HDR *iphdr = NULL; + PXE_ICMP_HDR *icmphdr = NULL; + uint32_t wait_time = 0; + int scount = 0; + + if (flags) + printf("pxe_ping(): pinging %s, 32 bytes\n", inet_ntoa(ip->ip)); + + pinging.ip = ip->ip; + + iphdr = (PXE_IP_HDR *)data; + icmphdr = (PXE_ICMP_HDR *)(data + sizeof(PXE_IP_HDR)); + + /* base icmp header side */ + icmphdr->type = PXE_ICMP_ECHO_REQUEST; + icmphdr->code = 0; + + while (seq_number < count) { + + ++seq_number; + + icmphdr->seq_num = htons(seq_number); + /* is this good idea? */ + icmphdr->packet_id = (uint16_t)(seq_number*seq_number); + + /* recalc for every packet */ + icmphdr->checksum = 0; + icmphdr->checksum = + ~(pxe_ip_checksum(icmphdr, sizeof(PXE_ICMP_HDR) + 32)); + + if (!pxe_ip_send(data, ip, PXE_ICMP_PROTOCOL, pack_size) && + echo_flags) + { + printf("pxe_ping(): failed to send echo reply.\n"); + } + + /* echo reply waiting */ + wait_time = 0; + + while (wait_time < PXE_ICMP_TIMEOUT) { + + twiddle(); + wait_time += 10; + + if (!pxe_core_recv_packets()) + delay(10000); + + if (last_accepted == seq_number) { + + if (flags) + printf("< %d ms\n", wait_time); + + ++scount; + break; + } + } + + if ( (last_accepted != seq_number) && flags) + printf("ping timeout.\n"); + + /* wait a little, to avoid ICMP flood */ + delay(500000); + } + + pinging.ip = 0; + echo_flags = 0; + + return (scount); +} +#endif Index: user/sbruno/pxe_http/pxe_icmp.h =================================================================== --- user/sbruno/pxe_http/pxe_icmp.h (nonexistent) +++ user/sbruno/pxe_http/pxe_icmp.h (revision 245442) @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_ICMP_H_INCLUDED +#define PXE_ICMP_H_INCLUDED + +/* ICMP related code + * reference: RFC792 + */ + +#include + +#include "pxe_ip.h" + +/* ICMP protocol number in IP stack */ +#define PXE_ICMP_PROTOCOL 0x01 +/* ICMP header */ +typedef struct pxe_icmp_hdr { + uint8_t type; /* type of ICMP packet */ + uint8_t code; /* code, used to identify session */ + uint16_t checksum; /* ICMP header checksum */ + uint16_t packet_id; /* for echo */ + uint16_t seq_num; /* for echo */ +} __packed PXE_ICMP_HDR; + +/* timeout in milliseconds */ +#define PXE_ICMP_TIMEOUT 5000 + +/* pxe_ping - send icmp echo request packets to host + * in: + * ip - host ip address + * count - packets to send + * flags - 1 echo ping information to screen + * out: + * successfull recieved echo's count + */ +int pxe_ping(const PXE_IPADDR *ip, int count, int flags); + +/* pxe_icmp_init - inits icmp protocol + * in: + * none + * out: + * positive - if successful + * 0 - failed + */ +int pxe_icmp_init(); + +#define PXE_ICMP_ECHO_REPLY 0 +#define PXE_ICMP_DEST_UNREACHABLE 3 +#define PXE_ICMP_REDIRECT_MESSAGE 5 +#define PXE_ICMP_ECHO_REQUEST 8 + +#define PXE_ICMP_ALT_HOST_ADAPTER 6 +#define PXE_ICMP_SOURCE_QUENCH 4 + + +/* other packet types + * 9 - Router Advertisement + * 10 - Router Solicitation + * 11 - Time Exceeded + * 12 - Parameter Problem + * 13 - Timestamp + * 14 - Timestamp Reply + * 15 - Information Request + * 16 - Information Reply + * 17 - Address Mask Request + * 18 - Address Mask Reply + * 30 - Traceroute + * 31 - Datagram Conversion Error + * 32 - Mobile Host Redirect + * 35 - Mobile Registration Request + * 36 - Mobile Registration Reply + * 38 - Domain Name Reply + */ +#endif // PXE_ICMP_H_INCLUDED Index: user/sbruno/pxe_http/pxe_ip.c =================================================================== --- user/sbruno/pxe_http/pxe_ip.c (nonexistent) +++ user/sbruno/pxe_http/pxe_ip.c (revision 245442) @@ -0,0 +1,423 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_core.h" +#include "pxe_ip.h" +#ifdef PXE_MORE +#include "pxe_icmp.h" +#endif + +/* routing table */ +static PXE_IP_ROUTE_ENTRY route_table[PXE_MAX_ROUTES]; +/* total count of routes in table */ +static int all_routes = 0; +/* id of packets */ +static uint16_t packet_id = 1; + +/* pxe_ip_route() - init default routes + * in: + * def_gw - default gateway ip + * out: + * none + */ +void +pxe_ip_route_init(const PXE_IPADDR *def_gw) +{ + + if (all_routes) /* already inited */ + return; + + /* add default gw */ + pxe_ip_route_default(def_gw); + all_routes += 1; + + /* if using libstand, set network route in pxe_dhcp_query() */ +#ifndef PXE_BOOT_USE_LIBSTAND + const PXE_IPADDR* myip = pxe_get_ip(PXE_IP_MY); + + /* make route for local network */ + const PXE_IPADDR *netmask = pxe_get_ip(PXE_IP_NETMASK); + uint32_t mask = netmask->ip; + + if (mask == 0) /* mask isn't set via DHCP/BOOTP, setting it manually */ + mask = pxe_ip_get_netmask(myip); + + if (mask == 0) { + printf("pxe_ip_route_init(): my ip is class D or class E," + " don't know how understand this.\n"); + return; + } + + pxe_ip_route_add(myip, mask, NULL); +#endif +} + +/* pxe_ip_get_netmask() - returns class based mask for provided ip. + * in: + * ip - ip address, from which network class is extracted + * out: + * 0 - failed + * not 0 - network mask + */ +uint32_t +pxe_ip_get_netmask(const PXE_IPADDR *addr) +{ + uint8_t net_class = ((addr->ip) & 0x000000F0) >> 4; + + if ( (net_class & 0x0c) == 0x0c) /* class C */ + return (0x00ffffff); + else if ((net_class & 0x08) == 0x08) /* class B */ + return (0x0000ffff); + else if ((net_class & 0x08) == 0x00) /* class A */ + return (0x000000ff); + + /* D & E classes are not supported yet... */ + return (0); +} + +/* pxe_ip_route_add() - adds one more route to routing table + * in: + * net - network to route to + * mask - network mask + * gw - gateway for this network + * out: + * 0 - failed to add route + * 1 - success + */ +int +pxe_ip_route_add(const PXE_IPADDR *net, uint32_t mask, const PXE_IPADDR *gw) +{ + + printf("pxe_ip_route_add(): adding net %s mask %8x gw ", + inet_ntoa(net->ip), ntohl(mask)); + + if (gw && gw->ip) + printf("%s\n", inet_ntoa(gw->ip)); + else + printf("pxenet0\n"); + + if (all_routes == PXE_MAX_ROUTES) { + printf("pxe_ip_route_add(): failed, routing table is full.\n"); + return (0); + } + +#ifdef PXE_MORE + if ( (gw!=NULL) && (gw->ip) && (pxe_ping(gw, 3, 0) == 0) ) { + printf("pxe_ip_route_add(): failed, gateway is unreachable.\n"); + return (0); + } +#endif + route_table[all_routes].net.ip = (net->ip & mask); + route_table[all_routes].mask = mask; + route_table[all_routes].gw.ip = (gw != NULL) ? gw->ip : 0; + + ++all_routes; + + return (1); +} + +#ifdef PXE_MORE +/* pxe_ip_route_del() - removes route from routing table + * in: + * net - network to route to + * mask - network mask + * gw - gateway for this network + * out: + * 0 - failed to remove (e.g. no such route found) + * 1 - success + */ +int +pxe_ip_route_del(const PXE_IPADDR *net, uint32_t mask, const PXE_IPADDR *gw) +{ + int route_index = 1; + + printf("pxe_ip_route_add(): deleting net %s mask %8x gw", + inet_ntoa(net->ip), htonl(mask)); + + printf("%s\n", inet_ntoa(gw->ip)); + + for ( ; route_index < all_routes; ++route_index) { + + if ((route_table[route_index].net.ip == net->ip) && + (route_table[route_index].gw.ip == gw->ip) && + (route_table[route_index].mask == mask)) + { + --all_routes; + + if (route_index == all_routes) + return (1); + + /* shift routes */ + pxe_memcpy(&route_table[route_index + 1], + &route_table[route_index], + sizeof(PXE_IP_ROUTE_ENTRY) * + (all_routes - route_index)); + + return (1); + } + + } + + printf("pxe_ip_route_del(): there is no such route.\n"); + return (0); +} +#endif /* PXE_MORE */ + +/* pxe_ip_route_default() - sets default gateway + * in: + * gw - ip address of default gateway + * out: + * 0 - failed (e.g. gateway is unreachable for pings) + * 1 - success + */ +int +pxe_ip_route_default(const PXE_IPADDR *gw) +{ + + printf("pxe_ip_route_default(): setting default gateway %s\n", + inet_ntoa(gw->ip)); + +#ifdef PXE_MORE + /* don't check if there are no any entries */ + if (all_routes && (pxe_ping(gw, 3, 0) == 0) ) { + printf("pxe_ip_route_add(): failed, gateway is unreachable.\n"); + return (0); + } +#endif + route_table[0].net.ip = 0; + route_table[0].mask = 0; + route_table[0].gw.ip = gw->ip; + + return (1); +} + +/* pxe_ip_checksum() - calculates 16bit checksum of 16bit words + * in: + * data - pointer to buffer to calc checksum for + * size - size of buffer + * out: + * checksum + */ +uint16_t +pxe_ip_checksum(const void *data, size_t size) +{ + const uint8_t *cur = data; + uint32_t sum = 0; + uint32_t ind = 0; + + for (; ind < size; ++ind, ++cur) { + uint32_t byte = (*cur); + + if (ind & 1) /* odd */ + byte <<= 8; + + sum += byte; + + if (sum & 0xF0000) /* need carry out */ + sum -= 0xFFFF; + } + + return (uint16_t)( (sum) & 0x0000FFFF); +} + +#ifdef PXE_MORE +/* pxe_ip_route_stat() - shows current routes + * in: + * none + * out: + * none + */ +void +pxe_ip_route_stat() +{ + int index = 0; + + printf("Destination\t\tGateway\t\tMAC\n"); + for ( ; index < all_routes; ++index) { + + printf("%s/%x\t\t", + inet_ntoa(route_table[index].net.ip), + ntohl(route_table[index].mask)); + + if (route_table[index].gw.ip == 0) + printf("pxenet0"); + else { + printf("%s\t\t", + inet_ntoa(route_table[index].gw.ip)); + + uint8_t *mac = + (uint8_t *)pxe_arp_ip4mac(&route_table[index].gw); + + if (mac != NULL) + printf("%6D", mac, ":"); + } + printf("\n"); + } +} +#endif /* PXE_MORE */ + +/* pxe_create_ip_hdr() - creates IP header for data, + * placing header in this buffer + * in: + * data - buffer with data in which header will be created + * dst_ip - destination IP address + * protocol- IP protocol (e.g. UDP) + * size - size of buffer + * opts_size - size of IP header options. Currently unused, set 0. + * out: + * none + */ +void +pxe_create_ip_hdr(void* data, const PXE_IPADDR *dst, uint8_t protocol, + uint16_t size, uint16_t opts_size) +{ + PXE_IP_HDR *iphdr = (PXE_IP_HDR *)data; + const PXE_IPADDR *addr = pxe_get_ip(PXE_IP_MY); + + iphdr->checksum = 0; + iphdr->length = htons(size); + iphdr->protocol = protocol; + iphdr->checksum = 0; + + /* data_off - offset of fragment, need to think about renaming. */ + iphdr->data_off = 0; + iphdr->dst_ip = dst->ip; + iphdr->id = htons(++packet_id); + iphdr->tos = 0; + iphdr->src_ip = addr->ip; + iphdr->ttl = 64; + + /* 0x45 [ver_ihl] = 0x4 << 4 [ip version] | + * 0x5 [header length = 20 bytes, no opts] + */ + iphdr->ver_ihl = 0x45; + iphdr->ver_ihl += (opts_size >> 2); + + iphdr->checksum = + ~pxe_ip_checksum(data, sizeof(PXE_IP_HDR) + opts_size); +} + +/* pxe_ip_route_find() - searches gateway to destination + * in: + * dst - destination IP address + * out: + * dst - if there is no gateway, or dst_ip directly accessible + * otherwise - gateway IP address + */ +const PXE_IPADDR * +pxe_ip_route_find(const PXE_IPADDR *dst) +{ + int index = 1; /* route 0 - default gateway */ + + /* if there are no routes, try to send directly */ + if (all_routes == 0) + return (dst); + + PXE_IP_ROUTE_ENTRY *route = &route_table[1]; + + for ( ; index < all_routes; ++index) { + + if ( (dst->ip & route->mask) == route->net.ip ) { + /* found route */ +#ifdef PXE_IP_DEBUG_HELL + printf("pxe_ip_route_find(): route 0x%x\n", + (route->gw.ip == 0) ? dst : &route->gw); +#endif + /* gateway == 0 only for local network */ + return (route->gw.ip == 0) ? dst : &route->gw; + } + } + + /* return default gateway */ + return &route_table[0].gw; +} + +/* pxe_ip_send() - transmits packet provided destination address, + * using routing table + * in: + * data - buffer to transmit + * dst_ip - destination IP address + * protocol- IP stack protocol (e.g. UDP) + * size - size of data buffer + * out: + * 0 - failed + * 1 - success + */ +int +pxe_ip_send(void *data, const PXE_IPADDR *dst, uint8_t protocol, uint16_t size) +{ + PXE_PACKET pack_out; + int status = 0; + + pack_out.data = data; + pack_out.data_size = size; + + /* creating ip header */ + pxe_create_ip_hdr(pack_out.data, dst, protocol, size, 0); + + /* setting pxe_core packet parameters */ + pack_out.flags = (dst->ip != PXE_IP_BCAST) ? PXE_SINGLE : PXE_BCAST; + pack_out.protocol = PXE_PROTOCOL_IP; + + /* find gateway or direct MAC */ + const PXE_IPADDR *ip_to_send = dst; + + if (pack_out.flags != PXE_BCAST) { + ip_to_send = pxe_ip_route_find(dst); + pack_out.dest_mac = pxe_arp_ip4mac(ip_to_send); + } else { + pack_out.dest_mac = NULL; + } + +#ifdef PXE_IP_DEBUG_HELL + printf("pxe_ip_send(): %d proto, %s (%6D), %s.\n", protocol, + inet_ntoa(ip_to_send->ip), + pack_out.dest_mac != NULL ? pack_out.dest_mac : "\0\0\0\0\0\0", ":", + pack_out.flags == PXE_SINGLE ? "single" : "bcast"); +#endif + + if ( (pack_out.flags != PXE_BCAST) && (pack_out.dest_mac == NULL) ) { + /* MAC is not found for destination ip or gateway */ +#ifdef PXE_IP_DEBUG + printf("pxe_ip_send(): cannot send ip packet to %s, ", + inet_ntoa(dst->ip)); + + printf("MAC is unknown for %s\n", inet_ntoa(ip_to_send->ip)); +#endif + } else { + if (!pxe_core_transmit(&pack_out)) { +#ifdef PXE_IP_DEBUG + printf("pxe_ip_send(): failed to send packet.\n"); +#endif + } else + status = 1; + } + + return (status); +} Index: user/sbruno/pxe_http/pxe_ip.h =================================================================== --- user/sbruno/pxe_http/pxe_ip.h (nonexistent) +++ user/sbruno/pxe_http/pxe_ip.h (revision 245442) @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_IP_H_INCLUDED +#define PXE_IP_H_INCLUDED + +/* + * IP related declarations + * Reference: RFC791 + */ + +#include +#include + +#include "../libi386/pxe.h" + +/* IPv4 header */ +typedef struct pxe_ip_hdr { + + uint8_t ver_ihl; /* version & IHL (size / 4 octets)*/ + uint8_t tos; /* type of service */ + uint16_t length; /* packet total length */ + uint16_t id; /* packet id */ + uint16_t data_off; /* this frame data offset */ + uint8_t ttl; /* time to live */ + uint8_t protocol; /* protocol */ + uint16_t checksum; /* header checksum */ + uint32_t src_ip; /* source ip address */ + uint32_t dst_ip; /* destination ip address */ +} __packed PXE_IP_HDR; + +/* pseudo header, used in checksum calculation for UDP and TCP */ +typedef struct pxe_ip4_pseudo_hdr { + + uint32_t src_ip; /* source ip */ + uint32_t dst_ip; /* destination ip */ + uint8_t zero; /* filled by zero */ + uint8_t proto; /* protocol */ + uint16_t length; /* length (protocol header + data) */ +} __packed PXE_IP4_PSEUDO_HDR; + +/* IPv4 address */ +typedef struct pxe_ipaddr { + union { + uint32_t ip; + uint8_t octet[4]; + }; +} __packed PXE_IPADDR; + +/* often used here broadcast ip */ +#define PXE_IP_BCAST 0xffffffff +/* maximum route table size */ +#define PXE_MAX_ROUTES 4 + +/* routing related structure */ +typedef struct pxe_ip_route_entry { + PXE_IPADDR net; /* network address */ + uint32_t mask; /* network mask */ + PXE_IPADDR gw; /* gateway to this network */ +} PXE_IP_ROUTE_ENTRY; + +/* calculates checksum */ +uint16_t pxe_ip_checksum(const void *data, size_t size); + +/* fills ip header data */ +void pxe_create_ip_hdr(void *data, const PXE_IPADDR *dst, uint8_t protocol, + uint16_t size, uint16_t opts_size); + +/* inits routing table */ +void pxe_ip_route_init(const PXE_IPADDR *def_gw); + +/* adds route to routing table */ +int pxe_ip_route_add(const PXE_IPADDR *net, uint32_t mask, + const PXE_IPADDR *gw); + +/* dels route from routing table */ +int pxe_ip_route_del(const PXE_IPADDR *net, uint32_t mask, + const PXE_IPADDR *gw); + +/* returns class based netmask for ip */ +uint32_t pxe_ip_get_netmask(const PXE_IPADDR *ip); + +/* adds default gateway */ +int pxe_ip_route_default(const PXE_IPADDR *gw); + +/* sends ip packet */ +int pxe_ip_send(void *data, const PXE_IPADDR *dst, uint8_t protocol, + uint16_t size); + +/* show route table */ +void pxe_ip_route_stat(); + +#endif // PXE_IP_H_INCLUDED Index: user/sbruno/pxe_http/pxe_ip6.h =================================================================== --- user/sbruno/pxe_http/pxe_ip6.h (nonexistent) +++ user/sbruno/pxe_http/pxe_ip6.h (revision 245442) @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_IP6_H_INCLUDED +#define PXE_IP6_H_INCLUDED + +/* + * IP6 related declarations + */ + +#include +#include + +#include "../libi386/pxe.h" + +/* IPv6 header */ +typedef struct pxe_ip6_hdr { + uint32_t label; /* version (0-3), traffic class (4-11), + and label (12-31) */ + uint16_t use_size; /* data size */ + uint8_t next_hdr; /* next header */ + uint8_t hops; /* hop count */ + uint8_t src_ip[16]; /* source ip6 address */ + uint8_t dst_ip[16]; /* destination ip6 address */ +} __packed PXE_IP_HDR; + +/* IPv6 address */ +typedef struct pxe_ipaddr { + uint8_t octet[16]; +} __packed PXE_IPADDR; + +/* often used here broadcast ip */ +#define PXE_IP_BCAST 0xffffffff +/* maximum route table size */ +#define PXE_MAX_ROUTES 4 + +/* routing related structure */ +typedef struct pxe_ip6_route_entry { + PXE_IPADDR net; /* network address */ + uint32_t mask; /* network mask in ::123/40 format mask == 40 */ + PXE_IPADDR gw; /* gateway to this network */ +} PXE_IP_ROUTE_ENTRY; + +/* fills ipv6 header data */ +void pxe_create_ip6_hdr(void *data, const PXE_IPADDR *dst, uint8_t proto, + uint16_t size, uint16_t opts); + +/* sends ipv6 packet */ +int pxe_ip6_send(void *data, const PXE_IPADDR *dst, uint8_t proto, uint16_t size); + +#endif // PXE_IP6_H_INCLUDED Index: user/sbruno/pxe_http/pxe_isr.S =================================================================== --- user/sbruno/pxe_http/pxe_isr.S (nonexistent) +++ user/sbruno/pxe_http/pxe_isr.S (revision 245442) @@ -0,0 +1,455 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +/* ISR, ISR installer, PXE API calling, etc. + * references: Intel PXE 2.1 specification, PXE SDK + * pxe.c + */ + .globl __pxe_isr_occured + .globl __pxe_nic_irq + .globl __pxe_entry_off, __pxe_entry_seg + .globl __pxe_entry_off2, __pxe_entry_seg2 + .globl __pxe_call + .globl __isr_install + .globl __isr_remove + .globl __pxe_isr + .globl __chained_irq_off + .globl __chained_irq_seg + .globl __mask_irq + .globl __mem_copy + + .code16 + .p2align 4,0x90 + # s_PXENV_UNDI_ISR start, look pxe.h + .set UISR_STATUS,0x00 # s_PXENV_UNDI_ISR Status + .set UISR_FUNC_FLAG,0x02 # s_PXENV_UNDI_ISR FuncFlag + .set UISR_BUFFER_LEN,0x04 # s_PXENV_UNDI_ISR BufferLength + .set UISR_FRAME_LEN,0x06 # s_PXENV_UNDI_ISR FrameLength + .set UISR_HEADER_LEN,0x08 # s_PXENV_UNDI_ISR FrameHeaderLength + .set UISR_FRAME_OFFSET,0x10 # s_PXENV_UNDI_ISR Frame + .set UISR_FRAME_SEG,0x12 # s_PXENV_UNDI_ISR Frame + .set UISR_PROTO_TYPE,0x14 # s_PXENV_UNDI_ISR ProtType + .set UISR_PACKET_TYPE,0x15 # s_PXENV_UNDI_ISR PktType + # s_PXENV_UNIDI_ISR end + .set PXENV_UNDI_ISR_IN_START,0x1 + + .set PXENV_UNDI_ISR_OUT_OURS,0x0 + .set PXENV_UNDI_ISR_OUT_NOT_OUTS,0x1 + + .set PXENV_UNDI_ISR,0x0014 # PXE_UNDI_ISR function + + /* interrupt registers */ + .set I8259_EOI,0x20 # EOI + .set I8259_EOI_REG,0x20 # Interrupt Control Register + .set I8259_AT_INTR_CTRL_REG,0xA0 # AT Interrupt Control Register + .set I8259_PC_INTR_MASK_REG,0x21 # PC Interrupt Mask Register + .set I8259_AT_INTR_MASK_REG,0xA1 # AT Interrupt Mask Register + + /* offsets from data_start to needed variables*/ + .set CHAINED_OFF, 0x2 # to __chained_irq_off + .set ISR_OFF, 0x8 # to s_pxenv_undi_isr + .set NIC_IRQ_OFF, 0x6 # to __pxe_nic_irq + .set USER_MEM, 0xa000 # start of user memory +# +data_start: +__pxe_isr_occured: .word 0x0000 # flagged if isr occured +__chained_irq_off: .word 0x0000 # original ISR handler offset +__chained_irq_seg: .word 0x0000 # original ISR handler segment +__pxe_nic_irq: .word 0x0000 # NIC irq number +s_pxenv_undi_isr: .word 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 + +/* + * Adopted from libi386/pxetramp.S + * pxe_call + * in: + * DX - segment of data structure, used by PXE + * AX - offset + * BX - PXE function number + * out: + * AX - 0, if call was successfull + * - not 0, in other case + */ +__pxe_call: push %dx # seg + push %ax # off + push %bx # uint16_t func no + .byte 0x9a # far call +__pxe_entry_off: + .word 0x0000 # PXE API entry point offset +__pxe_entry_seg: + .word 0x0000 # PXE API entry point segment + add $6, %sp # restore stack + .byte 0xcb + +/* + * __pxe_isr() - handles interrupt, checks is interrupt ours + * and updates __pxe_isr_occured if needed + * in: + * none + * out: + * none + */ +__pxe_isr: cli # no interrupts + pushw %ds # saving all affected registers + pushl %eax # + pushl %edi # + + movl $data_start, %edi # data_start is starting address + addl $USER_MEM, %edi # of all our data + movl %edi, %eax + shrl $4, %eax # calc segment + movw %ax, %ds # our data segment + andl $0xf, %edi # calc offset + # %ds:%di - address of start_data + + pushw %di # saving initial offset + +/* + * initing s_pxenv_undi_isr struct + */ + addw $ISR_OFF, %di # setting to s_pxenv_undi_isr + movw $0x0, %ds:UISR_STATUS(%di) # status member = 0 + # starting interrupt verification + + movw $PXENV_UNDI_ISR_IN_START, %ds:UISR_FUNC_FLAG(%di) + + pushw %ds # seg:off to s_pxenv_undi_isr + pushw %di + pushw $PXENV_UNDI_ISR # starting handling (_IN_START) + + .byte 0x9a # far call to PXE entry +__pxe_entry_off2: + .word 0x0000 # PXE API entry point offset +__pxe_entry_seg2: + .word 0x0000 # PXE API entry point segment + + add $6, %sp # restore stack + + cmpw $0, %ax # is ok? + jne pxe_isr.not_our # nope + # getting result func flag + movw %ds:UISR_FUNC_FLAG(%di), %ax + popw %di # restore offset to data_start +/* + * if interrupt not ours - just return + */ + cmpw $PXENV_UNDI_ISR_OUT_OURS, %ax # is interrupt ours? + jne pxe_isr.not_our # no + +# addw $0x0, %di # offset of __pxe_isr_occured + movw $0x1, %ds:(%di) # flagging it +/* + * sending EOI to appropriate NIC. + */ + pushw %dx + movw %ds:NIC_IRQ_OFF(%di), %ax # getting irq number + movb %al, %dl # moving it to dl + movb $I8259_EOI, %al # set EOI control word + + cmpb $0x8, %dl # is IRQ8-IRQ15? + jb pxe_isr.master # no, use pic1 + + movw $I8259_AT_INTR_CTRL_REG, %dx # send EOI to PIC2 + outb %al, %dx # + +pxe_isr.master: movw $I8259_EOI_REG, %dx # send EOI to master + outb %al, %dx # + + popw %dx + +pxe_isr.exit: popl %edi # restore affected registers + popl %eax # + popw %ds # + + sti + iret + +pxe_isr.not_our: +/* + * checking, if we have chained handler + */ + je pxe_isr.2 + /* ignore chained handler */ + popw %di # restore offset to data_start + addw $CHAINED_OFF, %di # set di for __chained_irq_off + + movw %ds:(%di), %ax # get it value + cmpw $0, %ax # have chained interrupt handler? + je pxe_isr.2 # no, we think - dont + + sti # enable interrupts + pushf # push flags + +/* + * here is calling of chained interrupt handler. + */ + pushw %es # store es register + pushw %bx + + movw %ax, %bx + movw %ds:2(%di), %es # getting segment + call *%es:(%bx) # call chained handler + + popw %bx # restore registers + popw %es # + + popf # restore flags word + + +/* from Intel PXE SDK: + * If say "not my interrupt" by passing control to next in handler list, may + * end up invoking the BIOS, which will turn off the interrupt at the PIC. + * In case this happens, on return from next-handler call, see if must restore. + * This only executes when an interrupt is fielded which is not ours to handle. + */ + +/* + * NOTE: need to understand, if it is needed + */ + +/* pushw %dx + + movw $I8259_PC_INTR_MASK_REG, %dx # use master + movw __pxe_nic_irq, %bx + cmpb $0x8, %bl # is IRQ8-IRQ15? + jb pxe_isr.1 # no + movw $I8259_AT_INTR_MASK_REG, %dx # use PIC2 + + pxe_isr.1: movb save_int_mask, %bl # get saved mask + inb %dx, %al + notb %bl + testb %bl, %al + jz pxe_isr.2 + + notb %bl + andb %bl, %al + outb %al, %dx + +*/ +pxe_isr.2: + jmp pxe_isr.exit + +/* _mem_copy() - copies memory block + * in: + * EAX - seg:off to source + * EBX - seg:off to destination + * ECX - byte count to copy + * out: + * none + */ + __mem_copy: pushw %es # store affected registers + pushw %di # + pushw %ds # + pushw %si # + pushf # store affected by cld flags + + cld # set index increment flag + + movw %ax, %si # setting source seg:off + shrl $0x10, %eax # + movw %ax, %ds # + + movw %bx, %di # setting destination seg:off + shrl $0x10, %ebx # + movw %bx, %es # + + rep movsb # copy byte by byte + + popf # restore affected registers + popw %si # + popw %ds # + popw %di # + popw %es # + + .byte 0xcb + +/* + * __isr_install() - installs interrupt handler for provided IRQ, + * saves previous ("chained") handler + * in: + * AX - interrupt number (not IRQ) + * BX - ISR segment + * DX - ISR offset + * out: + * BX - chained ISR segment + * DX - chained ISR offset + */ +__isr_install: + cli # no interrupts + pushl %edi # saving affected registers + pushw %ds # + # calc interrupt vector address + shlw $2, %ax # multiply by 4 + xorw %di, %di # clear di + movw %di, %ds # setting 0 to data segment + movw %ax, %di # di offset to interrupt vector + + xchgw %dx, %ds:(%di) # installing ISR offset + xchgw %bx, %ds:2(%di) # installing ISR segment + +/* + * Masking is not our task + * + * call mask_int # masking + */ + + popw %ds # restore affected registers + popl %edi # + sti # start interrupts + .byte 0xcb # back to vm86 + + +/* __isr_remove() - uninstalls ISR + * Adopted from Intel PXE SDK + * removes interrupt handler for provided IRQ, restores previous handler + * in: + * AX - interrupt number (not IRQ) + * BX - chained ISE offset + * out: + * none + */ +__isr_remove: pushf + pushl %ebx + + shlw $2, %bx # calculating offset of + # interrupt vector + xorw %cx, %cx # clearing segment register es + movw %cx, %es + + movw %es:(%bx), %ax # get offset to current handler + +isr_remove.3: #movl chained_irq_off, %eax # getting old chained handler + #movl %eax, %es:(%bx) # restore it + +/* + * Forget about unmasking for now + * + * call unmask_int # unmasking + **/ + +isr_remove.fin: +# movl $0x0, chained_irq_off + popl %ebx + popf + clc + ret + + +/*******************************************************************************/ + +/* __mask_irq() - masks hardware interrupt + * Adopted from Intel PXE SDK + * + * in: + * BX - IRQ number + * CX - original mask + */ +__mask_irq: pushw %dx # saving registers + pushw %cx + pushw %ax # in fact, not useful + + cmpw $0x7, %bx # see if this master PIC + jbe mask_irq.master # yes, it is PIC1 + + movw $I8259_AT_INTR_MASK_REG, %dx # setting PIC2 register + jmp mask_irq.1 + +mask_irq.master: + movw I8259_PC_INTR_MASK_REG, %dx # setting master PIC + +mask_irq.1: movw %bx, %cx + andw $0x07, %cx # mask 0..2 bits + movb $0x1, %bl # setting cl-th bit + shlb %cl, %bl # + notb %bl # + + pushf # saving FLAGS register + cli # stop interrupts + + inb %dx, %al + andb %bl, %al + + nop + nop + + outb %al, %dx + popw %ax # popping FLAGS + + testw $0x200, %ax # check interrupt flag + jz mask_irq.2 # + + sti # starting interrupts +mask_irq.2: + popw %ax + popw %cx + popw %dx + + .byte 0xcb # return + +/* + * Adopted from Intel PXE SDK + * unmasks hardware interrupt + */ +#unmask_int: pushw %ax # save all affected +# pushw %cx # registers +# pushw %dx # +# +# movw __pxe_nic_irq, %bx # getting irq number +# cmpw $0x07, %bx # is it PIC2? +# jbe unmask_int.master # no, it is master +# +# subw $0x08, %bx +# mov $I8259_AT_INTR_MASK_REG, %dx # slave PIC register +# jmp unmask_int.2 +# +#unmask_int.master: +# mov $I8259_PC_INTR_MASK_REG, %dx # master PIC register +# +#unmask_int.2: movw %bx, %cx +# andw $0x07, %cx # masking first 3 bits +# movb $0x01, %bl # +# shlb %cl, %bl # shifting 1 bit to left +# notb %bl +# +# movb %bl, save_int_mask # saving mask +# +# pushf # saving FLAGS register +# cli +# +# inb %dx, %al # sending control word +# movb %al, original_mask # saving mask +# andb %bl, %al # and it with saved +# outb %al, %dx # out result +# +# popw %ax # popping flags +# testw $0x200, %ax # IF==1 ? +# jz unmask_int.3 # yes +# sti # set IF=1 +# +#unmask_int.3: popw %dx # restore registers +# popw %cx # +# popw %ax # +# ret Index: user/sbruno/pxe_http/pxe_isr.h =================================================================== --- user/sbruno/pxe_http/pxe_isr.h (nonexistent) +++ user/sbruno/pxe_http/pxe_isr.h (revision 245442) @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_ISR_H_INCLUDED +#define PXE_ISR_H_INCLUDED + +/* + * Declarations for functions, defined in pxe_isr.s + */ + +#include + +/* 1 - if interrupt occured, 0 - means nothing to do */ +extern uint16_t __pxe_isr_occured; +/* IRQ number of NIC */ +extern uint16_t __pxe_nic_irq; +/* PXE! API entry offset, used in __pxe_call() */ +extern uint16_t __pxe_entry_off; +/* PXE! API entry segment, used in __pxe_call() */ +extern uint16_t __pxe_entry_seg; +/* PXE! API entry offset, used in __pxe_isr() */ +extern uint16_t __pxe_entry_off2; +/* PXE! API entry segment, used in __pxe_isr() */ +extern uint16_t __pxe_entry_seg2; +/* chained ISR segment:offset */ +extern uint16_t __chained_irq_seg; +extern uint16_t __chained_irq_off; + +extern void __pxe_call(void); /* PXE API call */ +extern void __pxe_isr(void); /* PXE API call */ + +extern void __mask_irq(void); /* masks irq */ +extern void __isr_install(void); /* installs handler for interrupt */ +extern void __isr_remove(void); /* remove handler, ! not working ! now */ +extern void __mem_copy(void); /* copies memory in vm86 mode */ + +#endif Index: user/sbruno/pxe_http/pxe_mem.c =================================================================== --- user/sbruno/pxe_http/pxe_mem.c (nonexistent) +++ user/sbruno/pxe_http/pxe_mem.c (revision 245442) @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_mem.h" + +void * +pxe_alloc(size_t bsize) +{ + + return malloc(bsize); +} + +void +pxe_free(void *pmem) +{ + + free(pmem); +} + +int +pxe_init_mem(void *pool, size_t size) +{ + + /* dummy */ + return (1); +} + +void +pxe_memset(void *mblock, int toset, size_t size) +{ + if (toset == 0) + bzero(mblock, size); + else + memset(mblock, toset, size); +} + + +void +pxe_memcpy(const void *from, void *to, size_t size) +{ + bcopy(from, to, size); +} Index: user/sbruno/pxe_http/pxe_mem.h =================================================================== --- user/sbruno/pxe_http/pxe_mem.h (nonexistent) +++ user/sbruno/pxe_http/pxe_mem.h (revision 245442) @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_MEM_H_INCLUDED +#define PXE_MEM_H_INCLUDED + +/* + * Contains wrappers to memory routines, needed for allocating + * and releasing memory blocks. + */ + +#include + +/* pxe_alloc() - allocates memory block of requested size + * in: + * bsize - size in bytes of requeseted memory block + * out: + * NULL - failed to allocate + * not NULL - pointer to allocated memory + */ +void *pxe_alloc(size_t bsize); + +/* pxe_free() - frees previously allocated memory block + * in: + * pmem - pointer to memory block. Attempt to free unallocated block + * may cause undefined behaviour. + * out: + * none + */ +void pxe_free(void *pmem); + +/* pxe_init_mem() - inits internal structures for memory routines + * in: + * chunk - non NULL pointer to memory address, from which starts pool, + * used to allocate memory blocks + * size - size of provided memory pool + * out: + * positive - all is ok + * 0 - failed to init structures. + */ +int pxe_init_mem(void *pool, size_t size); + +/* pxe_memset() - set specified memory block with given value + * in: + * mblock - non NULL pointer to memory block + * toset - value to set in every byte in memory block + * size - size of memory block + * out: + * none + */ +void pxe_memset(void *mblock, int toset, size_t size); + +/* pxe_memcpy() - copy memory block + * in: + * from - non NULL pointer to source memory block + * to - non NULL pointer to destination memory block + * size - size of memory block + * out: + * none + */ +void pxe_memcpy(const void *from, void *to, size_t size); + +#endif // PXE_MEM_H_INCLUDED Index: user/sbruno/pxe_http/pxe_segment.c =================================================================== --- user/sbruno/pxe_http/pxe_segment.c (nonexistent) +++ user/sbruno/pxe_http/pxe_segment.c (revision 245442) @@ -0,0 +1,754 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_buffer.h" +#include "pxe_segment.h" +#include "pxe_connection.h" +#include "pxe_core.h" +#include "pxe_ip.h" +#include "pxe_tcp.h" + +/* pxe_resend_free() - releases all used by connection structures + * in: + * connection - connection to release data + * out: + * none + */ +void +pxe_resend_free(PXE_TCP_CONNECTION *connection) +{ + /* In fact we must not do anything here due current resendeng queue + * organization(allocating segments in place), memory released in sockets + * buffer related code. But in case it'll be redone to be more effective + * or just using other segment allocation algorithm - this function may + * be needed. + */ + +#if defined(PXE_TCP_DEBUG) && defined(PXE_MORE) + tcp_resend_stats(connection); +#endif +} + +/* pxe_resend_init() - initialize buffer map for connection + * in: + * connection - connection to initialize + * out: + * none + */ +void +pxe_resend_init(PXE_TCP_CONNECTION *connection) +{ + PXE_BUFFER *buffer = connection->send; + PXE_TCP_QUEUED_SEGMENT *segment = NULL; + void *data = buffer->data; + + int all_chunks = + PXE_TCP_BLOCK_COUNT * PXE_TCP_CHUNK_COUNT; + + int chunk_index = 0; + + /* NOTE: may be it's better to define macro for all this values + * and don't calculate all_chunks and chunk_size in runtime + */ + connection->chunk_size = PXE_DEFAULT_SEND_BUFSIZE / all_chunks; + + /* marking all chunks in all blocks free */ + for ( ; chunk_index < all_chunks; ++chunk_index) { + + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + segment->status = PXE_SEGMENT_FREE; + + data += connection->chunk_size; + } + + /* zeroing block map */ + pxe_memset(connection->buf_blocks, 0, PXE_TCP_BLOCK_COUNT); +} + +/* tcp_segment_alloc() - allocates from send buffer memory for packet, + * including segment data, IP & TCP headers + * in: + * connection - connection, from which send buffer segment is + * allocated + * allocBig - 1 if need big segment, 0 otherwise + * out: + * NULL - failed to allocate memory chunk(s) for segment + * not NULL - pointer to segment structure + */ +PXE_TCP_QUEUED_SEGMENT * +tcp_segment_alloc(PXE_TCP_CONNECTION *connection, int allocBig) +{ +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_segment_alloc(): connection 0x%x, big = %d.\n", + connection, allocBig); +#endif + int block_index = 0; + PXE_BUFFER *buffer = connection->send; + uint8_t *buf_blocks = connection->buf_blocks; + void *data = NULL; + PXE_TCP_QUEUED_SEGMENT *segment = NULL; + + if (connection->send == NULL) + return (NULL); + + for ( ; block_index < PXE_TCP_BLOCK_COUNT; ++block_index) { + + /* start of block */ + data = buffer->data + + PXE_TCP_CHUNK_COUNT * block_index * connection->chunk_size; + + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + + /* alloc small packet (alloc chunk)? */ + if (allocBig == PXE_SEGMENT_SMALL) { + /* checking if block is not fully used */ + if (buf_blocks[block_index] < PXE_TCP_BLOCK_USED) { + /* search free chunk in block */ + int chunk_index = 0; + + for ( ; chunk_index < PXE_TCP_CHUNK_COUNT; ++chunk_index) { + + if (segment->status == PXE_SEGMENT_FREE) { + + segment->status = PXE_SEGMENT_USED; + buf_blocks[block_index] += 1; + + return (segment); + } + + /* next chunk in block */ + data += connection->chunk_size; + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + } + } + + } else { /* alloc big one (entire block) */ + + if (buf_blocks[block_index] == PXE_TCP_BLOCK_FREE) { + + buf_blocks[block_index] = PXE_TCP_BLOCK_EXCLUSIVE; + segment->status = PXE_SEGMENT_USED; + + return (segment); + } + } + } /* block_index for end */ + + return (NULL); +} + +/* pxe_segment_free() - releases used by segment chunks + * in: + * connection - connection to release chunks + * block_index - index of block to which chunk belongs + * segment - segment to release + * out: + * none + */ +void +tcp_segment_free(PXE_TCP_CONNECTION *connection, int block_index, + PXE_TCP_QUEUED_SEGMENT *segment) +{ +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_segment_free(): connection: 0x%x, block: %d, chunk: 0x%x\n", + connection, block_index, segment); +#endif + uint8_t *block = &connection->buf_blocks[block_index]; + + if (segment->status == PXE_SEGMENT_FREE) /* already released */ + return; + + segment->status = PXE_SEGMENT_FREE; + + /* check if block is exlusively used */ + if ( *block == PXE_TCP_BLOCK_EXCLUSIVE) + *block = PXE_TCP_BLOCK_FREE; + else /* update used chunk count */ + *block -= 1; +} + +/* pxe_resend_check() - checks if need to resend segment + * in: + * connection - connection to check resending needs for + * out: + * none + */ +void +pxe_resend_check(PXE_TCP_CONNECTION *connection) +{ +#ifdef PXE_TCP_DEBUG + printf("pxe_resend_check(): started, state %d.\n", connection->state); +#endif + PXE_BUFFER *buffer = connection->send; + void *data = buffer->data; + int block_index = 0; + PXE_TCP_QUEUED_SEGMENT *segment = NULL; + uint8_t *buf_blocks = connection->buf_blocks; + + time_t cur_time = pxe_get_secs(); + + for ( ; block_index < PXE_TCP_BLOCK_COUNT; ++block_index) { + + if (buf_blocks[block_index] == PXE_TCP_BLOCK_FREE) + continue; /* block is unused */ + + /* pointer to head chunk of block */ + data = buffer->data + + block_index * PXE_TCP_CHUNK_COUNT * connection->chunk_size; + + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + + /* block is used exclusevely by one "big" packet */ + if (buf_blocks[block_index] == PXE_TCP_BLOCK_EXCLUSIVE) { + + if (segment->status != PXE_SEGMENT_SENT) + continue; /* it was not ever sent yet */ + + /* check if it's time to resend */ + if (cur_time >= segment->resend_at) { +#ifdef PXE_TCP_DEBUG_HELL + printf("pxe_resend_check(): %lu:%lu " + "resending (next try at: %lu)\n", + segment->resend_at, cur_time, + cur_time + + PXE_RESEND_TIME * (segment->trys + 1)); +#endif + segment->trys += 1; + + segment->resend_at = cur_time + + PXE_RESEND_TIME * segment->trys; + + if (segment->trys == PXE_RESEND_TRYS) { + /* TODO: need to break connection */ + } + + tcp_update_segment(connection, segment); + pxe_tcp_send_segment(connection, segment); + + } + continue; + } + + /* block is dirty, need to check chunks manually */ + int chunk_index = 0; + + for ( ; chunk_index < PXE_TCP_CHUNK_COUNT; ++chunk_index) { + + if (segment->status == PXE_SEGMENT_SENT) { + /* check time to resend */ + if (cur_time >= segment->resend_at) { +#ifdef PXE_TCP_DEBUG_HELL + printf("pxe_resend_check(): %lu:%lu " + "resending (next try at: %lu)\n", + segment->resend_at, cur_time, + cur_time + + PXE_RESEND_TIME * (segment->trys + 1)); +#endif + /* resend later, with more delay + * with every try */ + segment->trys += 1; + + segment->resend_at = cur_time + + PXE_RESEND_TIME * segment->trys; + + if (segment->trys == PXE_RESEND_TRYS) { + /* TODO: need to break connection */ + } + + tcp_update_segment(connection, segment); + pxe_tcp_send_segment(connection, segment); + } + } + + /* point segment to next chunk */ + data += connection->chunk_size; + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + } + } /* block_index for end */ +} + +/* pxe_resend_drop_same() - removes from resend queue older segments with same + * sequence number to avoid duplicate resending of same + * ACKs and etc. + * in: + * connection - connection to update segments for + * segment - segment to check with + * out: + * none + */ +void +pxe_resend_drop_same(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *new_segment) +{ +#ifdef PXE_TCP_DEBUG + printf("pxe_resend_drop_same(): started.\n"); +#endif + if (connection->send == NULL) { + printf("pxe_resend_drop_same(): send buffer is NULL.\n"); + return; + } + + uint32_t drop_seq = new_segment->seq; + PXE_BUFFER *buffer = connection->send; + void *data = buffer->data; + int block_index = 0; + PXE_TCP_QUEUED_SEGMENT *segment = NULL; + uint8_t *buf_blocks = connection->buf_blocks; + + for ( ; block_index < PXE_TCP_BLOCK_COUNT; ++block_index) { + + /* block is used exclusevely by one "big" packet, skip this */ + if (buf_blocks[block_index] == PXE_TCP_BLOCK_EXCLUSIVE) + continue; + + if (buf_blocks[block_index] == PXE_TCP_BLOCK_FREE) + continue; /* block is unused */ + + /* pointer to head chunk of block */ + data = buffer->data + + block_index * PXE_TCP_CHUNK_COUNT * connection->chunk_size; + + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + + if (segment == new_segment) + continue; + + /* block is dirty, need to check chunks manually */ + int chunk_index = 0; + + for ( ; chunk_index < PXE_TCP_CHUNK_COUNT; ++chunk_index) { + /* skip segment if it's new_segment */ + if (segment == new_segment) + continue; + + if ( (segment->status != PXE_SEGMENT_FREE) && + (segment->seq == drop_seq) ) + { /* this segment is updated by new segment */ +#ifdef PXE_TCP_DEBUG_HELL + printf("pxe_resend_drop_same(): drop chunk %d#%d.\n", + chunk_index, block_index); +#endif + tcp_segment_free(connection, block_index, + segment); + } + + /* point segment to next chunk */ + data += connection->chunk_size; + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + } + } +} + +/* pxe_resend_update() - update segments that were acked + * in: + * connection - connection to update segments for + * out: + * none + */ +void +pxe_resend_update(PXE_TCP_CONNECTION *connection) +{ +#ifdef PXE_TCP_DEBUG_HELL + printf("pxe_resend_update(): started.\n"); +#endif + PXE_BUFFER *buffer = connection->send; + void *data = buffer->data; + int block_index = 0; + PXE_TCP_QUEUED_SEGMENT *segment = NULL; + + for ( ; block_index < PXE_TCP_BLOCK_COUNT; ++block_index) { + + if (connection->buf_blocks[block_index] == PXE_TCP_BLOCK_FREE) + continue; /* block is unused */ + + /* pointer to head chunk of block */ + data = buffer->data + + block_index * PXE_TCP_CHUNK_COUNT * connection->chunk_size; + + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + + /* block is used exclusevely by one "big" packet */ + if (connection->buf_blocks[block_index] == PXE_TCP_BLOCK_EXCLUSIVE) { + + if (segment->status != PXE_SEGMENT_SENT) + continue; /* it was not ever sent yet */ + + if (connection->una >= segment->seq) { + /* segment was acked, release it */ +#ifdef PXE_TCP_DEBUG_HELL + printf("pxe_resend_update(): block %d acked.\n", + block_index); +#endif + tcp_segment_free(connection, block_index, + segment); + } + continue; + } + + /* block is dirty, need to check chunks manually */ + int chunk_index = 0; + + for ( ; chunk_index < PXE_TCP_CHUNK_COUNT; ++chunk_index) { + + if (segment->status == PXE_SEGMENT_SENT) { + + if (connection->una >= segment->seq) { + /* segment was acked */ +#ifdef PXE_TCP_DEBUG_HELL + printf("pxe_resend_update(): chunk %d@%d acked.\n", + chunk_index, block_index); +#endif + tcp_segment_free(connection, block_index, + segment); + } + } + + /* point segment to next chunk */ + data += connection->chunk_size; + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + } + } +} + +/* pxe_start_segment() - fills initial data in headers for provided segment + * in: + * connection - connection to update segments for + * segment - segment to start + * add_options - 1 if add default options (mss), 0 - don't add anything + * out: + * none + */ +void +tcp_start_segment(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment, int add_options) +{ + if (segment == NULL) { + printf("tcp_start_segment(): segment = NULL.\n"); + return; + } + + PXE_TCP_PACKET *tcp_packet = (PXE_TCP_PACKET *)(segment + 1); + + /* reserving 8 bytes for options */ + uint16_t length = sizeof(PXE_TCP_PACKET); + + tcp_packet->tcphdr.src_port = htons(connection->src_port); + tcp_packet->tcphdr.dst_port = htons(connection->dst_port); + tcp_packet->tcphdr.checksum = 0; + tcp_packet->tcphdr.sequence = htonl(connection->next_send); + tcp_packet->tcphdr.data_off = sizeof(PXE_TCP_HDR); + + if (add_options == PXE_SEGMENT_OPTS_DEFAULT) { + /* reserving 8 bytes for options */ + length += 8; + tcp_packet->tcphdr.data_off += 8; + + /* pointing to options, leading tcp_header */ + PXE_TCP_DEFAULT_OPTIONS *options = + (PXE_TCP_DEFAULT_OPTIONS *)(tcp_packet + 1); + + pxe_memset(options, 0, sizeof(PXE_TCP_DEFAULT_OPTIONS)); + + options->kind = 2; + options->size = 4; + options->mss = htons(PXE_TCP_MSS); + } + + tcp_packet->tcphdr.data_off = (tcp_packet->tcphdr.data_off / 4) << 4; + tcp_packet->tcphdr.urgent = 0; + + segment->trys = 0; + segment->resend_at = 0; + segment->size = length; + segment->seq = connection->next_send; +} + +/* pxe_finish_segment() - finishes segmentm calculates checksums and fills + * sequence numbers + * in: + * connection - connection to update segments for + * segment - segment to start + * tcp_flags - flags of header (PXE_TCP_...) + * out: + * none + */ +void +tcp_finish_segment(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment, uint8_t tcp_flags) +{ + if (segment == NULL) { + printf("tcp_finish_segment(): segment = NULL.\n"); + return; + } + + PXE_TCP_PACKET *tcp_packet = (PXE_TCP_PACKET *)(segment + 1); + + uint16_t length = segment->size - sizeof(PXE_IP_HDR); + + tcp_packet->tcphdr.ack_next = htonl(connection->next_recv); + tcp_packet->tcphdr.flags = tcp_flags; + + PXE_BUFFER *recv_buffer = connection->recv; + + /* set window size to free buffer space size, + * or to zero if recv_buffer == NULL + */ + tcp_packet->tcphdr.window_size = (recv_buffer != NULL) ? + htons(recv_buffer->bufleft) : 0; + tcp_packet->tcphdr.checksum = 0; + + PXE_IP4_PSEUDO_HDR pseudo_hdr; + const PXE_IPADDR *my = pxe_get_ip(PXE_IP_MY); + + pseudo_hdr.src_ip = my->ip; + pseudo_hdr.dst_ip = connection->dst.ip; + pseudo_hdr.zero = 0; + pseudo_hdr.proto = PXE_TCP_PROTOCOL; + pseudo_hdr.length = htons(length); + + /* adding pseudo header checksum to checksum of tcp header with data + * and make it complimentary + */ + uint16_t part1 = pxe_ip_checksum(&pseudo_hdr, + sizeof(PXE_IP4_PSEUDO_HDR)); + + uint16_t part2 = pxe_ip_checksum(&tcp_packet->tcphdr, length); + + uint32_t tmp_sum = ((uint32_t)part1) + ((uint32_t)part2); + + if (tmp_sum & 0xf0000) /* need carry out */ + tmp_sum -= 0xffff; + + tcp_packet->tcphdr.checksum = ~((uint16_t)(tmp_sum & 0xffff)); + + /* special case */ + if (tcp_packet->tcphdr.checksum == 0) + tcp_packet->tcphdr.checksum = 0xffff; + + /* setting sequence number next to the segment last byte + * when connection->una become this value we must remove packet + * from resend queue. + */ + segment->seq += (length - 4 * (tcp_packet->tcphdr.data_off >> 4)); + +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_finish_segment(): checksum 0x%4x for %d bytes\n", + tcp_packet->tcphdr.checksum, length); +#endif +} + +/* pxe_update_segment() - updates segment at resending, recalcs checksum + * for updated header + * in: + * connection - connection to update segments for + * segment - segment to start + * out: + * none + */ +void +tcp_update_segment(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment) +{ + if (segment == NULL) { + printf("tcp_update_segment(): segment = NULL.\n"); + return; + } + + PXE_TCP_PACKET *tcp_packet = (PXE_TCP_PACKET *)(segment + 1); + + uint16_t length = segment->size - sizeof(PXE_IP_HDR); + + tcp_packet->tcphdr.ack_next = htonl(connection->next_recv); + + PXE_BUFFER *recv_buffer = connection->recv; + + /* set window size to free buffer space size, + * or to zero if recv_buffer == NULL + */ + tcp_packet->tcphdr.window_size = (recv_buffer != NULL) ? + htons(recv_buffer->bufleft) : 0; + tcp_packet->tcphdr.checksum = 0; + + PXE_IP4_PSEUDO_HDR pseudo_hdr; + const PXE_IPADDR *my = pxe_get_ip(PXE_IP_MY); + + pseudo_hdr.src_ip = my->ip; + pseudo_hdr.dst_ip = connection->dst.ip; + pseudo_hdr.zero = 0; + pseudo_hdr.proto = PXE_TCP_PROTOCOL; + pseudo_hdr.length = htons(length); + + /* adding pseudo header checksum to checksum of tcp header with data + * and make it complimentary + */ + uint16_t part1 = pxe_ip_checksum(&pseudo_hdr, + sizeof(PXE_IP4_PSEUDO_HDR)); + + uint16_t part2 = pxe_ip_checksum(&tcp_packet->tcphdr, length); + + uint32_t tmp_sum = ((uint32_t)part1) + ((uint32_t)part2); + + if (tmp_sum & 0xf0000) /* need carry out */ + tmp_sum -= 0xffff; + + tcp_packet->tcphdr.checksum = ~((uint16_t)(tmp_sum & 0xffff)); + + /* special case */ + if (tcp_packet->tcphdr.checksum == 0) + tcp_packet->tcphdr.checksum = 0xffff; + +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_update_segment(): checksum 0x%4x for %d bytes\n", + tcp_packet->tcphdr.checksum, length); +#endif +} + +/* pxe_tcp_send_segment() - send data segment via TCP protocol + * in: + * connection - connection to which segment belongs + * segment - segment to send + * out: + * 0 - failed + * 1 - success + */ +int +pxe_tcp_send_segment(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment) +{ + if (segment == NULL) { + printf("pxe_tcp_send_segment(): segment = NULL.\n"); + return (0); + } + + PXE_TCP_PACKET *tcp_packet = (PXE_TCP_PACKET *)(segment + 1); + + if (!pxe_ip_send(tcp_packet, &connection->dst, + PXE_TCP_PROTOCOL, segment->size)) + { + printf("pxe_tcp_send_segment(): failed send tcp packet to %s\n", + inet_ntoa(connection->dst.ip)); + + return (0); + } + + /* mark segment to be checked in resend and update calls*/ + segment->status = PXE_SEGMENT_SENT; + +#ifdef PXE_TCP_DEBUG + const PXE_IPADDR *from = pxe_get_ip(PXE_IP_MY); + + printf("pxe_tcp_send_segment(): tcp packet from %s:%u to ", + inet_ntoa(from->ip), connection->src_port); + + printf("%s:%u\n next seq %lu", + inet_ntoa(connection->dst.ip), connection->dst_port, + connection->next_send - connection->iss); + + uint8_t flags = tcp_packet->tcphdr.flags; + + if (flags & PXE_TCP_FIN) + printf(" fin,"); + + if (flags & PXE_TCP_SYN) + printf(" syn,"); + + if (flags & PXE_TCP_RST) + printf(" rst,"); + + if (flags & PXE_TCP_ACK) + printf(" ack %lu,", connection->next_recv - connection->irs); + + if (flags & PXE_TCP_URG) + printf(" urg,"); + + if (flags & PXE_TCP_URG) + printf(" psh,"); + + uint16_t length = segment->size - sizeof(PXE_IP_HDR) - + 4 * (tcp_packet->tcphdr.data_off >> 4); + + printf(" %lu bytes.\n", length); +#endif + return (1); +} + +#ifdef PXE_MORE +/* tcp_resend_stats() - shows statistics for chunks in resend queue + * in: + * connection - which connection's resend queue to show + * out: + * none + */ +void +tcp_resend_stats(PXE_TCP_CONNECTION *connection) +{ + int block_index = 0; + PXE_BUFFER *buffer = connection->send; + uint8_t *buf_blocks = connection->buf_blocks; + void *data = NULL; + PXE_TCP_QUEUED_SEGMENT *segment = NULL; + + printf("pxe_resend_stats(): stats for connection 0x%x\n", connection); + + for ( ; block_index < PXE_TCP_BLOCK_COUNT; ++block_index) { + + /* start of block */ + data = buffer->data + + PXE_TCP_CHUNK_COUNT * block_index * connection->chunk_size; + + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + + if (buf_blocks[block_index] != PXE_TCP_BLOCK_FREE) { + + if (buf_blocks[block_index] != PXE_TCP_BLOCK_EXCLUSIVE) { + /* search free chunk in block */ + int chunk_index = 0; + + for ( ; chunk_index < PXE_TCP_CHUNK_COUNT; ++chunk_index) { + + if (segment->status != PXE_SEGMENT_FREE) { + + printf("\tchunk %d@%d awaiting %lu ack.\n", + chunk_index, block_index, + segment->seq - connection->iss); + } + + /* next chunk in block */ + data += connection->chunk_size; + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + } + + } else { + printf("pxe_resend_stats(): block %d awaiting %lu ack.\n", + block_index, segment->seq - connection->iss); + } /* check exclusive end*/ + } /* check free end */ + } /* cycle end */ +} +#endif Index: user/sbruno/pxe_http/pxe_segment.h =================================================================== --- user/sbruno/pxe_http/pxe_segment.h (nonexistent) +++ user/sbruno/pxe_http/pxe_segment.h (revision 245442) @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_SEGMENT_INCLUDED +#define PXE_SEGMENT_INCLUDED + +/* + * Contains functions to send/resend tcp segments + */ + +#include + +#include "pxe_connection.h" + +/* free status for segment */ +#define PXE_SEGMENT_FREE 0x00 +/* segment is used, e.g. data is written to it */ +#define PXE_SEGMENT_USED 0x01 +/* segment is filled with data, sent but not ACKed yet */ +#define PXE_SEGMENT_SENT 0x02 +/* default resend time if not acked, in seconds */ +#define PXE_RESEND_TIME 1 +/* default resend trys */ +#define PXE_RESEND_TRYS 5 + +/* how much blocks in buffer */ +#define PXE_TCP_BLOCK_COUNT 8 +/* how much chunks in one block */ +#define PXE_TCP_CHUNK_COUNT 8 + +/* chunk is unused */ +#define PXE_TCP_BLOCK_FREE 0x00 +/* 1..(PXE_TCP_CHUNK_COUNT - 1) are dirty flags, partially used block */ +#define PXE_TCP_BLOCK_USED PXE_TCP_CHUNK_COUNT +/* block is entirely owned by one segment */ +#define PXE_TCP_BLOCK_EXCLUSIVE 0x80 + +/* resend queue in this project organized as just a bunch of segments. + * to update queue it's needed to check all used chunks. + * buffer is divided in PXE_TCP_BLOCK_COUNT blocks, each block divided + * in PXE_TCP_CHUNK_COUNT chunks, so by default we have 64 chunks at all + * with size 64 bytes for each (for default buffer size 4096) + * packets may be "small" (e.g. system packets ACK, RST and etc) and contain + * no user data. In such case usualy will be enough one chunk for packet + * sizeof(iphdr+tcphdr) = 40 bytes + options < 52 = 64 - sizeof(tcp_queue_segment) + * also packets may be "big", but not bigger than + * one block size - sizeof(tcp_queue_segment) + * in such case packet exclusevely uses all chunks in block for own purposes. + * by default this means 500 bytes packet maximum (or about 460 bytes of + * user data per packet). For client-side usage this must be enough in + * this project + */ + +typedef struct pxe_tcp_queued_segment { + uint32_t seq; /* sequence number */ + uint32_t resend_at; /* time to ressend at */ + uint16_t size; /* size of ready to send packet */ + uint8_t trys; /* how many resend trys were done */ + uint8_t status; /* segment status */ +} PXE_TCP_QUEUED_SEGMENT; + + + +/* checks if need to resend some segments of connection */ +void pxe_resend_check(PXE_TCP_CONNECTION *connection); + +/* updates resend queue, removes ACKed segments */ +void pxe_resend_update(PXE_TCP_CONNECTION *connection); + +/* removes segments that are dublicates or old versions of new segment */ +void pxe_resend_drop_same(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment); + +/* destroys resend queue */ +void pxe_resend_free(PXE_TCP_CONNECTION *connection); + +/* inits buffer map of connection */ +void pxe_resend_init(PXE_TCP_CONNECTION *connection); + +/* sends chhosed segment to adrressee */ +int pxe_tcp_send_segment(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment); + +#define PXE_SEGMENT_BIG 1 +#define PXE_SEGMENT_SMALL 0 +/* allocates in buffer space segment */ +PXE_TCP_QUEUED_SEGMENT *tcp_segment_alloc(PXE_TCP_CONNECTION *connection, + int allocBig); + +/* releases memory used by segment */ +void tcp_segment_free(PXE_TCP_CONNECTION *connection, int block_index, + PXE_TCP_QUEUED_SEGMENT *segment); + +#define PXE_SEGMENT_OPTS_DEFAULT 1 +#define PXE_SEGMENT_OPTS_NO 0 +/* fills most of fields of tcp header of segment */ +void tcp_start_segment(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment, int add_options); + +/* finishes filling of tcp header, adds checksum */ +void tcp_finish_segment(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment, uint8_t tcp_flags); + +/* when resending updates ack and checksum */ +void tcp_update_segment(PXE_TCP_CONNECTION *connection, + PXE_TCP_QUEUED_SEGMENT *segment); + +/* when resending updates ack and checksum */ +void tcp_resend_stats(PXE_TCP_CONNECTION *connection); + +#endif Index: user/sbruno/pxe_http/pxe_sock.c =================================================================== --- user/sbruno/pxe_http/pxe_sock.c (nonexistent) +++ user/sbruno/pxe_http/pxe_sock.c (revision 245442) @@ -0,0 +1,862 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_await.h" +#include "pxe_buffer.h" +#include "pxe_core.h" +#include "pxe_filter.h" +#include "pxe_mem.h" +#include "pxe_sock.h" +#include "pxe_tcp.h" +#include "pxe_udp.h" + +/* storage for socket describing structures */ +static PXE_SOCKET pxe_sockets[PXE_DEFAULT_SOCKETS]; +/* next available local port to use */ +static uint16_t avail_port = 1025; + +/* pxe_socket_init() - initialization of socket module + * in/out: + * none + */ +void +pxe_socket_init() +{ + + pxe_memset(pxe_sockets, 0, sizeof(pxe_sockets)); +} + +/* pxe_socket_alloc() - allocates new socket describing structure + * in: + * none + * out: + * -1 - failed + * nonnegative - success + */ +int +pxe_socket_alloc() +{ + int sock_index = 0; + + /* searching free sockets */ + for (; sock_index < PXE_DEFAULT_SOCKETS; ++sock_index) { + + if (pxe_sockets[sock_index].state == PXE_SOCKET_FREE) { + /* found free socket */ + pxe_memset(&pxe_sockets[sock_index], 0, + sizeof(PXE_SOCKET)); + + pxe_sockets[sock_index].state = PXE_SOCKET_USED; + + return sock_index; + } + } + + return (-1); /* no socket found :( */ +} + +/* pxe_socket_free() - releases socket describing structure + * in: + * socket - socket descriptor + * out: + * 0 - failed + * 1 - success + */ +int +pxe_socket_free(int socket) +{ + PXE_SOCKET *sock = &pxe_sockets[socket]; + + sock->state = PXE_SOCKET_FREE; + pxe_buffer_memfree(&sock->recv_buffer); + pxe_buffer_memfree(&sock->send_buffer); + + return (1); +} + +/* pxe_socket() - creates new socket + * in: + * none + * out: + * -1 - failed + * nonnegative - success + */ +int +pxe_socket() +{ + int socket = pxe_socket_alloc(); + + /* allocating structure */ + if (socket == -1) + return (-1); + +#ifdef PXE_DEBUG + printf("pxe_socket(): initing socket %d.\n", socket); +#endif + /* creating buffers */ + PXE_BUFFER *rbuf = &pxe_sockets[socket].recv_buffer; + PXE_BUFFER *sbuf = &pxe_sockets[socket].send_buffer; + + if (!pxe_buffer_memalloc(sbuf, PXE_DEFAULT_SEND_BUFSIZE)) { + + pxe_socket_free(socket); + return (-1); + } + + if (!pxe_buffer_memalloc(rbuf, PXE_DEFAULT_RECV_BUFSIZE)) { + + pxe_socket_free(socket); + return (-1); + } +#ifdef PXE_DEBUG + printf("pxe_socket(): socket %d created.\n", socket); +#endif + return (socket); +} + +/* pxe_close() - closes socket + * in: + * socket - socket descriptor number + * out: + * 0 - failed + * 1 - success + */ +int +pxe_close(int socket) +{ +#ifdef PXE_DEBUG + printf("pxe_close(): closing socket %d\n", socket); +#endif +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_close(): invalid socket %d\n", socket); + return (0); + } +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + + if (sock->state == PXE_SOCKET_FREE) { +#ifdef PXE_DEBUG + printf("pxe_close(): socket %d already closed.\n", socket); +#endif + return (0); + } + + PXE_FILTER_ENTRY *filter = sock->filter; + /* flush data in buffers */ + pxe_flush(socket); + + if (filter == NULL) { /* sanity check */ +#ifdef PXE_DEBUG + printf("pxe_close(): filter is NULL.\n"); +#endif + return (0); + } + + /* UDP socket closing is simple */ + if (filter->protocol == PXE_UDP_PROTOCOL) { + + if (filter != NULL) + pxe_filter_remove(sock->filter); +#ifdef PXE_DEBUG + else + printf("pxe_close(): filter for socket already NULL.\n"); +#endif + } else /* filter removing is done in check_time_to_die() */ + pxe_tcp_disconnect(sock); + +#ifdef PXE_DEBUG + printf("pxe_close(): closed\n"); +#endif + return pxe_socket_free(socket); +} + +#ifdef PXE_MORE +/* pxe_listen() - setups filter for socket and waits new connections + * in: + * socket - socket descriptor number + * proto - IP stack protocol number + * port - local port to listen connections on + * out: + * -1 - if failed + * nonnegative - number of waiting connections + */ +int +pxe_listen(int socket, uint8_t proto, uint16_t port) +{ +#ifdef PXE_DEBUG + printf("pxe_listen(): proto 0x%x, port: %d.\n", proto, port); +#endif + const PXE_IPADDR* to = pxe_get_ip(PXE_IP_MY); + + PXE_FILTER_ENTRY *filter = pxe_filter_add(0, 0, to, + port, &pxe_sockets[socket], proto); + + if (filter == NULL) { +#ifdef PXE_DEBUG + printf("pxe_listen(): failed to add filter.\n"); +#endif + return (-1); + } + + pxe_filter_mask(filter, 0, 0, 0xffffffff, 0xffff); + + pxe_sockets[socket].filter = filter; + + if (proto == PXE_UDP_PROTOCOL) { /* for UDP it's fake listen */ + return (socket); + } + + while (pxe_sockets[socket].waiting == 0) { +#ifdef PXE_DEBUG + twiddle(); +#endif + if (!pxe_core_recv_packets()) { + delay(100000); + } + } + + return (pxe_sockets[socket].waiting); +} + +/* pxe_accept() - accepts connections for listening socket and + * returns accepted socket + * in: + * socket - listening socket + * out: + * -1 - failed + * nonnegative - newly created socket descriptor number + */ +int +pxe_accept(int socket) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + return (-1); + } +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + + if (sock->waiting == 0) + return (-1); + + int back = sock->waiting; + + PXE_FILTER_ENTRY *entry = sock->filter; + + for ( ; back != 0; --back) { + + /* filter childs are earlier */ + entry = entry->prev; + + if (entry == NULL) { +#ifdef PXE_DEBUG + printf("pxe_accept(): corrupted waiting count.\n"); +#endif + return (-1); + } + } + + int accepted_socket = pxe_socket(); + + if (accepted_socket == -1) + return (-1); + + /* decreasing waiting queue */ + --sock->waiting; + + sock = &pxe_sockets[accepted_socket]; + + sock->filter = entry; + entry->socket = sock; + + return (accepted_socket); +} + +/* pxe_sock_stats() - show active sockets information + * in/out: + * none + */ +void +pxe_sock_stats() +{ + int socket = 0; + PXE_SOCKET* sock = pxe_sockets; + + for ( ; socket < PXE_DEFAULT_SOCKETS; ++socket, ++sock) { + + if (sock->state == PXE_SOCKET_FREE) + continue; + + printf("%d: filter 0x%x, recv/sent: %d/%d, waiting: %d.\n", + socket, sock->filter, sock->recv, sock->sent, sock->waiting); + } +} +#endif /* PXE_MORE */ + +/* pxe_next_port() - returns local port + * in: + * none + * out: + * 0 - no free port + * >0 - port number + */ +uint16_t +pxe_next_port() +{ /* dummy, TODO: check filters, if port used */ + + if (avail_port == 40000) + avail_port = 1025; + + return (avail_port++); +} + +/* NOTE: now assuming that only UDP is implemented */ +/* pxe_sendto() - sends data to chosen ip:port, connecting socket if needed + * in: + * socket - socket descriptor number + * dst - IP address to send to + * port - remote port + * data - data buffer to send + * size - size of data buffer + * out: + * -1 - failed + * nonnegative - actual bytes sended + */ +int +pxe_sendto(int socket, const PXE_IPADDR *dst, uint16_t port, void *data, + uint16_t size) +{ + + if (size + sizeof(PXE_UDP_PACKET) > PXE_DEFAULT_SEND_BUFSIZE) { + printf("pxe_sendto(): send buffer too small for %u bytes.\n", + size); + + return (-1); + } + + PXE_SOCKET *sock = &pxe_sockets[socket]; + + if ( sock->state == PXE_SOCKET_BINDED) { + /* if socket binded filter must not be NULL, + * cause pxe_bind() installs filter + */ + if (sock->filter == NULL) { + printf("pxe_sendto(): NULL filter for binded socket %d.\n", + socket); + + return (-1); + } + + } else { /* not binded, connect */ + + /* NOTE: if it's already connected, return error */ + if (pxe_connect(socket, dst, port, PXE_UDP_PROTOCOL) == -1) { + printf("pxe_sendto(): failed to connect.\n"); + return (-1); + } + } + + PXE_FILTER_ENTRY *filter = sock->filter; + + /* for UDP socket, send buffer used only for one dgram */ + PXE_UDP_PACKET *udp_pack = (PXE_UDP_PACKET *)sock->send_buffer.data; + + /* copy user data */ + pxe_memcpy(data, udp_pack + 1, size); + + /* filters are useful for incoming packet, so dst_port + * is local port. It's always set on this step (both for binded and + * connected sockets). for binded sockets pxe_connect() skipped, so + * need manually call pxe_next_port() to get local port (don't use + * binded local port, it seems correct behaviour) + */ + uint16_t lport = filter->dst_port; + +#ifdef PXE_DEBUG + printf("pxe_sendto(): %8x:%u -> %8x:%u, size = %u bytes.\n", + (pxe_get_ip(PXE_IP_MY))->ip, lport, dst->ip, port, size); +#endif + + if (!pxe_udp_send(udp_pack, dst, port, lport, + size + sizeof(PXE_UDP_PACKET))) + { + printf("pxe_sendto(): failed to send data.\n"); + return (-1); + } + + return (size); +} + +/* pxe_connect() - connect to remote ip:port + * in: + * socket - socket descriptor number + * dst - IP address to connect to + * port - remote port to connect to + * proto - IP stack protocol + * out: + * -1 - failed + * 0 - success + */ +int +pxe_connect(int socket, const PXE_IPADDR *dst, uint16_t port, uint8_t proto) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + return (-1); + } +#endif +#ifdef PXE_DEBUG + printf("pxe_connect(): started\n"); +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + + if (sock->state >= PXE_SOCKET_CONNECTED) { + printf("pxe_connect(): socket %d already connected.\n", socket); + return (-1); + } + + /* socket was already initalized */ + if (sock->filter != NULL) { + + pxe_filter_remove(sock->filter); + sock->filter = NULL; /* just to be sure... */ + } + + uint16_t lport = pxe_next_port(); /* getting free local port */ + + if (port == 0) { + printf("pxe_connect(): failed to allocate local port.\n"); + return (-1); + } + + PXE_FILTER_ENTRY *entry = pxe_filter_add(dst, port, + pxe_get_ip(PXE_IP_MY), + lport, sock, proto); + + if (entry == NULL) { + + /* try to get free filter from inactive connections */ + if (proto == PXE_TCP_PROTOCOL) { +#ifdef PXE_DEBUG + printf("pxe_connect(): forcing filter release\n"); +#endif + pxe_force_filter_release(); + entry = pxe_filter_add(dst, port, pxe_get_ip(PXE_IP_MY), + lport, sock, proto); + } + + if (entry == NULL) { + printf("pxe_connect(): failed to add filter.\n"); + return (-1); + } + } + + sock->filter = entry; + sock->state = PXE_SOCKET_CONNECTED; + + if (proto == PXE_TCP_PROTOCOL) { + /* trying handshaking */ + if (pxe_tcp_connect(sock)) { + sock->state = PXE_SOCKET_ESTABLISHED; + } else { /* failed, cleanup */ + pxe_filter_remove(entry); + return (-1); + } + } + +#ifdef PXE_DEBUG + printf("pxe_connect(): socket %d connected, 0x%x:%u -> 0x%x:%u\n", + socket, (pxe_get_ip(PXE_IP_MY))->ip, lport, dst->ip, port); +#endif + /* all is ok */ + return (0); +} + +/* pxe_send() - send data to socket + * in: + * socket - socket descriptor number to send data to + * buf - buffer with data to send + * buflen - size of buffer + * out: + * -1 - failure + * nonnegative - actual count of bytes sent + */ +int +pxe_send(int socket, void *buf, uint16_t buflen) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_send(): invalid socket %d.\n", socket); + return (-1); + } +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + PXE_FILTER_ENTRY *filter = sock->filter; + int result = -1; + + if (filter == NULL) { +#ifdef PXE_DEBUG + printf("pxe_send(): NULL filter\n"); +#endif + return (-1); + } + + if (filter->protocol == PXE_UDP_PROTOCOL) + result = pxe_udp_write(sock, buf, buflen); + + else if (filter->protocol == PXE_TCP_PROTOCOL) + result = pxe_tcp_write(sock, buf, buflen); + + else + printf("pxe_send(): only TCP and UDP sockets are implemented\n"); + + if (result > 0) + sock->sent += result; + + return (result); +} + +/* pxe_recv() - receive data to socket + * in: + * socket - socket descriptor number to recieve data from + * tobuf - buffer to receive data to + * buflen - size of buffer + * flags - PXE_SOCK... flags + * out: + * -1 - failure + * nonnegative - actual count of bytes received + */ +int +pxe_recv(int socket, void *tobuf, uint16_t buflen, int flags) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_recv(): invalid socket %d.\n", socket); + return (-1); + } +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + PXE_FILTER_ENTRY *filter = sock->filter; + + if (filter == NULL) { +#ifdef PXE_DEBUG + printf("pxe_recv(): NULL filter\n"); +#endif + return (-1); + } + + if ( (filter->protocol != PXE_UDP_PROTOCOL) && + (filter->protocol != PXE_TCP_PROTOCOL) ) + { + printf("pxe_recv(): only TCP and UDP sockets are implemented\n"); + return (-1); + } + + uint32_t timer = 0; +#ifdef PXE_TCP_AGRESSIVE + uint32_t check_timer = 0; +#endif + int result = 0; + + while (1) { + + if (filter->protocol == PXE_UDP_PROTOCOL) { + + result = pxe_udp_read(sock, tobuf, buflen, NULL); + + } else { + + result = pxe_tcp_read(sock, tobuf, buflen); + } + + if ((result != 0) || (flags == PXE_SOCK_NONBLOCKING)) + break; + + if (timer > PXE_SOCKET_TIMEOUT) + break; +#ifdef PXE_TCP_AGRESSIVE + if (filter->protocol == PXE_TCP_PROTOCOL) { + + if (check_timer > PXE_SOCKET_CHECK_TIMEOUT) { + check_timer = 0; + pxe_tcp_check_connection(sock); + } + } + + check_timer += TIME_DELTA; +#endif + timer += TIME_DELTA; + /* idle 10 ms */ + delay(TIME_DELTA_MS); + } + + if (result > 0) + sock->recv += result; + + return (result); +} + +#ifdef PXE_MORE +/* pxe_recvfrom() - receive data to socket with information about sender + * in: + * socket - socket descriptor number to recieve data from + * tobuf - buffer to receive data to + * buflen - size of buffer + * src_ip - pointer to memory, where store IP of sender + * flags - one of PXE_SOCK... flags + * out: + * -1 - failure + * nonnegative - actual count of bytes received + */ +int +pxe_recvfrom(int socket, void *tobuf, size_t buflen, uint32_t *src_ip, int flags) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_recvfrom(): invalid socket %d.\n", socket); + return (-1); + } +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + PXE_FILTER_ENTRY *filter = sock->filter; + + if (filter == NULL) { +#ifdef PXE_DEBUG + printf("pxe_recvfrom(): NULL filter\n"); +#endif + return (-1); + } + + if ( (filter->protocol != PXE_UDP_PROTOCOL) && + (filter->protocol != PXE_TCP_PROTOCOL) ) + { + printf("pxe_recvfrom(): only TCP and UDP sockets are implemented\n"); + return (-1); + } + + uint32_t timer = 0; + uint32_t check_timer = 0; + + int result = 0; + + PXE_UDP_DGRAM dgram; + + while (1) { + + if (filter->protocol == PXE_UDP_PROTOCOL) { + + result = pxe_udp_read(sock, tobuf, buflen, &dgram); + + } else { + + result = pxe_tcp_read(sock, tobuf, buflen); + } + + if ((result != 0) || (flags == PXE_SOCK_NONBLOCKING)) + break; + + if (timer > PXE_SOCKET_TIMEOUT) + break; + + if (filter->protocol == PXE_TCP_PROTOCOL) { + + if (check_timer > PXE_SOCKET_CHECK_TIMEOUT) { + check_timer = 0; + pxe_tcp_check_connection(sock); + } + } + + check_timer += 5; + timer += 5; + /* idle 5 ms */ + delay(5000); + } + + if (result >= 0) { + sock->recv += result; + + if (src_ip != NULL) { /* return source of data, if not NULL */ + if (filter->protocol == PXE_TCP_PROTOCOL) + *src_ip = filter->src.ip; + else + *src_ip = dgram.src.ip; + } + } + + return (result); +} +#endif /* PXE_MORE */ + +/* pxe_bind() - bind socket to local ip:port + * in: + * socket - socket descriptor number + * to - local ip to bind to + * lport - local port to bind to + * proto - IP stack protocol number + * out: + * -1 - failed + * 0 - success + */ +int +pxe_bind(int socket, const PXE_IPADDR *to, uint16_t lport, uint8_t proto) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_bind(): invalid socket %d.\n", socket); + return (-1); + } +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + + if (sock->state == PXE_SOCKET_CONNECTED) { + printf("pxe_bind(): cannot bind connected socket %d.\n", + socket); + + return (-1); + } + /* socket was already initalized */ + if (sock->filter != NULL) { + pxe_filter_remove(sock->filter); + sock->filter = NULL; + } + + PXE_FILTER_ENTRY *entry = + pxe_filter_add( NULL, 0, to, lport, sock, proto); + + if ( entry == NULL ) { + printf("pxe_bind(): failed to add filter.\n"); + return (0); + } + + /* allow any src_ip:port to our ip:lport */ + pxe_filter_mask(entry, 0, 0, 0xffffffff, 0xffff); + sock->filter = entry; + + /* all is ok */ + + sock->state = PXE_SOCKET_BINDED; + return (0); +} + +/* pxe_flush() - flushes send buffers + * in: + * socket - socket descriptor number + * out: + * -1 - failed + * 0 - success + */ +int +pxe_flush(int socket) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_flush(): invalid socket %d.\n", socket); + return (-1); + } +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + PXE_FILTER_ENTRY *filter = sock->filter; + + if (filter == NULL) { +#ifdef PXE_DEBUG + printf("pxe_flush(): NULL filter\n"); +#endif + return (-1); + } + + if (filter->protocol == PXE_UDP_PROTOCOL) /* it's always flushed */ + return (0); + else if (filter->protocol == PXE_TCP_PROTOCOL) + return (pxe_tcp_push(sock->filter) == 0) ? (-1) : 0; + + printf("pxe_flush(): only TCP and UDP sockets are implemented.\n"); + + return (-1); +} + +/* pxe_sock_state() - returns current state of socket + * in: + * socket - socket descriptor number + * out: + * -1 - if failed + * one of PXE_SOCKET_ state flags otherwise + */ +int +pxe_sock_state(int socket) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_sock_state(): invalid socket %d.\n", socket); + return (-1); + } +#endif + PXE_SOCKET *sock = &pxe_sockets[socket]; + PXE_FILTER_ENTRY *filter = sock->filter; + + if (filter == NULL) { +#ifdef PXE_DEBUG + printf("pxe_sock_state(): NULL filter\n"); +#endif + return (PXE_SOCKET_USED); + } + + if (filter->protocol == PXE_UDP_PROTOCOL) /* it's always 'established' */ + return (PXE_SOCKET_ESTABLISHED); + + else if (filter->protocol == PXE_TCP_PROTOCOL) { + /* for TCP connections need to check state */ + PXE_TCP_CONNECTION *connection = filter_to_connection(filter); + + if (connection && (connection->state == PXE_TCP_ESTABLISHED) ) + return (PXE_SOCKET_ESTABLISHED); + } + + return (PXE_SOCKET_CONNECTED); +} + +/* pxe_sock_recv_buffer() - returns recv buffer of socket + * in: + * socket - socket descriptor number + * out: + * NULL - if failed + * non NULL - pointer to buffer + */ +PXE_BUFFER * +pxe_sock_recv_buffer(int socket) +{ +#ifdef PXE_SOCKET_ACCURATE + if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) { + printf("pxe_sock_recv_buffer(): invalid socket %d.\n", socket); + return (NULL); + } +#endif + return (&pxe_sockets[socket].recv_buffer); +} + Index: user/sbruno/pxe_http/pxe_sock.h =================================================================== --- user/sbruno/pxe_http/pxe_sock.h (nonexistent) +++ user/sbruno/pxe_http/pxe_sock.h (revision 245442) @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_SOCK_H_INCLUDED +#define PXE_SOCK_H_INCLUDED + +/* + * Implements simple sockets API + */ + +#include +#include + +#include "pxe_buffer.h" +#include "pxe_filter.h" +#include "pxe_ip.h" + +/* default count of sockets used at the same time */ +#define PXE_DEFAULT_SOCKETS 4 +/* default count of waiting queue */ +#define PXE_DEFAULT_WAITCOUNT 3 +/* socket timeout when receiving data, in milliseconds */ +#define PXE_SOCKET_TIMEOUT 30000 +/* timeout, after that force connection checking, in milliseconds */ +#define PXE_SOCKET_CHECK_TIMEOUT 100 +/* define to add extra socket validating at every function */ + #define PXE_SOCKET_ACCURATE +/* socket states */ +/* socket unused and free for allocating */ +#define PXE_SOCKET_FREE 0x0 +/* socket structure used */ +#define PXE_SOCKET_USED 0x1 +/* socket binded (set local ip/local port). TODO: check if need */ +#define PXE_SOCKET_BINDED 0x2 +/* socket connected (set remote ip/remote port). TODO: check if need */ +#define PXE_SOCKET_CONNECTED 0x3 +/* connection established. TODO: check if need */ +#define PXE_SOCKET_ESTABLISHED 0x4 + +#define PXE_SOCK_NONBLOCKING 0 +#define PXE_SOCK_BLOCKING 1 + +/* socket */ +typedef struct pxe_socket { + PXE_BUFFER send_buffer; /* sending buffer */ + PXE_BUFFER recv_buffer; /* receiving buffer */ + + /* transmit and status counters*/ + uint32_t sent; /* bytes sent to socket */ + uint32_t recv; /* bytes received from socket */ + uint8_t state; /* current state */ + uint8_t waiting; /* number of connections waiting + * to be accepted */ + /* for resending usage */ + uint32_t last_time_sent; + uint32_t last_time_recv; + PXE_FILTER_ENTRY *filter; /* filter, that feeds data to socket */ +} PXE_SOCKET; + +/* inits this module */ +void pxe_sock_init(); + +/* allocates pxe_socket structure */ +/* int pxe_socket_alloc(); */ + +/* frees socket structure */ +/* int pxe_socket_free(int socket); (/ + +/* shows socket usage statistics */ +void pxe_sock_stats(); + +/* returns current socket state */ +int pxe_sock_state(int socket); + +PXE_BUFFER * pxe_sock_recv_buffer(int socket); + +/* pxe_listen() - creates "listening" socket + * it's not the same as normal listen() system call. + * Every pxe_listen() call creates pxe_socket structure + * and adds filter to filter table. + * WARN: + * -1 - means failed + * >= 0 - socket for UDP + * == 0 - success for TCP + */ +int pxe_listen(int socket, uint8_t proto, uint16_t port); + +/* accept awaiting connections */ +int pxe_accept(int socket); + +/* send to provided ip/port, updating filter for socket */ +int pxe_sendto(int socket, const PXE_IPADDR *dst, uint16_t port, + void *data, uint16_t size); + +/* moves socket to connected state */ +int pxe_connect(int socket, const PXE_IPADDR *ip, uint16_t port, + uint8_t proto); + +/* send data to socket, blocking */ +int pxe_send(int socket, void *buf, uint16_t buflen); + +/* receive data from socket, blocking */ +int pxe_recv(int socket, void *buf, uint16_t buflen, int flags); + +/* create new socket */ +int pxe_socket(); + +/* binding */ +int pxe_bind(int socket, const PXE_IPADDR *ip, uint16_t port, + uint8_t proto); + +/* flushes send buffers */ +int pxe_flush(int socket); + +/* close socket */ +int pxe_close(int socket); + +/* returns next available local port */ +uint16_t pxe_next_port(); + +#endif // PXE_SOCK_H_INCLUDED Index: user/sbruno/pxe_http/pxe_tcp.c =================================================================== --- user/sbruno/pxe_http/pxe_tcp.c (nonexistent) +++ user/sbruno/pxe_http/pxe_tcp.c (revision 245442) @@ -0,0 +1,888 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_await.h" +#include "pxe_buffer.h" +#include "pxe_connection.h" +#include "pxe_core.h" +#include "pxe_filter.h" +#include "pxe_ip.h" +#include "pxe_segment.h" +#include "pxe_tcp.h" + +/* used by pxe_tcp_syssend, when connection have no buffers */ +static PXE_BUFFER sysbuf; +/* buffer space for sysbuf */ +static uint8_t bufdata[PXE_TCP_SYSBUF_SIZE]; + +#ifdef PXE_TCP_DEBUG_HELL +/* states in human friendly */ +static char strstates[PXE_TCP_ALL_STATES][15] = { + "CLOSED", + "SYN_SENT", + "SYN_RECEIVED", + "ESTABLISHED", + "CLOSE_WAIT", + "LAST_ACK", + "FIN_WAIT_1", + "CLOSING", + "FIN_WAIT_2", + "TIME_WAIT" + }; +#endif + +/* tcp_check_time_to_die() - moves to CLOSED state connections from state + * TIME_WAIT if last received packet (ACK for FIN in most cases) + * was more than 2*MSL time ago. + * in: + * connection - connection to check + * out: + * none + */ +static void +tcp_check_time_to_die(PXE_TCP_CONNECTION *connection) +{ + /* if connection in other states - do nothing */ + if (connection->state != PXE_TCP_TIME_WAIT) + return; + + time_t cur_time = pxe_get_secs(); + + if (cur_time - connection->last_recv > 2 * PXE_TCP_MSL) { +#ifdef PXE_TCP_DEBUG + printf("tcp_check_time_to_die(): time for 0x%x connection.\n", + connection); +#endif + /* release filter */ + PXE_FILTER_ENTRY *filter = connection->filter; + + if (filter != NULL) /* it must always be non NULL */ + pxe_filter_remove(filter); + + /* release connection */ + free_connection(connection); + } +} + +/* tcp_send_rst_for() - sends RST in reply to provided packet + * in: + * tcp_packet - packet which caused RST sending + * out: + * 0 - failed + * 1 - success + */ +static int +tcp_send_rst_for(PXE_TCP_PACKET *tcp_packet, uint32_t ack, uint32_t seq, + uint8_t flags, uint16_t seglen) +{ + PXE_TCP_CONNECTION connection; + pxe_memset(&connection, 0, sizeof(PXE_TCP_CONNECTION)); + + connection.dst_port = tcp_packet->tcphdr.src_port; + connection.src_port = tcp_packet->tcphdr.dst_port; + connection.dst.ip = tcp_packet->iphdr.src_ip; + + connection.next_recv = seq + seglen; /* acking */ + connection.next_send = ack; /* next send */ + + connection.chunk_size = PXE_TCP_SYSBUF_SIZE; + connection.buf_blocks[0] = PXE_TCP_BLOCK_FREE; + connection.send = &sysbuf; + + return pxe_tcp_syssend(&connection, flags); +} + +/* tcp_is_acceptable() - first check for SYN_RECEIVED, ESTABLISHED, FIN_WAIT_1, + * FIN_WAIT_2, CLOSE_WAIT, CLOSING, LAST_ACK, TIME_WAIT + * in: + * connection - connection for which packet received + * tcp_packet - received packet + * seglen - segment length + * out: + * 0 - not acceptable + * 1 - acceptable + */ +int +tcp_is_acceptable(PXE_TCP_CONNECTION *connection, PXE_TCP_PACKET *tcp_packet, + uint16_t seglen) +{ + if (connection == NULL) + return (0); + + if (connection->recv == NULL) + return (0); + + uint16_t window = pxe_buffer_space(connection->recv); + uint32_t seq = tcp_packet->tcphdr.sequence; + + if (seglen == 0) { + + if (window == 0) { + if (seq == connection->next_recv) + return (1); + } + + if (connection->next_recv > seq) + return (0); + + if (seq < connection->next_recv + window) + return (1); + + } else { /* segment size > 0 */ + + if (window == 0) + return (0); + + if ((connection->next_recv <= seq) && + (seq < connection->next_recv + window) ) + return (1); + + /* or? */ + if ((connection->next_recv <= seq + seglen - 1) && + (seq + seglen - 1 < connection->next_recv + window) ) + return (1); + } + + return (0); +} + +/* tcp checks has same numbers as in RFC 793, page 65+ */ + +/* tcp_check_1() - check if packet is acceptable, sends ACK if not + * in: + * connection - connection for which packet received + * tcp_packet - received packet + * seglen - segment length + * out: + * 0 - not acceptable + * 1 - acceptable + */ +static int inline +tcp_check_1(PXE_TCP_CONNECTION *connection, PXE_TCP_PACKET *tcp_packet, + uint16_t seglen) +{ + if (tcp_is_acceptable(connection, tcp_packet, seglen)) + return (1); + + PXE_BUFFER *buffer = connection->recv; + + if (buffer && (buffer->bufleft == 0)) + connection->winlock = 1; + + pxe_tcp_syssend(connection, PXE_TCP_ACK); + +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_check_1(): failed\n"); +#endif + return (0); +} + +/* tcp_check_2() - check if packet has RST flag + * in: + * tcp_packet - received packet + * out: + * 0 - not have + * 1 - have + */ +static int inline +tcp_check_2(PXE_TCP_PACKET *tcp_packet) +{ + if (tcp_packet->tcphdr.flags & PXE_TCP_RST) + return (1); + +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_check_2(): failed\n"); +#endif + return (0); +} + +/* tcp_check_3() - check precedence + * in: + * connection - connection for which packet received + * tcp_packet - received packet + * out: + * 0 - failed + * 1 - precedence ok + */ +static int inline +tcp_check_3(PXE_TCP_CONNECTION *connection, PXE_TCP_PACKET *tcp_packet) +{ + /* TODO?: implement */ + return (1); +} + +/* tcp_check_4() - check if packet has SYN flag and sends RST + * in: + * connection - connection for which packet received + * tcp_packet - received packet + * seglen - segment length + * out: + * 0 - not have + * 1 - have + */ +static int inline +tcp_check_4(PXE_TCP_CONNECTION *connection, PXE_TCP_PACKET *tcp_packet, + uint16_t seglen) +{ + + if ( (tcp_packet->tcphdr.flags & PXE_TCP_SYN) == 0) { +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_check_4(): failed\n"); +#endif + return (0); + } + + tcp_send_rst_for(tcp_packet, 0, connection->next_send, PXE_TCP_RST, + seglen); + + return (1); +} + +/* tcp_check_5() - check if packet has ACK flag + * in: + * connection - connection for which packet received + * tcp_packet - received packet + * out: + * 0 - not have + * 1 - have + */ +static int inline +tcp_check_5(PXE_TCP_CONNECTION *connection, PXE_TCP_PACKET *tcp_packet) +{ + if ((tcp_packet->tcphdr.flags & PXE_TCP_ACK) == 0) { +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_check_5(): failed\n"); +#endif + return (0); + } + + uint32_t ack = tcp_packet->tcphdr.ack_next; + + if (ack > connection->next_send) { + /* acked something, that was not sent */ +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_check_5(): failed, acked %d, but next_snd = %d\n", + ack - connection->iss, + connection->next_send - connection->iss); +#endif + pxe_tcp_syssend(connection, PXE_TCP_ACK); + return (0); + } + + if ( connection->una <= ack) { + connection->una = ack; + pxe_resend_update(connection); + } else { /* ignore dublicate packet */ +#ifdef PXE_TCP_DEBUG + printf("tcp_check_5(): failed\n"); +#endif + return (0); + } + + connection->remote_window = tcp_packet->tcphdr.window_size; + + return (1); +} + +/* tcp_check_6() - check if packet has URG flag + * in: + * tcp_packet - received packet + * out: + * 0 - not have + * 1 - have + */ +static int inline +tcp_check_6(PXE_TCP_PACKET *tcp_packet) +{ + if (tcp_packet->tcphdr.flags & PXE_TCP_URG) + return (1); + +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_check_6(): failed\n"); +#endif + return (0); +} + +/* tcp_process_7() - processes data and sends ACK + * in: + * connection - connection for which packet received + * tcp_packet - received packet + * seglen - segment length + * out: + * 0 - not have + * 1 - have + */ +static void inline +tcp_process_7(PXE_TCP_CONNECTION *connection, PXE_TCP_PACKET *tcp_packet, + uint16_t seglen) +{ + connection->next_recv += seglen; + + if (tcp_packet->tcphdr.flags & (PXE_TCP_SYN | PXE_TCP_FIN) ) + connection->next_recv += 1; + + if ( (seglen > 0) && (connection->state == PXE_TCP_ESTABLISHED)) { + /* write data to buffer, always enough space, + * if packet is acceptable + */ + void *data = ((void *)tcp_packet) + sizeof(PXE_IP_HDR) + + 4 * (tcp_packet->tcphdr.data_off >> 4); + + pxe_buffer_write(connection->recv, data, seglen); + } + + pxe_tcp_syssend(connection, PXE_TCP_ACK); + connection->last_recv = pxe_get_secs(); +} + +/* tcp_check_8() - check if packet has FIN flag + * in: + * tcp_packet - received packet + * out: + * 0 - not have + * 1 - have + */ +static int inline +tcp_check_8(PXE_TCP_PACKET *tcp_packet) +{ + if (tcp_packet->tcphdr.flags & PXE_TCP_FIN) + return (1); + +#ifdef PXE_TCP_DEBUG_HELL + printf("tcp_check_8(): failed\n"); +#endif + return (0); +} + +/* tcp_syn_sent() - SYN_SENT state handler + * in: + * tcp_packet - incoming packet data + * connection - current connection + * out: + * 0 - don't interested more in this packet + * 1 - interested + */ +static int +tcp_syn_sent(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection, + uint16_t seglen) +{ + uint8_t flags = tcp_packet->tcphdr.flags; + uint32_t ack = tcp_packet->tcphdr.ack_next; + uint32_t seq = tcp_packet->tcphdr.sequence; + int acceptable = 1; + + /* first check */ + if ( flags & PXE_TCP_ACK) { + + if ( (ack <= connection->iss) || + (ack > connection->next_send) ) + { + if ( (flags & PXE_TCP_RST) == 0) { + /* sending RST, if it was not sent to us */ +#ifdef PXE_TCP_DEBUG + printf("tcp_syn_sent(): resetting, ack = %d, " + "iss = %d, nxt = %d\n", ack, + connection->iss, connection->next_send); +#endif + tcp_send_rst_for(tcp_packet, ack, 0, + PXE_TCP_RST, 0); + } + + /* drop segment and return */ + return (0); + } + + /* check if ACK acceptable */ + if ( (connection->una > ack) || (ack > connection->next_send) ) + acceptable = 0; + } + + /* second check, check RST */ + if (flags & PXE_TCP_RST) { + + if (acceptable == 0) /* just drop */ + return (0); + + /* destroy connection */ +#ifdef PXE_TCP_DEBUG + printf("tcp_syn_sent(): new state - CLOSED\n"); +#endif + connection->state = PXE_TCP_CLOSED; + return (0); + } + + /* third check */ + /* TODO?: check security/compartment and precedence */ + + /* fourth check, check SYN */ + if (flags & PXE_TCP_SYN) { + + if (acceptable == 1) { + connection->next_recv = seq + 1; + connection->irs = seq; + connection->una = ack; + pxe_resend_update(connection); + } + + if ((connection->una > connection->iss) || (acceptable == 1) ) { + /* acking */ + if (pxe_tcp_syssend(connection, PXE_TCP_ACK)) { +#ifdef PXE_TCP_DEBUG + printf("tcp_syn_sent(): new state - ESTABLISHED\n"); +#endif + connection->state = PXE_TCP_ESTABLISHED; + connection->last_recv = pxe_get_secs(); + } else + printf("tcp_syn_sent(): ack syn reply failed.\n"); + + } else { + /* enter SYN_RECEIVED, form SYN+ACK */ + } + } + + return (0); +} + +/* pxe_tcp_process() - processes incoming packets in states, other than SYN_SENT + * in: + * tcp_packet - incoming packet data + * connection - current connection + * + * out: + * 0 - don't interested more in this packet + * 1 - interested + */ +static int +pxe_tcp_process(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION * connection, + uint16_t seglen) +{ + uint8_t state = connection->state; + uint8_t state_out = connection->state_out; + + /* first check, if acceptable at all */ + if (!tcp_check_1(connection, tcp_packet, seglen)) + return (0); + + /* check establishing of commmunication */ + if (state == PXE_TCP_SYN_SENT) { + + if (tcp_packet->tcphdr.flags & PXE_TCP_SYN) { + + uint32_t ack = tcp_packet->tcphdr.ack_next; + uint32_t seq = tcp_packet->tcphdr.sequence; + + connection->next_recv = seq + 1; + connection->irs = seq; + connection->una = ack; + pxe_resend_update(connection); + } + + if (pxe_tcp_syssend(connection, PXE_TCP_ACK)) { + connection->state = PXE_TCP_ESTABLISHED; + connection->last_recv = pxe_get_secs(); + } else { + printf("tcp_syn_sent(): ack syn reply failed.\n"); + return (0); + } + } + + /* check, if have RST flag, sequentially incorrect or have SYN */ + if (( tcp_check_2(tcp_packet)) || + ( tcp_check_4(connection, tcp_packet, seglen))) + { + connection->state = PXE_TCP_CLOSED; + pxe_resend_free(connection); + + /* if (state == PXE_TCP_TIME_WAIT) */ + free_connection(connection); + + return (0); + } + + /* fifth check, if ACK received */ + if (!tcp_check_5(connection, tcp_packet)) + return (0); + + switch (state) { + case PXE_TCP_FIN_WAIT1: + connection->next_send = tcp_packet->tcphdr.ack_next; + + /* if acked our FIN */ + if (state_out == PXE_TCP_FIN) { + connection->state = PXE_TCP_FIN_WAIT2; + /* return (0); */ + } + break; + + case PXE_TCP_FIN_WAIT2: + connection->next_send = tcp_packet->tcphdr.ack_next; + break; + + case PXE_TCP_CLOSING: + if (state_out == PXE_TCP_FIN) + connection->state = PXE_TCP_TIME_WAIT; + break; + + case PXE_TCP_LAST_ACK: + if (state_out == PXE_TCP_FIN) { + connection->state = PXE_TCP_CLOSED; + pxe_resend_free(connection); + free_connection(connection); + return (0); + } + break; + + case PXE_TCP_TIME_WAIT: + /* in that state only retransmission of FIN may arrive + * ACKing it + */ + pxe_tcp_syssend(connection, PXE_TCP_ACK); + break; + + default: + break; + } + + /* FIN_WAIT_2 + if (tcp_queue_size(connection) == 0) { + connection->state = PXE_TCP_CLOSE; + } + */ + + /* sixth check, if urgent. Ignoring. */ + /* if (tcp_check_6(tcp_packet)) + return (0); + */ + + /* seventh, process segment */ + switch (state) { + case PXE_TCP_ESTABLISHED: + case PXE_TCP_FIN_WAIT1: + case PXE_TCP_FIN_WAIT2: + tcp_process_7(connection, tcp_packet, seglen); + break; + + case PXE_TCP_LAST_ACK: + /* if got here, means we have ACK */ + connection->state = PXE_TCP_CLOSED; + return (0); + break; + + case PXE_TCP_TIME_WAIT: + /* check TIME_WAIT time */ + tcp_check_time_to_die(connection); + /* going to return */ + + case PXE_TCP_CLOSE_WAIT: + /* just return */ + + default: + return (0); + break; + } + + /* eighth, check FIN */ + if (tcp_check_8(tcp_packet)) { + + switch (connection->state) { + case PXE_TCP_ESTABLISHED: + /* remote host requested connection break */ + connection->state = PXE_TCP_CLOSE_WAIT; + break; + + case PXE_TCP_FIN_WAIT1: + if (state_out == PXE_TCP_FIN) { + connection->state = PXE_TCP_TIME_WAIT; + } else { + connection->state = PXE_TCP_CLOSING; + } + break; + + case PXE_TCP_FIN_WAIT2: + connection->state = PXE_TCP_TIME_WAIT; + break; + + default: + break; + } + } + + return (0); +} + +/* pxe_tcp_callback() - TCP protocol callback function, executed by pxe_core + * in: + * pack - packet description + * function- function to perform + * out: + * 1 - if packet is fragment and code is interested in it + * 0 - if success or error + */ +int +pxe_tcp_callback(PXE_PACKET *pack, uint8_t function) +{ + PXE_TCP_PACKET *tcp_packet = pack->data; + PXE_IPADDR from; + PXE_IPADDR to; + + from.ip = tcp_packet->iphdr.src_ip; + to.ip = tcp_packet->iphdr.dst_ip; + + /* conversion to little endian */ + tcp_packet->tcphdr.sequence = ntohl(tcp_packet->tcphdr.sequence); + tcp_packet->tcphdr.ack_next = ntohl(tcp_packet->tcphdr.ack_next); + tcp_packet->tcphdr.src_port = ntohs(tcp_packet->tcphdr.src_port); + tcp_packet->tcphdr.dst_port = ntohs(tcp_packet->tcphdr.dst_port); + + tcp_packet->tcphdr.window_size = + ntohs(tcp_packet->tcphdr.window_size); + + uint16_t src_port = tcp_packet->tcphdr.src_port; + uint16_t dst_port = tcp_packet->tcphdr.dst_port; + + PXE_IP_HDR *iphdr = pack->data; + + /* calculating data size from ip length minus headers length */ + uint16_t data_size = ntohs(iphdr->length) - + 4 * ((iphdr->ver_ihl & 0x0F) + + (tcp_packet->tcphdr.data_off >> 4)); +#ifdef PXE_TCP_DEBUG_HELL + printf("packet: size = %u(%u), ip_hdr = %u(%u), tcp_hdr = %u (%u)\n", + data_size, pack->data_size, 4 * (iphdr->ver_ihl & 0x0F), + sizeof(PXE_IP_HDR), 4 * (tcp_packet->tcphdr.data_off >> 4), + sizeof(PXE_TCP_HDR)); +#endif +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_callback(): tcp packet from %s:%u", + inet_ntoa(from.ip), src_port); + + printf(" to %s:%u\n", + inet_ntoa(to.ip), dst_port); +#endif + + uint8_t flags = tcp_packet->tcphdr.flags; + + PXE_SOCKET *sock = pxe_filter_check(&from, src_port, &to, + dst_port, PXE_TCP_PROTOCOL); + + if (sock == NULL) { /* nobody is interested in this packet */ +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_callback(): packet filtered out, sending RST.\n"); +#endif + if (flags & PXE_TCP_ACK) + tcp_send_rst_for(tcp_packet, 0, + tcp_packet->tcphdr.ack_next, PXE_TCP_RST, data_size); + else + tcp_send_rst_for(tcp_packet, + tcp_packet->tcphdr.ack_next + data_size, 0, + PXE_TCP_RST | PXE_TCP_ACK, data_size); + + return (0); + } + + /* inform, we are interested in whole packet */ + if (function == PXE_CORE_FRAG) + return (1); + + /* Here filter is not NULL, that means packet is for connected socket or + * connection is trying to be established/breaked correctly + */ + + PXE_TCP_CONNECTION *connection = filter_to_connection(sock->filter); + + if (connection == NULL) { + printf("pxe_tcp_callback(): no connection for filter 0x%x\n", + sock->filter); + + pxe_filter_remove(sock->filter); + return (0); /* NOTE: this is internal error, if got here */ + } + +#ifdef PXE_TCP_DEBUG + printf(" seq %lu,", tcp_packet->tcphdr.sequence - connection->irs); + + if (flags & PXE_TCP_FIN) + printf(" fin,"); + + if (flags & PXE_TCP_SYN) + printf(" syn,"); + + if (flags & PXE_TCP_RST) + printf(" rst,"); + + if (flags & PXE_TCP_ACK) + printf(" ack %lu,", tcp_packet->tcphdr.ack_next - connection->iss); + + if (flags & PXE_TCP_URG) + printf(" urg,"); + + if (flags & PXE_TCP_URG) + printf(" psh,"); + + printf(" %u bytes.\n", data_size); +#endif + /* TODO: verify checksum */ + + uint32_t seq = tcp_packet->tcphdr.sequence; + + if (flags & PXE_TCP_RST) { + /* connection aborted (hard error) by remote host */ + connection->state = PXE_TCP_CLOSED; +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_callback(): new state - CLOSED\n"); +#endif + return (0); + } + + if (connection->state > PXE_TCP_SYN_SENT) { + + /* if we know sequence number, then check it */ + if (seq != connection->next_recv) { + /* not next in order, drop it, send ACK */ +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_callback(): got %d != awaited %d\n", + seq - connection->irs, + connection->next_recv - connection->irs); +#endif + pxe_tcp_syssend(connection, PXE_TCP_ACK); + return (0); + } + } else { + /* in case of SYN_SENT state we don't know sequence number yet */ + } + + int result = 0; + + /* calling appropriate state handler, if it's not NULL */ + if (connection->state < PXE_TCP_ALL_STATES) { + + while (1) { +#ifdef PXE_TCP_DEBUG_HELL + printf("pxe_tcp_callback(): connection state = %s\n", + strstates[connection->state]); +#endif + + if (connection->state == PXE_TCP_SYN_SENT) { + result = tcp_syn_sent(tcp_packet, connection, data_size); + } else { + + result = pxe_tcp_process(tcp_packet, connection, data_size); + } + + if (result == 2) + continue; + + break; + } + } + + /* check ACKed packets */ + pxe_resend_update(connection); + + /* check if need to resend some segments */ + pxe_resend_check(connection); + + /* check time to die */ + if (connection->state == PXE_TCP_TIME_WAIT) + tcp_check_time_to_die(connection); + + return (result); +} + +/* pxe_tcp_init() - initialization of TCP module + * in/out: + * none + */ +void +pxe_tcp_init() +{ +#ifdef PXE_TCP_DEBUG + printf("pxe_tcp_init(): started\n"); +#endif + pxe_connection_init(); + + /* registering protocol */ + pxe_core_register(PXE_TCP_PROTOCOL, pxe_tcp_callback); + + /* sysbuf init */ + pxe_memset(&bufdata, 0 , PXE_TCP_SYSBUF_SIZE); + sysbuf.data = &bufdata; + /* not really need, cause not using buffer realted functions */ + sysbuf.bufleft = PXE_TCP_SYSBUF_SIZE; + sysbuf.bufsize = PXE_TCP_SYSBUF_SIZE; + sysbuf.fstart = 0; + sysbuf.fend = PXE_TCP_SYSBUF_SIZE; +} + +/* pxe_tcp_syssend() - send system packets via TCP protocol + * in: + * connection - connection to send to + * tcp_flags - one or more PXE_TCP_.. flags + * out: + * 0 - failed + * 1 - success + */ +int +pxe_tcp_syssend(PXE_TCP_CONNECTION *connection, uint8_t tcp_flags) +{ + /* allocating "small" segment */ + PXE_TCP_QUEUED_SEGMENT *segment = tcp_segment_alloc(connection, + PXE_SEGMENT_SMALL); + + if (segment == NULL) { + printf("pxe_tcp_syssend(): failed to allocate segment.\n"); + return (0); + } + + /* add to every system segment default options */ + tcp_start_segment(connection, segment, PXE_SEGMENT_OPTS_DEFAULT); + + /* finish segment */ + tcp_finish_segment(connection, segment, tcp_flags); + + /* Here is simpliest ever in the world way to calculate resend time. + * For more reliable resend time calculation need to implement RTT + * calculating and use more accurate timer. + */ + segment->resend_at = pxe_get_secs() + PXE_RESEND_TIME; + + /* remove other segments with same sequence number, + * so this segment is last + */ + pxe_resend_drop_same(connection, segment); + + if ( /* (connection->state != PXE_TCP_ESTABLISHED) && */ + (!pxe_tcp_send_segment(connection, segment))) + { + printf("pxe_tcp_syssend(): failed to send segment.\n"); + return (0); + } + + return (1); +} Index: user/sbruno/pxe_http/pxe_tcp.h =================================================================== --- user/sbruno/pxe_http/pxe_tcp.h (nonexistent) +++ user/sbruno/pxe_http/pxe_tcp.h (revision 245442) @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_TCP_H_INCLUDED +#define PXE_TCP_H_INCLUDED + +/* + * Contains functions needed to transmit tcp packets, using pxe_segment.h module + */ + +#include +#include + +#include "pxe_buffer.h" +#include "pxe_connection.h" +#include "pxe_ip.h" +#include "pxe_filter.h" + +/* TCP IP stack protocol number*/ +#define PXE_TCP_PROTOCOL 6 +/* maximum segment life time in ms */ +#define PXE_TCP_MSL 60000 +/* buffer size used for system messages for packets without real connection */ +#define PXE_TCP_SYSBUF_SIZE 64 + +/* tcp packet flags */ +#define PXE_TCP_FIN 0x01 +#define PXE_TCP_SYN 0x02 +#define PXE_TCP_RST 0x04 +#define PXE_TCP_PSH 0x08 +#define PXE_TCP_ACK 0x10 +#define PXE_TCP_URG 0x20 + +typedef struct pxe_tcp_hdr { + + uint16_t src_port; /* local port */ + uint16_t dst_port; /* remote port */ + uint32_t sequence; /* seqence number */ + uint32_t ack_next; /* ACK'd number */ + uint8_t data_off; /* offset to data */ + uint8_t flags; /* TCP flags, see higher TCP_FLAG_ */ + uint16_t window_size; /* current window size */ + uint16_t checksum; /* packet checksum*/ + uint16_t urgent; /* urgent flags */ +} __packed PXE_TCP_HDR; + +/* #define PXE_TCP_MSS 1460 */ +#define PXE_TCP_MSS 1260 + +/* default TCP options for sending data structure */ +typedef struct pxe_tcp_default_options { + + uint8_t kind; /* kind = 2, maximum segment size option */ + uint8_t size; /* size of option including + * sizeof(kind) + sizeof(size) + */ + uint16_t mss; /* maximum segment size in octets */ + uint8_t end; /* kind = 0 */ + uint8_t pad[3]; /* padding, not nessesary */ +} __packed PXE_TCP_DEFAULT_OPTIONS; + +typedef struct pxe_tcp_packet { + + PXE_IP_HDR iphdr; + PXE_TCP_HDR tcphdr; +} __packed PXE_TCP_PACKET; + +typedef struct pxe_tcp_wait_data { + + uint8_t state; /* what state is waited for */ + PXE_TCP_CONNECTION *connection; /* which connection is monitored */ +} __packed PXE_TCP_WAIT_DATA; + +/* state function handler type */ +typedef int (*pxe_tcp_state_func)(PXE_TCP_PACKET *tcp_packet, + PXE_TCP_CONNECTION *connection, uint16_t seglen); + +/* init tcp */ +void pxe_tcp_init(); + +/* sends "system" (no user data) segment */ +int pxe_tcp_syssend(PXE_TCP_CONNECTION *connection, uint8_t tcp_flags); + +#endif // PXE_TCP_H_INCLUDED Index: user/sbruno/pxe_http/pxe_udp.c =================================================================== --- user/sbruno/pxe_http/pxe_udp.c (nonexistent) +++ user/sbruno/pxe_http/pxe_udp.c (revision 245442) @@ -0,0 +1,348 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include + +#include "pxe_buffer.h" +#include "pxe_core.h" +#include "pxe_filter.h" +#include "pxe_ip.h" +#include "pxe_sock.h" +#include "pxe_udp.h" + +#ifdef UDP_DEFAULT_SOCKET +PXE_BUFFER def_buffer; +#endif + +/* pxe_udp_callback() - UDP protocol callback function, executed by pxe_core + * in: + * pack - packet description + * function- function to perform + * out: + * 1 - if packet is fragment and code is interested in it + * 0 - if success or error + */ +int +pxe_udp_callback(PXE_PACKET *pack, uint8_t function) +{ + PXE_UDP_PACKET *udp_packet = pack->data; + PXE_IPADDR from; + PXE_IPADDR to; + + from.ip = udp_packet->iphdr.src_ip; + to.ip = udp_packet->iphdr.dst_ip; + + uint16_t src_port = ntohs(udp_packet->udphdr.src_port); + uint16_t dst_port = ntohs(udp_packet->udphdr.dst_port); + +#ifdef PXE_DEBUG + printf("pxe_udp_callback(): udp packet from %s:%u to ", + inet_ntoa(from.ip), src_port); + + printf("%s:%u\n", inet_ntoa(to.ip), dst_port); +#endif + + PXE_SOCKET *sock = pxe_filter_check(&from, src_port, &to, dst_port, + PXE_UDP_PROTOCOL); + + if (sock == NULL) { /* nobody is interested in this packet */ +#ifndef UDP_DEFAULT_SOCKET +#ifdef PXE_DEBUG + printf("pxe_udp_callback(): packet filtered out.\n"); +#endif + return (0); +#endif + } + + /* informm, we are interested in whole packet */ + if (function == PXE_CORE_FRAG) + return (1); + + /* TODO: verify checksum */ + + uint16_t data_size = pack->data_size - sizeof(PXE_UDP_PACKET); + +#ifdef UDP_DEFAULT_SOCKET + PXE_BUFFER* recv_buffer = + (sock != NULL) ? &sock->recv_buffer : &def_buffer; +#else + PXE_BUFFER* recv_buffer = &sock->recv_buffer; +#endif + PXE_UDP_DGRAM udp_dgram; + + if (pxe_buffer_space(recv_buffer) < data_size + sizeof(PXE_UDP_DGRAM)) + printf("pxe_udp_callback(): socket 0x%x buffer has no space\n", + sock); + else { + udp_dgram.magic = PXE_MAGIC_DGRAM; + udp_dgram.src.ip = from.ip; + udp_dgram.src_port = src_port; + udp_dgram.size = data_size; + + /* NOTE: here is assuming that there is no other writings to + * buffer, so, to writes, place data sequentially in bufer. + */ + pxe_buffer_write(recv_buffer, &udp_dgram, + sizeof(PXE_UDP_DGRAM)); + + pxe_buffer_write(recv_buffer, + pack->data + sizeof(PXE_UDP_PACKET), data_size); + } + + return (0); +} + +/* pxe_udp_init() - initialization of UDP module + * in/out: + * none + */ +void +pxe_udp_init() +{ +#ifdef PXE_DEBUG + printf("pxe_udp_init(): started\n"); +#endif + pxe_core_register(PXE_UDP_PROTOCOL, pxe_udp_callback); + +#ifdef UDP_DEFAULT_SOCKET + pxe_buffer_memalloc(&def_buffer, 16384); +#endif +} + + +/* pxe_udp_shutdown() - cleanup of used memory buffer + * in/out: + * none + */ +void +pxe_udp_shutdown() +{ +#ifdef UDP_DEFAULT_SOCKET + pxe_buffer_memfree(&def_buffer); +#endif +} + + +/* pxe_udp_send() - send data via UDP protocol + * in: + * data - buffer of data to send + * dst_ip - destination IP address + * dst_port- destination port + * src_port- source port + * size - size of data + * flags - 1 if space for UDP & IP headers reserved in buffer, + * 0 otherwise + * out: + * 0 - failed + * 1 - success + */ +int +pxe_udp_send(void *data, const PXE_IPADDR *dst, uint16_t dst_port, + uint16_t src_port, uint16_t size) +{ + PXE_UDP_PACKET *udp_packet = (PXE_UDP_PACKET *)data; + + uint16_t length = size - sizeof(PXE_IP_HDR); + udp_packet->udphdr.src_port = htons(src_port); + udp_packet->udphdr.dst_port = htons(dst_port); + udp_packet->udphdr.length = htons(length); + udp_packet->udphdr.checksum = 0; + + PXE_IP4_PSEUDO_HDR pseudo_hdr; + const PXE_IPADDR *my = pxe_get_ip(PXE_IP_MY); + +#ifdef PXE_DEBUG + printf("pxe_udp_send(): %s:%u -> ", + inet_ntoa(my->ip), src_port); + + printf("%s:%u, size = %u bytes.\n", + inet_ntoa(dst->ip), dst_port, size); +#endif + + pseudo_hdr.src_ip = my->ip; + pseudo_hdr.dst_ip = dst->ip; + pseudo_hdr.zero = 0; + pseudo_hdr.proto = PXE_UDP_PROTOCOL; + pseudo_hdr.length = udp_packet->udphdr.length; + + /* adding pseudo header checksum to checksum of udp header with data + * and make it complimentary + */ + + uint16_t part1 = pxe_ip_checksum(&pseudo_hdr, + sizeof(PXE_IP4_PSEUDO_HDR)); + + uint16_t part2 = pxe_ip_checksum(&udp_packet->udphdr, length); + + uint32_t tmp_sum = ((uint32_t)part1) + ((uint32_t)part2); + + if (tmp_sum & 0xf0000) /*need carry out */ + tmp_sum -= 0xffff; + + udp_packet->udphdr.checksum = ~((uint16_t)(tmp_sum & 0xffff)); + + /* special case */ + if (udp_packet->udphdr.checksum == 0) + udp_packet->udphdr.checksum = 0xffff; + +#ifdef PXE_DEBUG_HELL + printf("pxe_udp_send(): checksum 0x%4x for %u bytes\n", + udp_packet->udphdr.checksum, length); +#endif + + if (!pxe_ip_send(udp_packet, dst, PXE_UDP_PROTOCOL, + length + sizeof(PXE_IP_HDR))) + { + printf("pxe_udp_send(): failed to send udp packet to %s\n", + inet_ntoa(dst->ip)); + + return (0); + } + + return (1); +} + +/* pxe_udp_read() - performs reading from UDP socket + * in: + * sock - UDP socket to read from + * tobuf - buffer, where to read + * buflen - buffer size + * dgram_out - if not NULL, here placed dgram info + * out: + * -1 - failed + * >= 0 - actual bytes were read + */ +int +pxe_udp_read(PXE_SOCKET *sock, void *tobuf, uint16_t buflen, + PXE_UDP_DGRAM *dgram_out) +{ + PXE_UDP_DGRAM udp_dgram; + + PXE_BUFFER *buffer = NULL; + + if (sock == NULL) { +#ifndef UDP_DEFAULT_SOCKET + return (-1); /* bad socket */ +#else + buffer = &def_buffer; +#endif + } else + buffer = &sock->recv_buffer; + + if (buffer == NULL) { +#ifdef PXE_DEBUG + printf("pxe_udp_read(): NULL buffer.\n"); +#endif + return (0); + } + + uint16_t usage = buffer->bufsize - pxe_buffer_space(buffer); + + if (sizeof(PXE_UDP_DGRAM) != pxe_buffer_read(buffer, &udp_dgram, + sizeof(PXE_UDP_DGRAM))) + { +#ifdef PXE_DEBUG_HELL + printf("pxe_udp_read(): failed to read datagram data.\n"); +#endif + return (0); + } + + if (udp_dgram.magic != PXE_MAGIC_DGRAM) { /* sanity check failed */ +#ifdef PXE_DEBUG + printf("pxe_udp_sock_recv(): dgram magic failed.\n"); +#endif + return (0); + } + + uint16_t tocopy = ((uint16_t)buflen < udp_dgram.size) ? + (uint16_t)buflen : udp_dgram.size; + + uint16_t result = pxe_buffer_read(buffer, tobuf, tocopy); + + if (result < udp_dgram.size) /* free truncated dgram part */ + pxe_buffer_read(buffer, NULL, udp_dgram.size - result); + + if (dgram_out != NULL) { + pxe_memcpy(&udp_dgram, dgram_out, sizeof(PXE_UDP_DGRAM)); + } + + return ((int)result); +} + +/* pxe_udp_write() - performs writing to UDP socket + * in: + * sock - UDP socket to write to + * tobuf - buffer with data to write + * buflen - buffer size + * out: + * -1 - failed + * >= 0 - actual bytes were written + */ +int +pxe_udp_write(PXE_SOCKET *sock, void *buf, uint16_t buflen) +{ + + if (buflen + sizeof(PXE_UDP_PACKET) > PXE_DEFAULT_SEND_BUFSIZE) { + printf("pxe_udp_write(): send buffer too small for %d bytes.\n", + buflen); + + return (-1); + } + + /* for UDP socket, send buffer used only for one dgram */ + PXE_UDP_PACKET *udp_pack = + (PXE_UDP_PACKET *)sock->send_buffer.data; + + PXE_FILTER_ENTRY *filter = sock->filter; + + if (filter == NULL) { /* not connected socket */ + printf("pxe_udp_write(): socket is not connected.\n"); + return (-1); + } + + /* copy user data */ + pxe_memcpy(buf, udp_pack + 1, buflen); + + const PXE_IPADDR *my = pxe_get_ip(PXE_IP_MY); + +#ifdef PXE_DEBUG + printf("pxe_udp_write(): %s:%u -> ", + inet_ntoa(my->ip), filter->dst_port); + + printf("%s:%u, size = %u bytes.\n", + inet_ntoa(filter->src.ip), filter->src_port, buflen); +#endif + + if (!pxe_udp_send(udp_pack, &filter->src, filter->src_port, + filter->dst_port, buflen + sizeof(PXE_UDP_PACKET))) + { + printf("pxe_udp_write(): failed to send data.\n"); + return (-1); + } + + return (buflen); +} Index: user/sbruno/pxe_http/pxe_udp.h =================================================================== --- user/sbruno/pxe_http/pxe_udp.h (nonexistent) +++ user/sbruno/pxe_http/pxe_udp.h (revision 245442) @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2007 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef PXE_UDP_H_INCLUDED +#define PXE_UDP_H_INCLUDED + +/* + * UDP related declarations + * Reference: RFC 768 + */ + +#include +#include + +#include "../libi386/pxe.h" + +/* define to use default UDP socket, for incoming packets if there are no + * filters, sockets and etc + */ +/* #define UDP_DEFAULT_SOCKET */ +/* UDP number in IP stack */ +#define PXE_UDP_PROTOCOL 0x11 + +/* UDP header */ +typedef struct pxe_udp_hdr { + + uint16_t src_port; /* source port */ + uint16_t dst_port; /* destination port */ + uint16_t length; /* packet total length, + * including this header + */ + uint16_t checksum; /* header, pseudo header and + * data checksum + */ +} __packed PXE_UDP_HDR; + +typedef struct pxe_udp_packet { + + PXE_IP_HDR iphdr; + PXE_UDP_HDR udphdr; +} __packed PXE_UDP_PACKET; + +#define PXE_MAGIC_DGRAM 0x26101982 + +/* structure is used to store datagrams in receive buffer of socket */ +typedef struct pxe_udp_dgram { + + uint32_t magic; /* magic for debug purposes */ + PXE_IPADDR src; /* ip of dgram sender */ + uint16_t src_port; /* source port */ + uint16_t size; /* size of datagram */ + +} PXE_UDP_DGRAM; + +/* UDP module init */ +void pxe_udp_init(); + +/* UDP module shutdown routine */ +void pxe_udp_shutdown(); + +/* sends udp packet */ +int pxe_udp_send(void *data, const PXE_IPADDR *dst, uint16_t dst_port, + uint16_t src_port, uint16_t size); + +/* writes data to udp socket */ +/* int pxe_udp_write(PXE_SOCKET *sock, void *buf, uint16_t buflen); */ + +/* reads data from udp socket */ +/*int pxe_udp_read(PXE_SOCKET *sock, void *tobuf, uint16_t buflen, + PXE_UDP_DGRAM *dgram_out);*/ + + +#endif // PXE_IP_H_INCLUDED Index: user/sbruno/pxe_http/socketfs.c =================================================================== --- user/sbruno/pxe_http/socketfs.c (nonexistent) +++ user/sbruno/pxe_http/socketfs.c (revision 245442) @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 2008 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#include +#include + +#include "pxe_core.h" +#include "pxe_ip.h" +#include "pxe_sock.h" +#include "socketfs.h" + +static int socket_open(const char *path, struct open_file *f); +static int socket_close(struct open_file *f); +static int socket_read(struct open_file *f, void *buf, size_t size, + size_t *resid); +static int socket_write(struct open_file *f, void *buf, size_t size, + size_t *resid); +static off_t socket_seek(struct open_file *f, off_t offset, int where); +static int socket_stat(struct open_file *f, struct stat *sb); + +struct fs_ops socket_fsops = { + "socketfs", + socket_open, + socket_close, + socket_read, + socket_write, + socket_seek, + socket_stat, + null_readdir +}; + +void +handle_cleanup(PXE_SOCKET_HANDLE *socketfile) +{ + if (socketfile == NULL) + return; + + if (socketfile->socket != -1) + pxe_close(socketfile->socket); + + free(socketfile); +} + +static int +socket_open(const char *path, struct open_file *f) +{ +#ifdef PXE_HTTP_DEBUG + printf("socket_open(): %s\n", path); +#endif + PXE_SOCKET_HANDLE *socketfile = + (PXE_SOCKET_HANDLE *)malloc(sizeof(PXE_SOCKET_HANDLE)); + + if (socketfile == NULL) + return (ENOMEM); + + pxe_memset(socketfile, 0, sizeof(PXE_SOCKET_HANDLE)); + + socketfile->offset = 0; + socketfile->socket = -1; + + /* DUMMY: need to get port, protocol and address from string */ + PXE_IPADDR *addr = pxe_gethostbyname(path[4]); + int port = 80; + + if (addr == NULL) { + handle_cleanup(socketfile); + return (EINVAL); + } + + socketfile->socket = pxe_socket(); + + if (socketfile->socket == -1) { + handle_cleanup(socketfile); + return (EROFS); + } + + if (-1 == pxe_connect(socketfile->socket, addr, port, PXE_TCP_PROTOCOL)) { + handle_cleanup(socketfile); + return (EROFS); + } + + f->f_fsdata = (void *) socketfile; + + return (0); +} + +static int +socket_read(struct open_file *f, void *addr, size_t size, size_t *resid) +{ + PXE_SOCKET_HANDLE *socketfile = (PXE_SOCKET_HANDLE *) f->f_fsdata; + int result = -1; + + if (socketfile == NULL) { + printf("socket_read(): NULL file descriptor.\n"); + return (EINVAL); + } + + result = pxe_recv(socketfile->socket, addr, size, PXE_SOCK_BLOCKING); + + if (result == -1) { + printf("socket_read(): failed to read\n"); + return (EINVAL); + } + + socketfile->offset += result; + + if (resid) + *resid = size - result; + + return (0); +} + +static int +socket_close(struct open_file *f) +{ + PXE_SOCKET_HANDLE *socketfile = (PXE_SOCKET_HANDLE *) f->f_fsdata; + handle_cleanup(socketfile); + + return (0); +} + +static int +socket_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + PXE_SOCKET_HANDLE *socketfile = (PXE_SOCKET_HANDLE *) f->f_fsdata; + + if (socketfile == NULL) { + printf("socket_write(): NULL file descriptor.\n"); + return (EINVAL); + } + + int result = pxe_send(socketfile->socket, start, size); + + if (result == -1) { + printf("socket_write(): failed to write\n"); + return (EINVAL); + } + + if (resid) + *resid = size - result; + + return (0); +} + +static int +socket_stat(struct open_file *f, struct stat *sb) +{ + PXE_SOCKET_HANDLE *socketfile = (PXE_SOCKET_HANDLE *) f->f_fsdata; + + sb->st_mode = 0666 | S_IFREG; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + + sb->st_size = -1; + + return (0); +} + +static off_t +socket_seek(struct open_file *f, off_t offset, int where) +{ + errno = EOFFSET; + + return (-1); +} Index: user/sbruno/pxe_http/socketfs.h =================================================================== --- user/sbruno/pxe_http/socketfs.h (nonexistent) +++ user/sbruno/pxe_http/socketfs.h (revision 245442) @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2008 Alexey Tarasov + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + */ + +#ifndef SOCKETFS_INCLUDED +#define SOCKETFS_INCLUDED + +/* + * Implements httpfs - allows working with PXE sockets as with files + */ + +#include + +extern struct fs_ops socket_fsops; + +typedef struct pxe_socket_handle { + + int socket; + off_t offset; /* current offset in stream from start + * of reading */ +} PXE_SOCKET_HANDLE; + + +#endif