BTARGET = version.gen version.h version.mk
BOBJECTS = $(BTARGET) \
mbr/*.bin \
- core/pxelinux.0 core/isolinux.bin core/isolinux-debug.bin \
+ core/pxelinux.0 core/lpxelinux.0 \
+ core/isolinux.bin core/isolinux-debug.bin \
gpxe/gpxelinux.0 dos/syslinux.com \
win32/syslinux.exe win64/syslinux64.exe \
dosutil/*.com dosutil/*.sys \
# Things to install in /usr/lib/syslinux
INSTALL_AUX = core/pxelinux.0 gpxe/gpxelinux.0 gpxe/gpxelinuxk.0 \
core/isolinux.bin core/isolinux-debug.bin \
- dos/syslinux.com \
+ dos/syslinux.com core/lpxelinux.0 \
mbr/*.bin $(INSTALLABLE_MODULES)
INSTALL_AUX_OPT = win32/syslinux.exe win64/syslinux64.exe
INSTALL_DIAG = diag/mbr/handoff.bin \
EXTBOOTINSTALL = $(INSTALLABLE_MODULES)
# Things to install in /tftpboot
-NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 \
+NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 core/lpxelinux.0 \
$(INSTALLABLE_MODULES)
all:
OPTFLAGS =
INCLUDES = -I./include -I$(com32)/include -I$(com32)/lib \
- -I./lwip/src/include -I./lwip/src/include/ipv4
+ -I./lwip/src/include -I./lwip/src/include/ipv4 -I./fs/pxe
# This is very similar to cp437; technically it's for Norway and Denmark,
# but it's unlikely the characters that are different will be used in
# The targets to build in this directory...
BTARGET = kwdhash.gen \
ldlinux.bss ldlinux.sys ldlinux.bin \
- isolinux.bin isolinux-debug.bin pxelinux.0
+ isolinux.bin isolinux-debug.bin pxelinux.0 lpxelinux.0
# All primary source files for the main syslinux files
NASMSRC := $(wildcard *.asm)
COBJ := $(patsubst %.c,%.o,$(CSRC))
SOBJ := $(patsubst %.S,%.o,$(SSRC))
-# Don't include console objects
-COBJS = $(filter-out ./rawcon.o ./plaincon.o,$(COBJ))
+# To make this compatible with the following $(filter-out), make sure
+# we prefix everything with ./
+CORE_PXE_CSRC = \
+ $(addprefix ./fs/pxe/, dhcp_option.c pxe.c tftp.c urlparse.c)
+
+LPXELINUX_CSRC = $(CORE_PXE_CSRC) \
+ $(shell find ./lwip -name '*.c' -print) \
+ $(addprefix ./fs/pxe/, \
+ core.c dnsresolv.c ftp.c ftp_readdir.c gpxeurl.c http.c \
+ http_readdir.c idle.c isr.c tcp.c)
+
+PXELINUX_CSRC = $(CORE_PXE_CSRC) \
+ $(shell find ./legacynet -name '*.c' -print)
+
+LPXELINUX_OBJS = $(LPXELINUX_CSRC:%.c=%.o)
+PXELINUX_OBJS = $(PXELINUX_CSRC:%.c=%.o)
+
+# Don't include console and network stack specific objects
+FILTER_OBJS = ./rawcon.o ./plaincon.o $(LPXELINUX_OBJS) $(PXELINUX_OBJS)
+COBJS = $(filter-out $(FILTER_OBJS),$(COBJ))
+SOBJS = $(filter-out $(FILTER_OBJS),$(SOBJ))
LIB = libcom32.a
LIBS = $(LIB) --whole-archive $(com32)/lib/libcom32core.a
LIBDEP = $(filter-out -% %start%,$(LIBS))
-LIBOBJS = $(COBJS) $(SOBJ)
+LIBOBJS = $(COBJS) $(SOBJS)
NASMDEBUG = -g -F dwarf
NASMOPT += $(NASMDEBUG)
-DHEXDATE="$(HEXDATE)" \
-l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $<
-AUXLIBS = libisolinux.a libisolinux-debug.a libldlinux.a libpxelinux.a
+AUXLIBS = libisolinux.a libisolinux-debug.a libldlinux.a \
+ libpxelinux.a liblpxelinux.a
%.elf: %.o $(LIBDEP) syslinux.ld $(AUXLIBS)
$(LD) $(LDFLAGS) -Bsymbolic -pie -E --hash-style=gnu -T syslinux.ld -M -o $@ $< \
libisolinux-debug.a: libisolinux.a
cp $^ $@
-libpxelinux.a: libisolinux.a
- cp $^ $@
+# Legacy network stack
+libpxelinux.a: rawcon.o $(PXELINUX_OBJS)
+ rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+ rm $(PXELINUX_OBJS)
+
+# LwIP network stack
+liblpxelinux.a: rawcon.o
+ $(MAKE) CFLAGS="$(CFLAGS) -DIS_LPXELINUX" $(LPXELINUX_OBJS)
+ rm -f $@
+ $(AR) cq $@ $^ $(LPXELINUX_OBJS)
+ $(RANLIB) $@
+ rm $(LPXELINUX_OBJS)
libldlinux.a: plaincon.o
rm -f $@
$(AR) cq $@ $^
$(RANLIB) $@
+pxelinux.o: pxelinux.asm kwdhash.gen ../version.gen
+ $(NASM) -f elf $(NASMOPT) -DDATE_STR="'$(DATE)'" \
+ -DHEXDATE="$(HEXDATE)" \
+ -DIS_LPXELINUX=0 \
+ -l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $<
+
pxelinux.0: pxelinux.bin
cp -f $< $@
+lpxelinux.o: pxelinux.asm kwdhash.gen ../version.gen
+ $(NASM) -f elf $(NASMOPT) -DDATE_STR="'$(DATE)'" \
+ -DHEXDATE="$(HEXDATE)" \
+ -DIS_LPXELINUX=1 \
+ -l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $<
+
+lpxelinux.0: lpxelinux.bin
+ cp -f $< $@
+
ldlinux.bss: ldlinux.bin
dd if=$< of=$@ bs=512 count=1
--- /dev/null
+#include <syslinux/pxe_api.h>
+#include <lwip/api.h>
+#include <lwip/tcpip.h>
+#include <lwip/dns.h>
+#include <core.h>
+#include <net.h>
+#include "pxe.h"
+
+/**
+ * Open a socket
+ *
+ * @param:socket, the socket to open
+ * @param:proto, the protocol of the new connection
+ *
+ * @out: error code, 0 on success, -1 on failure
+ */
+int net_core_open(struct pxe_pvt_inode *socket, enum net_core_proto proto)
+{
+ struct net_private *priv = &socket->private;
+ enum netconn_type type;
+ int err;
+
+ switch (proto) {
+ case NET_CORE_TCP:
+ type = NETCONN_TCP;
+ break;
+ case NET_CORE_UDP:
+ type = NETCONN_UDP;
+ break;
+ default:
+ type = NETCONN_INVALID;
+ break;
+ }
+
+ priv->conn = netconn_new(type);
+ if (!priv->conn)
+ return -1;
+
+ priv->conn->recv_timeout = 15; /* A 15 ms recv timeout... */
+ err = netconn_bind(priv->conn, NULL, 0);
+ if (err) {
+ printf("netconn_bind error %d\n", err);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Close a socket
+ *
+ * @param:socket, the socket to open
+ */
+void net_core_close(struct pxe_pvt_inode *socket)
+{
+ struct net_private *priv = &socket->private;
+
+ if (priv->conn) {
+ netconn_delete(priv->conn);
+ priv->conn = NULL;
+ }
+}
+
+/**
+ * Establish a connection on an open socket
+ *
+ * @param:socket, the open socket
+ * @param:ip, the ip address
+ * @param:port, the port number, host-byte order
+ */
+void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip,
+ uint16_t port)
+{
+ struct net_private *priv = &socket->private;
+ struct ip_addr addr;
+
+ addr.addr = ip;
+ netconn_connect(priv->conn, &addr, port);
+}
+
+/**
+ * Tear down a connection on an open socket
+ *
+ * @param:socket, the open socket
+ */
+void net_core_disconnect(struct pxe_pvt_inode *socket)
+{
+ struct net_private *priv = &socket->private;
+ netconn_disconnect(priv->conn);
+}
+
+/**
+ * Read data from the network stack
+ *
+ * @param:socket, the open socket
+ * @param:buf, location of buffer to store data
+ * @param:buf_len, size of buffer
+
+ * @out: src_ip, ip address of the data source
+ * @out: src_port, port number of the data source, host-byte order
+ */
+int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
+ uint32_t *src_ip, uint16_t *src_port)
+{
+ struct net_private *priv = &socket->private;
+ struct netbuf *nbuf;
+ u16_t nbuf_len;
+ int err;
+
+ err = netconn_recv(priv->conn, &nbuf);
+ if (err)
+ return err;
+
+ if (!nbuf)
+ return -1;
+
+ *src_ip = netbuf_fromaddr(nbuf)->addr;
+ *src_port = netbuf_fromport(nbuf);
+
+ netbuf_first(nbuf); /* XXX needed? */
+ nbuf_len = netbuf_len(nbuf);
+ if (nbuf_len <= *buf_len)
+ netbuf_copy(nbuf, buf, nbuf_len);
+ else
+ nbuf_len = 0; /* impossible mtu < PKTBUF_SIZE */
+ netbuf_delete(nbuf);
+
+ *buf_len = nbuf_len;
+ return 0;
+}
+
+/**
+ * Send a UDP packet.
+ *
+ * @param:socket, the open socket
+ * @param:data, data buffer to send
+ * @param:len, size of data bufer
+ */
+void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
+{
+ struct netconn *conn = socket->private.conn;
+ struct netbuf *nbuf;
+ void *pbuf;
+ int err;
+
+ nbuf = netbuf_new();
+ if (!nbuf) {
+ printf("netbuf allocation error\n");
+ return;
+ }
+
+ pbuf = netbuf_alloc(nbuf, len);
+ if (!pbuf) {
+ printf("pbuf allocation error\n");
+ goto out;
+ }
+
+ memcpy(pbuf, data, len);
+
+ err = netconn_send(conn, nbuf);
+ if (err) {
+ printf("netconn_send error %d\n", err);
+ goto out;
+ }
+
+out:
+ netbuf_delete(nbuf);
+}
+
+/**
+ * Network stack-specific initialization
+ */
+void net_core_init(void)
+{
+ int err;
+ int i;
+
+ http_bake_cookies();
+
+ /* Initialize lwip */
+ tcpip_init(NULL, NULL);
+
+ /* Start up the undi driver for lwip */
+ err = undiif_start(IPInfo.myip, IPInfo.netmask, IPInfo.gateway);
+ if (err) {
+ printf("undiif driver failed to start: %d\n", err);
+ kaboom();
+ }
+
+ for (i = 0; i < DNS_MAX_SERVERS; i++) {
+ /* Transfer the DNS information to lwip */
+ dns_setserver(i, (struct ip_addr *)&dns_server[i]);
+ }
+}
+
+void probe_undi(void)
+{
+ /* Probe UNDI information */
+ pxe_call(PXENV_UNDI_GET_INFORMATION, &pxe_undi_info);
+ pxe_call(PXENV_UNDI_GET_IFACE_INFO, &pxe_undi_iface);
+
+ printf("UNDI: baseio %04x int %d MTU %d type %d \"%s\" flags 0x%x\n",
+ pxe_undi_info.BaseIo, pxe_undi_info.IntNumber,
+ pxe_undi_info.MaxTranUnit, pxe_undi_info.HwType,
+ pxe_undi_iface.IfaceType, pxe_undi_iface.ServiceFlags);
+}
+
*q++ = '\n';
cmd_len += 2;
- err = netconn_write(socket->conn, cmd_buf, cmd_len, NETCONN_COPY);
+ err = netconn_write(socket->private.conn, cmd_buf, cmd_len, NETCONN_COPY);
if (err)
return -1;
}
int resp;
ctlsock = socket->ctl ? PVT(socket->ctl) : NULL;
- if (ctlsock->conn) {
+ if (ctlsock->private.conn) {
resp = ftp_cmd_response(socket->ctl, "QUIT", NULL, NULL, NULL);
while (resp == 226) {
resp = ftp_cmd_response(socket->ctl, NULL, NULL, NULL, NULL);
return;
ctlsock = PVT(socket->ctl);
ctlsock->ops = &tcp_conn_ops; /* The control connection is just TCP */
- ctlsock->conn = netconn_new(NETCONN_TCP);
- if (!ctlsock->conn)
+ ctlsock->private.conn = netconn_new(NETCONN_TCP);
+ if (!ctlsock->private.conn)
goto err_free;
addr.addr = url->ip;
- err = netconn_connect(ctlsock->conn, &addr, url->port);
+ err = netconn_connect(ctlsock->private.conn, &addr, url->port);
if (err)
goto err_delete;
if (resp != 227 || pasv_bytes != 6)
goto err_disconnect;
- socket->conn = netconn_new(NETCONN_TCP);
- if (!socket->conn)
+ socket->private.conn = netconn_new(NETCONN_TCP);
+ if (!socket->private.conn)
goto err_disconnect;
- err = netconn_connect(socket->conn, (struct ip_addr *)&pasv_data[0],
+ err = netconn_connect(socket->private.conn, (struct ip_addr *)&pasv_data[0],
ntohs(*(uint16_t *)&pasv_data[4]));
if (err)
goto err_disconnect;
return; /* Sucess! */
err_disconnect:
- if (ctlsock->conn)
- netconn_write(ctlsock->conn, "QUIT\r\n", 6, NETCONN_NOCOPY);
- if (socket->conn)
- netconn_delete(socket->conn);
- if (ctlsock->buf)
- netbuf_delete(ctlsock->buf);
+ if (ctlsock->private.conn)
+ netconn_write(ctlsock->private.conn, "QUIT\r\n", 6, NETCONN_NOCOPY);
+ if (socket->private.conn)
+ netconn_delete(socket->private.conn);
+ if (ctlsock->private.buf)
+ netbuf_delete(ctlsock->private.buf);
err_delete:
- if (ctlsock->conn)
- netconn_delete(ctlsock->conn);
+ if (ctlsock->private.conn)
+ netconn_delete(ctlsock->private.conn);
err_free:
free_socket(socket->ctl);
}
inode->size = content_length = -1;
/* Start the http connection */
- socket->conn = netconn_new(NETCONN_TCP);
- if (!socket->conn) {
+ socket->private.conn = netconn_new(NETCONN_TCP);
+ if (!socket->private.conn) {
printf("netconn_new failed\n");
return;
}
if (!url->port)
url->port = HTTP_PORT;
- err = netconn_connect(socket->conn, &addr, url->port);
+ err = netconn_connect(socket->private.conn, &addr, url->port);
if (err) {
printf("netconn_connect error %d\n", err);
goto fail;
if (header_bytes >= header_len)
goto fail; /* Buffer overflow */
- err = netconn_write(socket->conn, header_buf,
+ err = netconn_write(socket->private.conn, header_buf,
header_bytes, NETCONN_NOCOPY);
if (err) {
printf("netconn_write error %d\n", err);
#include <minmax.h>
#include <fcntl.h>
#include <sys/cpu.h>
-#include <lwip/api.h>
-#include <lwip/dns.h>
-#include <lwip/tcpip.h>
-#include <lwip/opt.h>
#include "pxe.h"
#include "thread.h"
#include "url.h"
#include "tftp.h"
+#include <net.h>
__lowmem t_PXENV_UNDI_GET_INFORMATION pxe_undi_info;
__lowmem t_PXENV_UNDI_GET_IFACE_INFO pxe_undi_iface;
int ok_flags;
} url_schemes[] = {
{ "tftp", tftp_open, 0 },
+#ifdef IS_LPXELINUX
{ "http", http_open, O_DIRECTORY },
{ "ftp", ftp_open, O_DIRECTORY },
+#endif
{ NULL, NULL, 0 },
};
#define OK_FLAGS_MASK (O_DIRECTORY|O_WRONLY)
real_base_mem = max(code_seg, data_seg) >> 6; /* Convert to kilobytes */
- /* Probe UNDI information */
- pxe_call(PXENV_UNDI_GET_INFORMATION, &pxe_undi_info);
- pxe_call(PXENV_UNDI_GET_IFACE_INFO, &pxe_undi_iface);
-
- printf("UNDI: baseio %04x int %d MTU %d type %d \"%s\" flags 0x%x\n",
- pxe_undi_info.BaseIo, pxe_undi_info.IntNumber,
- pxe_undi_info.MaxTranUnit, pxe_undi_info.HwType,
- pxe_undi_iface.IfaceType, pxe_undi_iface.ServiceFlags);
+ probe_undi();
return 0;
}
*/
static void network_init(void)
{
- int err;
int pkt_len;
- int i;
struct bootp_t *bp;
const size_t dhcp_max_packet = 4096;
if (have_uuid)
sysappend_set_uuid(uuid);
ip_init();
- /* print_sysappend(); */
- http_bake_cookies();
+ /* print_sysappend(); */
/*
* Check to see if we got any PXELINUX-specific DHCP options; in particular,
* if we didn't get the magic enable, do not recognize any other options.
if ((DHCPMagic & 1) == 0)
DHCPMagic = 0;
- /* Initialize lwip */
- tcpip_init(NULL, NULL);
-
- /* Start up the undi driver for lwip */
- err = undiif_start(IPInfo.myip, IPInfo.netmask, IPInfo.gateway);
- if (err) {
- printf("undiif driver failed to start: %d\n", err);
- kaboom();
- }
-
- for (i = 0; i < DNS_MAX_SERVERS; i++) {
- /* Transfer the DNS information to lwip */
- dns_setserver(i, (struct ip_addr *)&dns_server[i]);
- }
+ net_core_init();
}
/*
int (*readdir)(struct inode *inode, struct dirent *dirent);
};
-struct pxe_pvt_inode {
+struct net_private {
+#ifdef IS_LPXELINUX
struct netconn *conn; /* lwip network connection */
struct netbuf *buf; /* lwip cached buffer */
- uint16_t tftp_remoteport; /* Remote port number */
- uint32_t tftp_filepos; /* bytes downloaded (including buffer) */
- uint32_t tftp_blksize; /* Block size for this connection(*) */
- uint16_t tftp_bytesleft; /* Unclaimed data bytes */
- uint16_t tftp_lastpkt; /* Sequence number of last packet (HBO) */
- char *tftp_dataptr; /* Pointer to available data */
- uint8_t tftp_goteof; /* 1 if the EOF packet received */
- uint8_t tftp_unused[3]; /* Currently unused */
- char *tftp_pktbuf; /* Packet buffer */
- struct inode *ctl; /* Control connection (for FTP) */
+#else
+ uint16_t tftp_localport; /* Local port number (0=not in use) */
+ uint32_t tftp_remoteip; /* Remote IP address (0 = disconnected) */
+#endif
+
+};
+
+struct pxe_pvt_inode {
+ struct net_private private; /* Network stack private data */
+ uint16_t tftp_remoteport; /* Remote port number */
+ uint32_t tftp_filepos; /* bytes downloaded (including buffer) */
+ uint32_t tftp_blksize; /* Block size for this connection(*) */
+ uint16_t tftp_bytesleft; /* Unclaimed data bytes */
+ uint16_t tftp_lastpkt; /* Sequence number of last packet (HBO) */
+ char *tftp_dataptr; /* Pointer to available data */
+ uint8_t tftp_goteof; /* 1 if the EOF packet received */
+ uint8_t tftp_unused[3]; /* Currently unused */
+ char *tftp_pktbuf; /* Packet buffer */
+ struct inode *ctl; /* Control connection (for FTP) */
const struct pxe_conn_ops *ops;
};
extern uint8_t uuid[];
/*
+ * Compute the suitable gateway for a specific route -- too many
+ * vendor PXE stacks don't do this correctly...
+ */
+static inline uint32_t gateway(uint32_t ip)
+{
+ if ((ip ^ IPInfo.myip) & IPInfo.netmask)
+ return IPInfo.gateway;
+ else
+ return 0;
+}
+
+/*
* functions
*/
{
struct pxe_pvt_inode *socket = PVT(inode);
- if (socket->conn) {
- netconn_delete(socket->conn);
- socket->conn = NULL;
+ if (socket->private.conn) {
+ netconn_delete(socket->private.conn);
+ socket->private.conn = NULL;
}
- if (socket->buf) {
- netbuf_delete(socket->buf);
- socket->buf = NULL;
+ if (socket->private.buf) {
+ netbuf_delete(socket->private.buf);
+ socket->private.buf = NULL;
}
}
err_t err;
/* Clean up or advance an inuse netbuf */
- if (socket->buf) {
- if (netbuf_next(socket->buf) < 0) {
- netbuf_delete(socket->buf);
- socket->buf = NULL;
+ if (socket->private.buf) {
+ if (netbuf_next(socket->private.buf) < 0) {
+ netbuf_delete(socket->private.buf);
+ socket->private.buf = NULL;
}
}
/* If needed get a new netbuf */
- if (!socket->buf) {
- err = netconn_recv(socket->conn, &(socket->buf));
- if (!socket->buf || err) {
+ if (!socket->private.buf) {
+ err = netconn_recv(socket->private.conn, &(socket->private.buf));
+ if (!socket->private.buf || err) {
socket->tftp_goteof = 1;
if (inode->size == -1)
inode->size = socket->tftp_filepos;
}
}
/* Report the current fragment of the netbuf */
- err = netbuf_data(socket->buf, &data, &len);
+ err = netbuf_data(socket->private.buf, &data, &len);
if (err) {
printf("netbuf_data err: %d\n", err);
kaboom();
#include <minmax.h>
-#include <lwip/api.h>
+#include <net.h>
#include "pxe.h"
#include "url.h"
#include "tftp.h"
-static const uint8_t TimeoutTable[] = {
+const uint8_t TimeoutTable[] = {
2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44,
53, 64, 77, 92, 110, 132, 159, 191, 229, 255, 255, 255, 255, 0
};
if (!socket->tftp_goteof) {
tftp_error(inode, 0, "No error, file close");
}
- if (socket->conn) {
- netconn_delete(socket->conn);
- socket->conn = NULL;
- }
-}
-
-/*
- * Send a UDP packet.
- */
-static void udp_send(struct netconn *conn, const void *data, size_t len)
-{
- struct netbuf *nbuf;
- void *pbuf;
- int err;
-
- nbuf = netbuf_new();
- if (!nbuf) {
- printf("netbuf allocation error\n");
- return;
- }
-
- pbuf = netbuf_alloc(nbuf, len);
- if (!pbuf) {
- printf("pbuf allocation error\n");
- goto out;
- }
-
- memcpy(pbuf, data, len);
-
- err = netconn_send(conn, nbuf);
- if (err) {
- printf("netconn_send error %d\n", err);
- goto out;
- }
-
-out:
- netbuf_delete(nbuf);
+ net_core_close(socket);
}
/**
memcpy(err_buf.err_msg, errstr, len);
err_buf.err_msg[len] = '\0';
- udp_send(socket->conn, &err_buf, 4 + len + 1);
+ net_core_send(socket, &err_buf, 4 + len + 1);
}
/**
ack_packet_buf[0] = TFTP_ACK;
ack_packet_buf[1] = htons(ack_num);
- udp_send(socket->conn, ack_packet_buf, 4);
+ net_core_send(socket, ack_packet_buf, 4);
}
/*
uint16_t serial;
jiffies_t oldtime;
struct tftp_packet *pkt = NULL;
- struct netbuf *nbuf;
- u16_t nbuf_len;
+ uint16_t buf_len;
struct pxe_pvt_inode *socket = PVT(inode);
- err_t err;
+ uint16_t src_port;
+ uint32_t src_ip;
+ int err;
/*
* Start by ACKing the previous packet; this should cause
ack_packet(inode, socket->tftp_lastpkt);
while (timeout) {
- err = netconn_recv(socket->conn, &nbuf);
- if (!nbuf || err) {
+ buf_len = socket->tftp_blksize + 4;
+ err = net_core_recv(socket, socket->tftp_pktbuf, &buf_len,
+ &src_ip, &src_port);
+ if (err) {
jiffies_t now = jiffies();
if (now-oldtime >= timeout) {
continue;
}
- netbuf_first(nbuf);
- nbuf_len = 0;
- nbuf_len = netbuf_len(nbuf);
- if (nbuf_len <= socket->tftp_blksize + 4)
- netbuf_copy(nbuf, socket->tftp_pktbuf, nbuf_len);
- else
- nbuf_len = 0; /* invalid packet */
- netbuf_delete(nbuf);
- if (nbuf_len < 4) /* Bad size for a DATA packet */
+ if (buf_len < 4) /* Bad size for a DATA packet */
continue;
pkt = (struct tftp_packet *)(socket->tftp_pktbuf);
/* It's the packet we want. We're also EOF if the size < blocksize */
socket->tftp_lastpkt = last_pkt; /* Update last packet number */
- buffersize = nbuf_len - 4; /* Skip TFTP header */
+ buffersize = buf_len - 4; /* Skip TFTP header */
socket->tftp_dataptr = socket->tftp_pktbuf + 4;
socket->tftp_filepos += buffersize;
socket->tftp_bytesleft = buffersize;
{
struct pxe_pvt_inode *socket = PVT(inode);
char *buf;
- struct netbuf *nbuf;
- u16_t nbuf_len;
+ uint16_t buf_len;
char *p;
char *options;
char *data;
uint16_t opcode;
uint16_t blk_num;
uint32_t opdata, *opdata_ptr;
- struct ip_addr addr;
+ uint16_t src_port;
+ uint32_t src_ip;
(void)redir; /* TFTP does not redirect */
(void)flags;
url->port = TFTP_PORT;
socket->ops = &tftp_conn_ops;
- socket->conn = netconn_new(NETCONN_UDP);
- if (!socket->conn)
+ if (net_core_open(socket, NET_CORE_UDP))
return;
- socket->conn->recv_timeout = 15; /* A 15 ms recv timeout... */
- err = netconn_bind(socket->conn, NULL, 0);
- if (err) {
- printf("netconn_bind error %d\n", err);
- return;
- }
-
buf = rrq_packet_buf;
*(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */
buf += 2;
rrq_len = buf - rrq_packet_buf;
timeout_ptr = TimeoutTable; /* Reset timeout */
-
sendreq:
- netconn_disconnect(socket->conn);
+ net_core_disconnect(socket);
timeout = *timeout_ptr++;
if (!timeout)
return; /* No file available... */
oldtime = jiffies();
- addr.addr = url->ip;
- netconn_connect(socket->conn, &addr, url->port);
- udp_send(socket->conn, rrq_packet_buf, rrq_len);
+ net_core_connect(socket, url->ip, url->port);
+ net_core_send(socket, rrq_packet_buf, rrq_len);
/* If the WRITE call fails, we let the timeout take care of it... */
wait_pkt:
- netconn_disconnect(socket->conn);
+ net_core_disconnect(socket);
for (;;) {
- err = netconn_recv(socket->conn, &nbuf);
- if (!nbuf || err) {
+ buf_len = sizeof(reply_packet_buf);
+
+ err = net_core_recv(socket, reply_packet_buf, &buf_len,
+ &src_ip, &src_port);
+ if (err) {
jiffies_t now = jiffies();
if (now - oldtime >= timeout)
goto sendreq;
} else {
/* Make sure the packet actually came from the server */
- bool ok_source;
- ok_source = netbuf_fromaddr(nbuf)->addr == url->ip;
- nbuf_len = netbuf_len(nbuf);
- if (nbuf_len <= PKTBUF_SIZE)
- netbuf_copy(nbuf, reply_packet_buf, nbuf_len);
- else
- nbuf_len = 0; /* impossible mtu < PKTBUF_SIZE */
- netbuf_delete(nbuf);
- if (ok_source)
- break;
+ if (src_ip == url->ip)
+ break;
}
}
- netconn_connect(socket->conn, netbuf_fromaddr(nbuf), netbuf_fromport(nbuf));
+ net_core_disconnect(socket);
+ net_core_connect(socket, src_ip, src_port);
/* filesize <- -1 == unknown */
inode->size = -1;
socket->tftp_blksize = TFTP_BLOCKSIZE;
- buffersize = nbuf_len - 2; /* bytes after opcode */
+ buffersize = buf_len - 2; /* bytes after opcode */
if (buffersize < 0)
goto wait_pkt; /* Garbled reply */
inode->size = 0;
done:
- if (!inode->size) {
- netconn_delete(socket->conn);
- socket->conn = NULL;
- }
+ if (!inode->size)
+ net_core_close(socket);
+
return;
}
--- /dev/null
+#ifndef _NET_H
+#define _NET_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Protocol family */
+enum net_core_proto {
+ NET_CORE_TCP,
+ NET_CORE_UDP,
+};
+
+void net_core_init(void);
+
+struct pxe_pvt_inode;
+
+int net_core_open(struct pxe_pvt_inode *socket, enum net_core_proto proto);
+void net_core_close(struct pxe_pvt_inode *socket);
+
+void net_core_connect(struct pxe_pvt_inode *socket,
+ uint32_t ip, uint16_t port);
+void net_core_disconnect(struct pxe_pvt_inode *socket);
+
+int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
+ uint32_t *src_ip, uint16_t *src_port);
+
+void net_core_send(struct pxe_pvt_inode *socket,
+ const void *data, size_t len);
+
+void probe_undi(void);
+void pxe_init_isr(void);
+
+#endif /* _NET_H */
--- /dev/null
+#include <syslinux/pxe_api.h>
+#include <com32.h>
+#include <core.h>
+#include <net.h>
+#include <pxe.h>
+#include <minmax.h>
+
+/* Common receive buffer */
+static __lowmem char packet_buf[PKTBUF_SIZE] __aligned(16);
+
+extern uint16_t get_port(void);
+extern void free_port(uint16_t);
+
+/**
+ * Open a socket
+ *
+ * @param:socket, the socket to open
+ * @param:proto, the protocol of the new connection
+ *
+ * @out: error code, 0 on success, -1 on failure
+ */
+int net_core_open(struct pxe_pvt_inode *socket __unused,
+ enum net_core_proto proto)
+{
+ struct net_private *priv = &socket->private;
+
+ /* The legacy stack only supports UDP */
+ if (proto != NET_CORE_UDP)
+ return -1;
+
+ /* Allocate local UDP port number */
+ priv->tftp_localport = get_port();
+
+ return 0;
+}
+
+/**
+ * Close a socket
+ *
+ * @param:socket, the socket to open
+ */
+void net_core_close(struct pxe_pvt_inode *socket)
+{
+ struct net_private *priv = &socket->private;
+
+ if (priv->tftp_localport)
+ free_port(priv->tftp_localport);
+}
+
+/**
+ * Establish a connection on an open socket
+ *
+ * @param:socket, the open socket
+ * @param:ip, the ip address
+ * @param:port, the port number, host-byte order
+ */
+void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip,
+ uint16_t port)
+{
+ struct net_private *priv = &socket->private;
+
+ socket->tftp_remoteport = htons(port);
+ priv->tftp_remoteip = ip;
+
+}
+
+/**
+ * Tear down a connection on an open socket
+ *
+ * @param:socket, the open socket
+ */
+void net_core_disconnect(struct pxe_pvt_inode *socket __unused)
+{
+}
+
+/**
+ * Read data from the network stack
+ *
+ * @param:socket, the open socket
+ * @param:buf, location of buffer to store data
+ * @param:buf_len, size of buffer
+
+ * @out: src_ip, ip address of the data source
+ * @out: src_port, port number of the data source, host-byte order
+ */
+int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
+ uint32_t *src_ip, uint16_t *src_port)
+{
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+ struct net_private *priv = &socket->private;
+ uint16_t bytes;
+ int err;
+
+ udp_read.status = 0;
+ udp_read.buffer = FAR_PTR(packet_buf);
+ udp_read.buffer_size = PKTBUF_SIZE;
+ udp_read.dest_ip = IPInfo.myip;
+ udp_read.d_port = priv->tftp_localport;
+
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ if (err)
+ return err;
+
+ if (udp_read.status)
+ return udp_read.status;
+
+ bytes = min(udp_read.buffer_size, *buf_len);
+ memcpy(buf, packet_buf, bytes);
+
+ *src_ip = udp_read.src_ip;
+ *src_port = ntohs(udp_read.s_port);
+ *buf_len = bytes;
+
+ return 0;
+}
+
+/**
+ * Send a UDP packet.
+ *
+ * @param:socket, the open socket
+ * @param:data, data buffer to send
+ * @param:len, size of data bufer
+ */
+void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
+{
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ struct net_private *priv = &socket->private;
+ void *lbuf;
+ uint16_t tid;
+
+ lbuf = lmalloc(len);
+ if (!lbuf)
+ return;
+
+ memcpy(lbuf, data, len);
+
+ tid = priv->tftp_localport; /* TID(local port No) */
+ udp_write.buffer = FAR_PTR(lbuf);
+ udp_write.ip = priv->tftp_remoteip;
+ udp_write.gw = gateway(udp_write.ip);
+ udp_write.src_port = tid;
+ udp_write.dst_port = socket->tftp_remoteport;
+ udp_write.buffer_size = len;
+
+ pxe_call(PXENV_UDP_WRITE, &udp_write);
+
+ lfree(lbuf);
+}
+
+/**
+ * Network stack-specific initialization
+ *
+ * Initialize UDP stack
+ */
+void net_core_init(void)
+{
+ int err;
+ static __lowmem struct s_PXENV_UDP_OPEN udp_open;
+ udp_open.src_ip = IPInfo.myip;
+ err = pxe_call(PXENV_UDP_OPEN, &udp_open);
+ if (err || udp_open.status) {
+ printf("Failed to initialize UDP stack ");
+ printf("%d\n", udp_open.status);
+ kaboom();
+ }
+}
+
+void probe_undi(void)
+{
+}
+
+void pxe_init_isr(void)
+{
+}
+
+int reset_pxe(void)
+{
+ static __lowmem struct s_PXENV_UDP_CLOSE udp_close;
+ int err = 0;
+
+ pxe_idle_cleanup();
+
+ pxe_call(PXENV_UDP_CLOSE, &udp_close);
+
+ return err;
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include "pxe.h"
+
+/* DNS CLASS values we care about */
+#define CLASS_IN 1
+
+/* DNS TYPE values we care about */
+#define TYPE_A 1
+#define TYPE_CNAME 5
+
+/*
+ * The DNS header structure
+ */
+struct dnshdr {
+ uint16_t id;
+ uint16_t flags;
+ /* number of entries in the question section */
+ uint16_t qdcount;
+ /* number of resource records in the answer section */
+ uint16_t ancount;
+ /* number of name server resource records in the authority records section*/
+ uint16_t nscount;
+ /* number of resource records in the additional records section */
+ uint16_t arcount;
+} __attribute__ ((packed));
+
+/*
+ * The DNS query structure
+ */
+struct dnsquery {
+ uint16_t qtype;
+ uint16_t qclass;
+} __attribute__ ((packed));
+
+/*
+ * The DNS Resource recodes structure
+ */
+struct dnsrr {
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t rdlength; /* The lenght of this rr data */
+ char rdata[];
+} __attribute__ ((packed));
+
+
+#define DNS_PORT htons(53) /* Default DNS port */
+#define DNS_MAX_SERVERS 4 /* Max no of DNS servers */
+
+uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
+
+
+/*
+ * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
+ * number of dots encountered. On return, *dst is updated.
+ */
+int dns_mangle(char **dst, const char *p)
+{
+ char *q = *dst;
+ char *count_ptr;
+ char c;
+ int dots = 0;
+
+ count_ptr = q;
+ *q++ = 0;
+
+ while (1) {
+ c = *p++;
+ if (c == 0 || c == ':' || c == '/')
+ break;
+ if (c == '.') {
+ dots++;
+ count_ptr = q;
+ *q++ = 0;
+ continue;
+ }
+
+ *count_ptr += 1;
+ *q++ = c;
+ }
+
+ if (*count_ptr)
+ *q++ = 0;
+
+ /* update the strings */
+ *dst = q;
+ return dots;
+}
+
+
+/*
+ * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_
+ * is allowed pointers relative to a packet in buf.
+ *
+ */
+static bool dns_compare(const void *s1, const void *s2, const void *buf)
+{
+ const uint8_t *q = s1;
+ const uint8_t *p = s2;
+ unsigned int c0, c1;
+
+ while (1) {
+ c0 = p[0];
+ if (c0 >= 0xc0) {
+ /* Follow pointer */
+ c1 = p[1];
+ p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
+ } else if (c0) {
+ c0++; /* Include the length byte */
+ if (memcmp(q, p, c0))
+ return false;
+ q += c0;
+ p += c0;
+ } else {
+ return *q == 0;
+ }
+ }
+}
+
+/*
+ * Copy a DNS label into a buffer, considering the possibility that we might
+ * have to follow pointers relative to "buf".
+ * Returns a pointer to the first free byte *after* the terminal null.
+ */
+static void *dns_copylabel(void *dst, const void *src, const void *buf)
+{
+ uint8_t *q = dst;
+ const uint8_t *p = src;
+ unsigned int c0, c1;
+
+ while (1) {
+ c0 = p[0];
+ if (c0 >= 0xc0) {
+ /* Follow pointer */
+ c1 = p[1];
+ p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
+ } else if (c0) {
+ c0++; /* Include the length byte */
+ memcpy(q, p, c0);
+ p += c0;
+ q += c0;
+ } else {
+ *q++ = 0;
+ return q;
+ }
+ }
+}
+
+/*
+ * Skip past a DNS label set in DS:SI
+ */
+static char *dns_skiplabel(char *label)
+{
+ uint8_t c;
+
+ while (1) {
+ c = *label++;
+ if (c >= 0xc0)
+ return ++label; /* pointer is two bytes */
+ if (c == 0)
+ return label;
+ label += c;
+ }
+}
+
+extern const uint8_t TimeoutTable[];
+extern uint16_t get_port(void);
+extern void free_port(uint16_t port);
+
+/*
+ * Actual resolver function
+ * Points to a null-terminated or :-terminated string in _name_
+ * and returns the ip addr in _ip_ if it exists and can be found.
+ * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
+ *
+ * XXX: probably need some caching here.
+ */
+__export uint32_t dns_resolv(const char *name)
+{
+ static char __lowmem DNSSendBuf[PKTBUF_SIZE];
+ static char __lowmem DNSRecvBuf[PKTBUF_SIZE];
+ char *p;
+ int err;
+ int dots;
+ int same;
+ int rd_len;
+ int ques, reps; /* number of questions and replies */
+ uint8_t timeout;
+ const uint8_t *timeout_ptr = TimeoutTable;
+ uint32_t oldtime;
+ uint32_t srv;
+ uint32_t *srv_ptr;
+ struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf;
+ struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf;
+ struct dnsquery *query;
+ struct dnsrr *rr;
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+ uint16_t local_port;
+ uint32_t result = 0;
+
+ /*
+ * Return failure on an empty input... this can happen during
+ * some types of URL parsing, and this is the easiest place to
+ * check for it.
+ */
+ if (!name || !*name)
+ return 0;
+
+ /* Make sure we have at least one valid DNS server */
+ if (!dns_server[0])
+ return 0;
+
+ /* Get a local port number */
+ local_port = get_port();
+
+ /* First, fill the DNS header struct */
+ hd1->id++; /* New query ID */
+ hd1->flags = htons(0x0100); /* Recursion requested */
+ hd1->qdcount = htons(1); /* One question */
+ hd1->ancount = 0; /* No answers */
+ hd1->nscount = 0; /* No NS */
+ hd1->arcount = 0; /* No AR */
+
+ p = DNSSendBuf + sizeof(struct dnshdr);
+ dots = dns_mangle(&p, name); /* store the CNAME */
+
+ if (!dots) {
+ p--; /* Remove final null */
+ /* Uncompressed DNS label set so it ends in null */
+ p = stpcpy(p, LocalDomain);
+ }
+
+ /* Fill the DNS query packet */
+ query = (struct dnsquery *)p;
+ query->qtype = htons(TYPE_A);
+ query->qclass = htons(CLASS_IN);
+ p += sizeof(struct dnsquery);
+
+ /* Now send it to name server */
+ timeout_ptr = TimeoutTable;
+ timeout = *timeout_ptr++;
+ srv_ptr = dns_server;
+ while (timeout) {
+ srv = *srv_ptr++;
+ if (!srv) {
+ srv_ptr = dns_server;
+ srv = *srv_ptr++;
+ }
+
+ udp_write.status = 0;
+ udp_write.ip = srv;
+ udp_write.gw = gateway(srv);
+ udp_write.src_port = local_port;
+ udp_write.dst_port = DNS_PORT;
+ udp_write.buffer_size = p - DNSSendBuf;
+ udp_write.buffer = FAR_PTR(DNSSendBuf);
+ err = pxe_call(PXENV_UDP_WRITE, &udp_write);
+ if (err || udp_write.status)
+ continue;
+
+ oldtime = jiffies();
+ do {
+ if (jiffies() - oldtime >= timeout)
+ goto again;
+
+ udp_read.status = 0;
+ udp_read.src_ip = srv;
+ udp_read.dest_ip = IPInfo.myip;
+ udp_read.s_port = DNS_PORT;
+ udp_read.d_port = local_port;
+ udp_read.buffer_size = PKTBUF_SIZE;
+ udp_read.buffer = FAR_PTR(DNSRecvBuf);
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ } while (err || udp_read.status || hd2->id != hd1->id);
+
+ if ((hd2->flags ^ 0x80) & htons(0xf80f))
+ goto badness;
+
+ ques = htons(hd2->qdcount); /* Questions */
+ reps = htons(hd2->ancount); /* Replies */
+ p = DNSRecvBuf + sizeof(struct dnshdr);
+ while (ques--) {
+ p = dns_skiplabel(p); /* Skip name */
+ p += 4; /* Skip question trailer */
+ }
+
+ /* Parse the replies */
+ while (reps--) {
+ same = dns_compare(DNSSendBuf + sizeof(struct dnshdr),
+ p, DNSRecvBuf);
+ p = dns_skiplabel(p);
+ rr = (struct dnsrr *)p;
+ rd_len = ntohs(rr->rdlength);
+ if (same && ntohs(rr->class) == CLASS_IN) {
+ switch (ntohs(rr->type)) {
+ case TYPE_A:
+ if (rd_len == 4) {
+ result = *(uint32_t *)rr->rdata;
+ goto done;
+ }
+ break;
+ case TYPE_CNAME:
+ dns_copylabel(DNSSendBuf + sizeof(struct dnshdr),
+ rr->rdata, DNSRecvBuf);
+ /*
+ * We should probably rescan the packet from the top
+ * here, and technically we might have to send a whole
+ * new request here...
+ */
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* not the one we want, try next */
+ p += sizeof(struct dnsrr) + rd_len;
+ }
+
+ badness:
+ /*
+ *
+ ; We got back no data from this server.
+ ; Unfortunately, for a recursive, non-authoritative
+ ; query there is no such thing as an NXDOMAIN reply,
+ ; which technically means we can't draw any
+ ; conclusions. However, in practice that means the
+ ; domain doesn't exist. If this turns out to be a
+ ; problem, we may want to add code to go through all
+ ; the servers before giving up.
+
+ ; If the DNS server wasn't capable of recursion, and
+ ; isn't capable of giving us an authoritative reply
+ ; (i.e. neither AA or RA set), then at least try a
+ ; different setver...
+ */
+ if (hd2->flags == htons(0x480))
+ continue;
+
+ break; /* failed */
+
+ again:
+ continue;
+ }
+
+done:
+ free_port(local_port); /* Return port number to the free pool */
+
+ return result;
+}
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+#include <minmax.h>
+#include <sys/cpu.h>
+#include "pxe.h"
+
+static int pxe_idle_poll(void)
+{
+ static __lowmem char junk_pkt[PKTBUF_SIZE];
+ static __lowmem t_PXENV_UDP_READ read_buf;
+
+ memset(&read_buf, 0, sizeof read_buf);
+
+ read_buf.src_ip = 0; /* Any destination */
+ read_buf.dest_ip = IPInfo.myip;
+ read_buf.s_port = 0; /* Any source port */
+ read_buf.d_port = htons(9); /* Discard port (not used...) */
+ read_buf.buffer_size = sizeof junk_pkt;
+ read_buf.buffer = FAR_PTR(junk_pkt);
+
+ pxe_call(PXENV_UDP_READ, &read_buf);
+
+ return 0;
+}
+
+static uint32_t pxe_detect_nic_type(void)
+{
+ static __lowmem t_PXENV_UNDI_GET_NIC_TYPE nic_type;
+
+ if (pxe_call(PXENV_UNDI_GET_NIC_TYPE, &nic_type))
+ return -1; /* Unknown NIC */
+
+ if (nic_type.NicType != PCI_NIC && nic_type.NicType != CardBus_NIC)
+ return -1; /* Not a PCI NIC */
+
+ /*
+ * Return VID:DID as a single number, with the VID in the high word
+ * -- this is opposite from the usual order, but it makes it easier to
+ * enforce that the table is sorted.
+ */
+ return (nic_type.info.pci.Vendor_ID << 16) + nic_type.info.pci.Dev_ID;
+}
+
+#define PCI_DEV(vid, did) (((vid) << 16) + (did))
+
+/* This array should be sorted!! */
+static const uint32_t pxe_need_idle_drain[] =
+{
+ /*
+ * Older Broadcom NICs: they need receive calls on idle to avoid
+ * FIFO stalls.
+ */
+ PCI_DEV(0x14e4, 0x1659), /* BCM5721 */
+ PCI_DEV(0x14e4, 0x165a), /* BCM5722 */
+ PCI_DEV(0x14e4, 0x165b), /* BCM5723 */
+ PCI_DEV(0x14e4, 0x1668), /* BCM5714 */
+ PCI_DEV(0x14e4, 0x1669), /* BCM5714S */
+ PCI_DEV(0x14e4, 0x166a), /* BCM5780 */
+ PCI_DEV(0x14e4, 0x1673), /* BCM5755M */
+ PCI_DEV(0x14e4, 0x1674), /* BCM5756ME */
+ PCI_DEV(0x14e4, 0x1678), /* BCM5715 */
+ PCI_DEV(0x14e4, 0x1679), /* BCM5715S */
+ PCI_DEV(0x14e4, 0x167b), /* BCM5755 */
+};
+
+void pxe_idle_init(void)
+{
+ uint32_t dev_id = pxe_detect_nic_type();
+ int l, h;
+ bool found;
+
+ l = 0;
+ h = sizeof pxe_need_idle_drain / sizeof pxe_need_idle_drain[0] - 1;
+
+ found = false;
+ while (h >= l) {
+ int x = (l+h) >> 1;
+ uint32_t id = pxe_need_idle_drain[x];
+
+ if (id == dev_id) {
+ found = true;
+ break;
+ } else if (id < dev_id) {
+ l = x+1;
+ } else {
+ h = x-1;
+ }
+ }
+
+ if (found)
+ idle_hook_func = pxe_idle_poll;
+}
+
+void pxe_idle_cleanup(void)
+{
+ idle_hook_func = NULL;
+}
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <netinet/in.h>
+#include "pxe.h"
+
+/* Port number bitmap - port numbers 49152 (0xc000) to 57343 (0xefff) */
+#define PORT_NUMBER_BASE 49152
+#define PORT_NUMBER_COUNT 8192 /* Power of 2, please */
+static uint32_t port_number_bitmap[PORT_NUMBER_COUNT/32];
+static uint16_t first_port_number /* = 0 */;
+
+/*
+ * Bitmap functions
+ */
+static bool test_bit(const uint32_t *bitmap, int32_t index)
+{
+ uint8_t st;
+ asm("btl %2,%1 ; setc %0" : "=qm" (st) : "m" (*bitmap), "r" (index));
+ return st;
+}
+
+static void set_bit(uint32_t *bitmap, int32_t index)
+{
+ asm volatile("btsl %1,%0" : "+m" (*bitmap) : "r" (index) : "memory");
+}
+
+static void clr_bit(uint32_t *bitmap, int32_t index)
+{
+ asm volatile("btcl %1,%0" : "+m" (*bitmap) : "r" (index) : "memory");
+}
+
+/*
+ * Get and free a port number (host byte order)
+ */
+uint16_t get_port(void)
+{
+ uint16_t port;
+
+ do {
+ port = first_port_number++;
+ first_port_number &= PORT_NUMBER_COUNT - 1;
+ } while (test_bit(port_number_bitmap, port));
+
+ set_bit(port_number_bitmap, port);
+ return htons(port + PORT_NUMBER_BASE);
+}
+
+void free_port(uint16_t port)
+{
+ port = ntohs(port) - PORT_NUMBER_BASE;
+
+ if (port >= PORT_NUMBER_COUNT)
+ return;
+
+ clr_bit(port_number_bitmap, port);
+}
; PXE modules
; -----------------------------------------------------------------------------
+%if IS_LPXELINUX
%include "pxeisr.inc"
+%endif
; -----------------------------------------------------------------------------
; Common modules