summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/net
diff options
context:
space:
mode:
authorroot <root@lamia.panaceas.james.local>2015-12-19 13:13:57 +0000
committerroot <root@lamia.panaceas.james.local>2015-12-19 14:18:03 +0000
commit1a2238d1bddc823df06f67312d96ccf9de2893cc (patch)
treec58a3944d674a667f133ea5a730f5037e57d3d2e /cfe/cfe/net
downloadbootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.tar.gz
bootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.tar.bz2
bootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.zip
CFE from danitool [without hostTools dir]: https://mega.nz/#!mwZyFK7a!CPT3BKC8dEw29kubtdYxhB91G9vIIismTkgzQ3iUy3k
Diffstat (limited to 'cfe/cfe/net')
-rw-r--r--cfe/cfe/net/README17
-rw-r--r--cfe/cfe/net/dev_tcpconsole.c341
-rw-r--r--cfe/cfe/net/mii.h187
-rwxr-xr-xcfe/cfe/net/net_api.c1095
-rwxr-xr-xcfe/cfe/net/net_api.h179
-rwxr-xr-xcfe/cfe/net/net_arp.c865
-rw-r--r--cfe/cfe/net/net_dhcp.c869
-rwxr-xr-xcfe/cfe/net/net_dns.c354
-rw-r--r--cfe/cfe/net/net_ebuf.h165
-rw-r--r--cfe/cfe/net/net_ether.c705
-rw-r--r--cfe/cfe/net/net_ether.h89
-rw-r--r--cfe/cfe/net/net_icmp.c312
-rwxr-xr-xcfe/cfe/net/net_ip.c722
-rwxr-xr-xcfe/cfe/net/net_ip.h159
-rw-r--r--cfe/cfe/net/net_ip_internal.h128
-rwxr-xr-xcfe/cfe/net/net_nmrp.c656
-rwxr-xr-xcfe/cfe/net/net_nmrp.h1
-rwxr-xr-xcfe/cfe/net/net_tcp.c2215
-rwxr-xr-xcfe/cfe/net/net_tcp.h83
-rwxr-xr-xcfe/cfe/net/net_tcp_internal.h244
-rw-r--r--cfe/cfe/net/net_tcpbuf.c298
-rw-r--r--cfe/cfe/net/net_tcpbuf.h83
-rw-r--r--cfe/cfe/net/net_tftp.c921
-rw-r--r--cfe/cfe/net/net_udp.c637
24 files changed, 11325 insertions, 0 deletions
diff --git a/cfe/cfe/net/README b/cfe/cfe/net/README
new file mode 100644
index 0000000..f4c1c8c
--- /dev/null
+++ b/cfe/cfe/net/README
@@ -0,0 +1,17 @@
+
+This directory contains the network modules for CFE. The
+following standards are implemented here:
+
+* Ethernet datalink
+* ARP
+* IP
+* UDP
+* ICMP
+* TFTP
+* BOOTP/DHCP
+* DNS (for queries only)
+* TCP
+
+If anyone really screams for it, I've considered putting a simple
+(very simple) TCP stack in here as well, but it doesn't seem worth it.
+
diff --git a/cfe/cfe/net/dev_tcpconsole.c b/cfe/cfe/net/dev_tcpconsole.c
new file mode 100644
index 0000000..43b4f1c
--- /dev/null
+++ b/cfe/cfe/net/dev_tcpconsole.c
@@ -0,0 +1,341 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * TCP Console Driver File: dev_tcpconsole.c
+ *
+ * Evil hack: A console driver that uses a TCP socket.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "addrspace.h"
+
+#include "cfe_timer.h"
+
+#include "bsp_config.h"
+
+#if CFG_TCP
+#include "net_ebuf.h"
+#include "net_api.h"
+
+/*
+ * Friendly warning: Don't put printfs in here or enable any
+ * debugging messages in the TCP stack if you're really
+ * going to use this for your console device. You'll end up
+ * with a recursion loop!
+ */
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define TCPCONSOLE_DEFAULT_PORT 23 /* telnet */
+
+/* *********************************************************************
+ * Forward
+ ********************************************************************* */
+
+static void tcpconsole_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+static int tcpconsole_open(cfe_devctx_t *ctx);
+static int tcpconsole_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tcpconsole_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int tcpconsole_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tcpconsole_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tcpconsole_close(cfe_devctx_t *ctx);
+
+const static cfe_devdisp_t tcpconsole_dispatch = {
+ tcpconsole_open,
+ tcpconsole_read,
+ tcpconsole_inpstat,
+ tcpconsole_write,
+ tcpconsole_ioctl,
+ tcpconsole_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t tcpconsole = {
+ "TCP Console",
+ "tcpconsole",
+ CFE_DEV_SERIAL,
+ &tcpconsole_dispatch,
+ tcpconsole_probe
+};
+
+
+/* *********************************************************************
+ * tcpconsole structure
+ ********************************************************************* */
+
+/*
+ * States our connection can be in
+ */
+
+#define TCPCONSTAT_IDLE 0
+#define TCPCONSTAT_LISTEN 1
+#define TCPCONSTAT_CONNECTED 2
+#define TCPCONSTAT_DISCONNECTED 3
+#define TCPCONSTAT_BROKEN 4
+
+/*
+ * state information
+ */
+
+typedef struct tcpconsole_s {
+ int tcp_socket;
+ int tcp_status;
+ int tcp_port;
+} tcpconsole_t;
+
+
+static void tcpconsole_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ tcpconsole_t *softc;
+ char descr[80];
+
+ softc = (tcpconsole_t *) KMALLOC(sizeof(tcpconsole_t),0);
+ if (softc) {
+ softc->tcp_socket = -1;
+ softc->tcp_status = TCPCONSTAT_IDLE;
+ xsprintf(descr, "%s", drv->drv_description);
+
+ if (probe_a == 0) probe_a = TCPCONSOLE_DEFAULT_PORT;
+
+ softc->tcp_port = (int)probe_a;
+
+ cfe_attach(drv, softc, NULL, descr);
+ }
+}
+
+
+static int tcpconsole_isready(tcpconsole_t *softc,int *rxbytes)
+{
+ int res;
+ int connstat,rxeof;
+
+ res = tcp_status(softc->tcp_socket,&connstat,rxbytes,&rxeof);
+
+ /*
+ * Return:
+ * -1 if we could not get status
+ * 0 if we are not connected or are connected and at EOF
+ * 1 if we are connected.
+ */
+
+ if (res < 0) return res;
+ if (connstat != TCPSTATUS_CONNECTED) return 0;
+ if (!rxeof) return 1;
+
+ return 0;
+}
+
+
+static int tcpconsole_process(tcpconsole_t *softc)
+{
+ int res = 0;
+
+ switch (softc->tcp_status) {
+ case TCPCONSTAT_IDLE:
+ /* Idle, set up listening socket */
+ res = tcp_socket();
+ if (res < 0) {
+ softc->tcp_status = TCPCONSTAT_BROKEN;
+ return res;
+ }
+ softc->tcp_socket = res;
+
+ res = tcp_listen(softc->tcp_socket,softc->tcp_port);
+
+ if (res < 0) {
+ tcp_close(softc->tcp_socket);
+ softc->tcp_status = TCPCONSTAT_BROKEN;
+ softc->tcp_socket = -1;
+ return res;
+ }
+ softc->tcp_status = TCPCONSTAT_LISTEN;
+ break;
+
+ case TCPCONSTAT_LISTEN:
+ /* Still waiting for a connection */
+ res = 0;
+ if (tcpconsole_isready(softc,NULL) > 0) {
+ softc->tcp_status = TCPCONSTAT_CONNECTED;
+ }
+ break;
+
+ case TCPCONSTAT_CONNECTED:
+ res = 0; /* do nothing, we're okay */
+ break;
+
+ case TCPCONSTAT_DISCONNECTED:
+ /* Currently connected, kill off this connection */
+ tcp_close(softc->tcp_socket);
+ softc->tcp_socket = -1;
+ softc->tcp_status = TCPCONSTAT_IDLE;
+ break;
+
+ case TCPCONSTAT_BROKEN:
+ /* Broken. Stay broken. */
+ res = 0;
+ break;
+ }
+
+ return res;
+}
+
+
+static int tcpconsole_open(cfe_devctx_t *ctx)
+{
+ return 0;
+}
+
+static int tcpconsole_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ tcpconsole_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+ int res;
+
+ POLL();
+ tcpconsole_process(softc);
+
+ buffer->buf_retlen = 0;
+
+ if (softc->tcp_status == TCPCONSTAT_CONNECTED) {
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ if (tcpconsole_isready(softc,NULL) <= 0) {
+ softc->tcp_status = TCPCONSTAT_DISCONNECTED;
+ return 0;
+ }
+
+ res = tcp_recv(softc->tcp_socket,bptr,blen);
+
+ if (res > 0) {
+ buffer->buf_retlen = res;
+ }
+ }
+
+ return 0;
+}
+
+static int tcpconsole_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ tcpconsole_t *softc = ctx->dev_softc;
+ unsigned int rxbytes;
+
+ POLL();
+ tcpconsole_process(softc);
+
+ inpstat->inp_status = 0;
+
+ if (softc->tcp_status == TCPCONSTAT_CONNECTED) {
+ if (tcpconsole_isready(softc,&rxbytes) <= 0) {
+ softc->tcp_status = TCPCONSTAT_DISCONNECTED;
+ }
+ else {
+ inpstat->inp_status = (rxbytes > 0);
+ }
+ }
+
+ return 0;
+}
+
+static int tcpconsole_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ tcpconsole_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+ int res;
+
+ POLL();
+ tcpconsole_process(softc);
+
+ buffer->buf_retlen = 0;
+
+ if (softc->tcp_status == TCPCONSTAT_CONNECTED) {
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ if (tcpconsole_isready(softc,NULL) <= 0) {
+ softc->tcp_status = TCPCONSTAT_DISCONNECTED;
+ return 0;
+ }
+
+ res = tcp_send(softc->tcp_socket,bptr,blen);
+
+ if (res > 0) {
+ buffer->buf_retlen = res;
+ }
+ }
+
+ return 0;
+}
+
+static int tcpconsole_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+static int tcpconsole_close(cfe_devctx_t *ctx)
+{
+ tcpconsole_t *softc = ctx->dev_softc;
+
+ if (softc->tcp_status == TCPCONSTAT_CONNECTED) {
+ softc->tcp_status = TCPCONSTAT_DISCONNECTED;
+ }
+
+ return 0;
+}
+
+
+#endif
diff --git a/cfe/cfe/net/mii.h b/cfe/cfe/net/mii.h
new file mode 100644
index 0000000..ac56958
--- /dev/null
+++ b/cfe/cfe/net/mii.h
@@ -0,0 +1,187 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * MII register definitions File: mii.h
+ *
+ * Register and bit definitions for the standard MII management
+ * interface.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#ifndef _MII_H_
+#define _MII_H_
+
+/* Access/command codes */
+
+#define MII_COMMAND_START 0x01
+#define MII_COMMAND_READ 0x02
+#define MII_COMMAND_WRITE 0x01
+#define MII_COMMAND_ACK 0x02
+
+
+/* Registers */
+
+#define MII_BMCR 0x00 /* Basic Mode Control (rw) */
+#define MII_BMSR 0x01 /* Basic Mode Status (ro) */
+#define MII_PHYIDR1 0x02
+#define MII_PHYIDR2 0x03
+#define MII_ANAR 0x04 /* Autonegotiation Advertisement */
+#define MII_ANLPAR 0x05 /* Autonegotiation Link Partner Ability (rw) */
+#define MII_ANER 0x06 /* Autonegotiation Expansion */
+#define MII_K1CTL 0x09 /* 1000baseT control */
+#define MII_K1STSR 0x0A /* 1K Status Register (ro) */
+#define MII_AUXCTL 0x18 /* aux control register */
+
+
+/* Basic Mode Control register (RW) */
+
+#define BMCR_RESET 0x8000
+#define BMCR_LOOPBACK 0x4000
+#define BMCR_SPEED0 0x2000
+#define BMCR_ANENABLE 0x1000
+#define BMCR_POWERDOWN 0x0800
+#define BMCR_ISOLATE 0x0400
+#define BMCR_RESTARTAN 0x0200
+#define BMCR_DUPLEX 0x0100
+#define BMCR_COLTEST 0x0080
+#define BMCR_SPEED1 0x0040
+#define BMCR_SPEED1000 (BMCR_SPEED1)
+#define BMCR_SPEED100 (BMCR_SPEED0)
+#define BMCR_SPEED10 0
+
+
+/* Basic Mode Status register (RO) */
+
+#define BMSR_100BT4 0x8000
+#define BMSR_100BT_FDX 0x4000
+#define BMSR_100BT_HDX 0x2000
+#define BMSR_10BT_FDX 0x1000
+#define BMSR_10BT_HDX 0x0800
+#define BMSR_100BT2_FDX 0x0400
+#define BMSR_100BT2_HDX 0x0200
+#define BMSR_1000BT_XSR 0x0100
+#define BMSR_PRESUP 0x0040
+#define BMSR_ANCOMPLETE 0x0020
+#define BMSR_REMFAULT 0x0010
+#define BMSR_AUTONEG 0x0008
+#define BMSR_LINKSTAT 0x0004
+#define BMSR_JABDETECT 0x0002
+#define BMSR_EXTCAPAB 0x0001
+
+
+/* PHY Identifer registers (RO) */
+
+#define PHYIDR1 0x2000
+#define PHYIDR2 0x5C60
+
+
+/* Autonegotiation Advertisement register (RW) */
+
+#define ANAR_NP 0x8000
+#define ANAR_RF 0x2000
+#define ANAR_ASYPAUSE 0x0800
+#define ANAR_PAUSE 0x0400
+#define ANAR_T4 0x0200
+#define ANAR_TXFD 0x0100
+#define ANAR_TXHD 0x0080
+#define ANAR_10FD 0x0040
+#define ANAR_10HD 0x0020
+#define ANAR_PSB 0x001F
+
+#define PSB_802_3 0x0001 /* 802.3 */
+
+/* Autonegotiation Link Partner Abilities register (RW) */
+
+#define ANLPAR_NP 0x8000
+#define ANLPAR_ACK 0x4000
+#define ANLPAR_RF 0x2000
+#define ANLPAR_ASYPAUSE 0x0800
+#define ANLPAR_PAUSE 0x0400
+#define ANLPAR_T4 0x0200
+#define ANLPAR_TXFD 0x0100
+#define ANLPAR_TXHD 0x0080
+#define ANLPAR_10FD 0x0040
+#define ANLPAR_10HD 0x0020
+#define ANLPAR_PSB 0x001F
+
+
+/* Autonegotiation Expansion register (RO) */
+
+#define ANER_PDF 0x0010
+#define ANER_LPNPABLE 0x0008
+#define ANER_NPABLE 0x0004
+#define ANER_PAGERX 0x0002
+#define ANER_LPANABLE 0x0001
+
+
+#define ANNPTR_NP 0x8000
+#define ANNPTR_MP 0x2000
+#define ANNPTR_ACK2 0x1000
+#define ANNPTR_TOGTX 0x0800
+#define ANNPTR_CODE 0x0008
+
+#define ANNPRR_NP 0x8000
+#define ANNPRR_MP 0x2000
+#define ANNPRR_ACK3 0x1000
+#define ANNPRR_TOGTX 0x0800
+#define ANNPRR_CODE 0x0008
+
+
+#define K1TCR_TESTMODE 0x0000
+#define K1TCR_MSMCE 0x1000
+#define K1TCR_MSCV 0x0800
+#define K1TCR_RPTR 0x0400
+#define K1TCR_1000BT_FDX 0x200
+#define K1TCR_1000BT_HDX 0x100
+
+#define K1STSR_MSMCFLT 0x8000
+#define K1STSR_MSCFGRES 0x4000
+#define K1STSR_LRSTAT 0x2000
+#define K1STSR_RRSTAT 0x1000
+#define K1STSR_LP1KFD 0x0800
+#define K1STSR_LP1KHD 0x0400
+#define K1STSR_LPASMDIR 0x0200
+
+#define K1SCR_1KX_FDX 0x8000
+#define K1SCR_1KX_HDX 0x4000
+#define K1SCR_1KT_FDX 0x2000
+#define K1SCR_1KT_HDX 0x1000
+
+#endif /* _MII_H_ */
diff --git a/cfe/cfe/net/net_api.c b/cfe/cfe/net/net_api.c
new file mode 100755
index 0000000..c9f119e
--- /dev/null
+++ b/cfe/cfe/net/net_api.c
@@ -0,0 +1,1095 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Top-level API to network File: net_api.c
+ *
+ * This routine contains the highest-level API to the network
+ * routines. The global handle to the network state is right here.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "bsp_config.h"
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_iocb.h"
+#include "cfe_devfuncs.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+
+#include "cfe_error.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "cfe_timer.h"
+
+#include "net_ip.h"
+#include "net_ip_internal.h"
+#include "net_api.h"
+
+#include "env_subr.h"
+
+#if CFG_TCP
+#include "net_tcp.h"
+#endif
+
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+/*
+ * Net context. All the soft context structures of all the
+ * layers of the network stack are bundled here. There's only one
+ * of these in the system when the network is active.
+ */
+
+typedef struct net_ctx_s {
+ /* Global info */
+ int64_t timer;
+
+ /* device name */
+ char *devname;
+
+ /* Run-time info for IP interface */
+ ip_info_t *ipinfo;
+
+ /* Info for Ethernet interface */
+ ether_info_t *ethinfo;
+
+ /* Info specific to UDP */
+ udp_info_t *udpinfo;
+
+ /* Info specific to ICMP */
+ icmp_info_t *icmpinfo;
+
+#if CFG_TCP
+ /* Info specific to TCP */
+ tcp_info_t *tcpinfo;
+#endif
+} net_ctx_t;
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+/* Foxconn add start by Cliff Wang, 03/23/2010 */
+net_ctx_t *netctx = NULL;
+// static net_ctx_t *netctx = NULL;
+/* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+/* *********************************************************************
+ * UDP INTERFACE
+ ********************************************************************* */
+
+/* *********************************************************************
+ * udp_alloc()
+ *
+ * Allocate an ebuf with fields reserved for the UDP layer.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * pointer to ebuf, or NULL if no EBUFs are available
+ ********************************************************************* */
+
+ebuf_t *udp_alloc(void)
+{
+ if (!netctx) return NULL;
+ return _udp_alloc(netctx->udpinfo);
+}
+
+/* *********************************************************************
+ * udp_free(buf)
+ *
+ * Return an ebuf to the pool. The ebuf was presumably allocated
+ * via udp_alloc() first.
+ *
+ * Input parameters:
+ * buf - ebuf to return to the pool
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+void udp_free(ebuf_t *buf)
+{
+ if (!netctx) return;
+ _udp_free(netctx->udpinfo,buf);
+}
+
+/* *********************************************************************
+ * udp_socket(port)
+ *
+ * Open a UDP socket. Once open, datagrams sent on the socket will
+ * go to the specified port number. You can change the port later
+ * using the "udp_connect" function.
+ *
+ * Input parameters:
+ * port - port number
+ *
+ * Return value:
+ * UDP port handle, or -1 if no ports are available.
+ ********************************************************************* */
+
+int udp_socket(uint16_t port)
+{
+ if (!netctx) return -1;
+
+ return _udp_socket(netctx->udpinfo,port);
+}
+
+/* *********************************************************************
+ * udp_close(sock)
+ *
+ * Close a udp socket. You pass this handle returned from a previous
+ * call to udp_open.
+ *
+ * Input parameters:
+ * handle - UDP port handle, from udp_open()
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void udp_close(int portnum)
+{
+ if (!netctx) return;
+
+ _udp_close(netctx->udpinfo,portnum);
+}
+
+
+/* *********************************************************************
+ * udp_send(s,buf,dest)
+ *
+ * Send a datagram to the specified destination address. The
+ * source and destination UDP port numbers are taken from the
+ * values passed to earlier calls to udp_open, udp_bind, and
+ * udp_connect.
+ *
+ * Input parameters:
+ * s - socket handle, from udp_open
+ * buf - ebuf to send (allocated via udp_alloc)
+ * dest - pointer to 4-byte destination IP address
+ *
+ * Return value:
+ * 0 if ok
+ * <0 if an error occured.
+ ********************************************************************* */
+
+int udp_send(int s,ebuf_t *buf,uint8_t *dest)
+{
+ if (!netctx) return -1;
+
+ return _udp_send(netctx->udpinfo,s,buf,dest);
+}
+
+/* *********************************************************************
+ * udp_bind(s,port)
+ *
+ * Re-"bind" the specified udp socket to a new source port.
+ * This changes the source port number that will be transmitted
+ * in subsequent calls to udp_send()
+ *
+ * Input parameters:
+ * s - socket handle
+ * port - new port number
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int udp_bind(int s,uint16_t port)
+{
+ if (!netctx) return -1;
+
+ return _udp_bind(netctx->udpinfo,s,port);
+}
+
+
+/* *********************************************************************
+ * udp_connect(s,port)
+ *
+ * Set the port number to be used in the destination port field
+ * for subsequent calls to udp_send().
+ *
+ * Input parameters:
+ * s - udp socket handle
+ * port - new destination port number
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int udp_connect(int s,uint16_t port)
+{
+ if (!netctx) return -1;
+
+ return _udp_connect(netctx->udpinfo,s,port);
+}
+
+/* *********************************************************************
+ * udp_recv(s)
+ *
+ * Return the next packet from the receive queue for this port.
+ * If no packets are available, NULL is returned.
+ *
+ * Input parameters:
+ * s - udp port handle
+ *
+ * Return value:
+ * ebuf (if a packet is available)
+ * NULL (no packet available)
+ ********************************************************************* */
+
+ebuf_t *udp_recv(int s)
+{
+ if (!netctx) return NULL;
+
+ return _udp_recv(netctx->udpinfo,s);
+}
+
+
+/* *********************************************************************
+ * udp_recv_with_timeout(s,seconds)
+ *
+ * Return the next packet from the receive queue for this socket,
+ * waiting for one to arrive if there are none available.
+ *
+ * Input parameters:
+ * s - udp socket handle
+ * seconds - number of seconds to wait
+ *
+ * Return value:
+ * ebuf (if a packet is available)
+ * NULL (no packet available after timeout)
+ ********************************************************************* */
+
+ebuf_t *udp_recv_with_timeout(int s,int seconds)
+{
+ ebuf_t *buf = NULL;
+ int64_t timer;
+
+ if (!netctx) return NULL;
+
+ TIMER_SET(timer,seconds*CFE_HZ);
+
+ while (!TIMER_EXPIRED(timer)) {
+ POLL();
+ buf = _udp_recv(netctx->udpinfo,s);
+ if (buf) break;
+ }
+
+ return buf;
+}
+
+
+
+#if CFG_TCP
+/* *********************************************************************
+ * TCP INTERFACE
+ ********************************************************************* */
+
+
+/* *********************************************************************
+ * tcp_socket()
+ *
+ * Create a new TCP port.
+ *
+ * Input parameters:
+ * nothing.
+ *
+ * Return value:
+ * TCP port handle, or <0 if no ports are available.
+ ********************************************************************* */
+
+int tcp_socket(void)
+{
+ if (!netctx) return -1;
+
+ return _tcp_socket(netctx->tcpinfo);
+}
+
+/* *********************************************************************
+ * tcp_connect(handle,dest,port)
+ *
+ * Connect to a remote TCP destination.
+ *
+ * Input parameters:
+ * handle - returned from tcp_create
+ * dest - destination IP address
+ * port - destination port number
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int tcp_connect(int s,uint8_t *dest,uint16_t port)
+{
+ int res;
+ unsigned int flags;
+ unsigned int connflag;
+
+ if (!netctx) return -1;
+
+ /*
+ * Get socket's blocking status
+ * If nonblocking, just call the tcp stack
+ * and return what it returns.
+ */
+
+ res = _tcp_getflags(netctx->tcpinfo,s,&flags);
+ if (res < 0) return res;
+
+ if (flags & TCPFLG_NBIO) {
+ return _tcp_connect(netctx->tcpinfo,s,dest,port);
+ }
+
+ /*
+ * Otherwise, call connect and poll till the status
+ * changes. We want to see a transition to the
+ * CONNECTED state, so we loop while we see "CONNECTING"
+ * and return a status based on what it changes to.
+ */
+
+ res = _tcp_connect(netctx->tcpinfo,s,dest,port);
+ if (res < 0) return res;
+ connflag = TCPSTATUS_NOTCONN;
+
+ for (;;) {
+ POLL();
+
+ res = _tcp_status(netctx->tcpinfo,s,&connflag,NULL,NULL);
+ if (res < 0) break;
+
+ if (connflag == TCPSTATUS_CONNECTING) continue;
+ break;
+ }
+
+ if (connflag != TCPSTATUS_CONNECTED) return CFE_ERR_NOTCONN;
+
+ return res;
+}
+
+/* *********************************************************************
+ * tcp_close(s)
+ *
+ * Disconnect a connection (cleanly)
+ *
+ * Input parameters:
+ * s - handle from tcp_create
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+int tcp_close(int s)
+{
+ if (!netctx) return -1;
+
+ return _tcp_close(netctx->tcpinfo,s);
+}
+
+
+
+/* *********************************************************************
+ * tcp_send(s,buf,len)
+ *
+ * Send a buffer to the other TCP, buffering as much data as
+ * will fit in the send buffer.
+ *
+ * Input parameters:
+ * s - port handle, from tcp_open
+ * buf - buffer pointer
+ * len - length of buffer to send
+ *
+ * Return value:
+ * >=0 if ok (number of bytes sent)
+ * <0 if an error occured.
+ ********************************************************************* */
+
+int tcp_send(int s,uint8_t *buf,int len)
+{
+ unsigned int flags;
+ int res;
+ int total = 0;
+
+ if (!netctx) return -1;
+
+ /*
+ * Get socket's blocking status
+ * If nonblocking, just call the tcp stack
+ * and return what it returns.
+ */
+
+ res = _tcp_getflags(netctx->tcpinfo,s,&flags);
+ if (res < 0) return res;
+
+ if (flags & TCPFLG_NBIO) {
+ return _tcp_send(netctx->tcpinfo,s,buf,len);
+ }
+
+ /*
+ * The first time we'll check the return code for an
+ * error so we can pass up the failure.
+ */
+
+ res = _tcp_send(netctx->tcpinfo,s,buf,len);
+ if (res < 0) return res;
+
+ buf += res;
+ len -= res;
+ total += res;
+
+ while (len > 0) {
+ /*
+ * Give the TCP stack and devices a chance to run
+ */
+
+ POLL();
+
+ /*
+ * Try to send some more. If we get an error, get out.
+ * otherwise, keep going till all the data is gone.
+ */
+
+ res = _tcp_send(netctx->tcpinfo,s,buf,len);
+ if (res < 0) break;
+ buf += res;
+ len -= res;
+ total += res;
+ }
+
+ /*
+ * If we sent nothing and have an error, return the error.
+ * Otherwise return the amount of data we sent.
+ */
+ if ((total == 0) && (res < 0)) return res;
+ else return total;
+}
+
+/* *********************************************************************
+ * tcp_recv(s,buf,len)
+ *
+ * Receive data from the remote TCP session
+ *
+ * Input parameters:
+ * s - port handle, from tcp_open
+ * buf - buffer pointer
+ * len - length of buffer to send
+ *
+ * Return value:
+ * >=0 if ok (number of bytes received)
+ * <0 if an error occured.
+ ********************************************************************* */
+
+int tcp_recv(int s,uint8_t *buf,int len)
+{
+ unsigned int flags;
+ int res;
+ int total = 0;
+
+ if (!netctx) return -1;
+
+ /*
+ * Get socket's blocking status
+ * If nonblocking, just call the tcp stack
+ * and return what it returns.
+ */
+
+ res = _tcp_getflags(netctx->tcpinfo,s,&flags);
+ if (res < 0) return res;
+
+ if (flags & TCPFLG_NBIO) {
+ return _tcp_recv(netctx->tcpinfo,s,buf,len);
+ }
+
+ /*
+ * The first time we'll check the return code for an
+ * error so we can pass up the failure.
+ */
+
+ res = _tcp_recv(netctx->tcpinfo,s,buf,len);
+ if (res < 0) return res;
+
+ buf += res;
+ len -= res;
+ total += res;
+
+ while (len > 0) {
+ /*
+ * Give the TCP stack and devices a chance to run
+ */
+
+ POLL();
+
+ /*
+ * Try to receive some more. If we get an error, get out.
+ * otherwise, keep going till all the data is gone.
+ */
+
+ res = _tcp_recv(netctx->tcpinfo,s,buf,len);
+ if (res < 0) break;
+
+ if (res == 0) {
+ _tcp_status(netctx->tcpinfo,s,&flags,NULL,NULL);
+ if (flags != TCPSTATUS_CONNECTED) {
+ res = CFE_ERR_NOTCONN;
+ break;
+ }
+ }
+
+ buf += res;
+ len -= res;
+ total += res;
+ }
+
+ /*
+ * If we sent received and have an error, return the error.
+ * Otherwise return the amount of data we sent.
+ */
+ if ((total == 0) && (res < 0)) return res;
+ else return total;
+
+}
+
+/* *********************************************************************
+ * tcp_bind(s,port)
+ *
+ * Re-"bind" the specified tcp port handle to a new source port.
+ *
+ * Used for listening sockets.
+ *
+ * Input parameters:
+ * s - port handle
+ * port - new port number
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int tcp_bind(int s,uint16_t port)
+{
+ if (!netctx) return -1;
+
+ return _tcp_bind(netctx->tcpinfo,s,port);
+}
+
+/* *********************************************************************
+ * tcp_peeraddr(s,addr,port)
+ *
+ * Return the address of the remote peer.
+ *
+ * Input parameters:
+ * s - port handle
+ * addr - points to 4-byte buffer to receive IP address
+ * port - points to uint16 to receive port number
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int tcp_peeraddr(int s,uint8_t *addr,uint16_t *port)
+{
+ if (!netctx) return -1;
+
+ return _tcp_peeraddr(netctx->tcpinfo,s,addr,port);
+}
+
+/* *********************************************************************
+ * tcp_setflags(s,addr,flags)
+ *
+ * Set per-socket flags (nodelay, etc.)
+ *
+ * Input parameters:
+ * s - port handle
+ * flags - flags for this socket
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int tcp_setflags(int s,unsigned int flags)
+{
+ if (!netctx) return -1;
+
+ return _tcp_setflags(netctx->tcpinfo,s,flags);
+}
+
+/* *********************************************************************
+ * tcp_getflags(s,addr,flags)
+ *
+ * Get per-socket flags (nodelay, etc.)
+ *
+ * Input parameters:
+ * s - port handle
+ * flags - flags for this socket
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int tcp_getflags(int s,unsigned int *flags)
+{
+ if (!netctx) return -1;
+
+ return _tcp_getflags(netctx->tcpinfo,s,flags);
+}
+
+
+/* *********************************************************************
+ * tcp_listen(s)
+ *
+ * Set the socket into "listen" mode.
+ *
+ * Input parameters:
+ * s - port handle
+ * port - port # to listen on
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+int tcp_listen(int s,uint16_t port)
+{
+ if (!netctx) return -1;
+
+ return _tcp_listen(netctx->tcpinfo,s,port);
+}
+
+/* *********************************************************************
+ * tcp_status(s,connflag,rxready,rxeof)
+ *
+ * Return the TCP connection's status
+ *
+ * Input parameters:
+ * s - port handle
+ * connflag - points to flag to receive connected status
+ * rxready - returns # of bytes ready to receive
+ * rxeof - returns TRUE if we've been FINed.
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+int tcp_status(int s,unsigned int *connflag,int *rxready,int *rxeof)
+{
+ if (!netctx) return -1;
+
+ return _tcp_status(netctx->tcpinfo,s,connflag,rxready,rxeof);
+}
+
+/* *********************************************************************
+ * tcp_debug(s,arg)
+ *
+ * Call the debug routine in the tcp stack.
+ *
+ * Input parameters:
+ * s - socket handle
+ * arg - passed to debug routine
+ *
+ * Return value:
+ * return value from debug routine
+ ********************************************************************* */
+
+int tcp_debug(int s,int arg)
+{
+ if (!netctx) return -1;
+ return _tcp_debug(netctx->tcpinfo,s,arg);
+}
+
+#endif
+
+/* *********************************************************************
+ * ARP FUNCTIONS
+ ********************************************************************* */
+
+
+/* *********************************************************************
+ * arp_add(destip,desthw)
+ *
+ * Add a permanent entry to the ARP table. This entry will
+ * persist until deleted or the interface is deactivated.
+ * This may cause a stale entry to be deleted if the table is full
+ *
+ * Input parameters:
+ * destip - pointer to 4-byte destination IP address
+ * desthw - pointer to 6-byte destination hardware address
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void arp_add(uint8_t *destip,uint8_t *desthw)
+{
+ if (netctx) _arp_add(netctx->ipinfo,destip,desthw);
+}
+
+/* *********************************************************************
+ * arp_lookup(destip)
+ *
+ * Look up the hardware address for an IP address.
+ *
+ * Input parameters:
+ * destip - pointer to 4-byte IP address
+ *
+ * Return value:
+ * pointer to 6-byte hardware address, or NULL if there are
+ * no matching entries in the table.
+ ********************************************************************* */
+
+uint8_t *arp_lookup(uint8_t *destip)
+{
+ if (!netctx) return NULL;
+ return _arp_lookup(netctx->ipinfo,destip);
+}
+
+
+/* *********************************************************************
+ * arp_enumerate(entrynum,ipaddr,hwaddr)
+ *
+ * Return an entry from the ARP table.
+ *
+ * Input parameters:
+ * entrynum - entry number to return, starting with zero
+ * ipaddr - pointer to 4 bytes to receive IP address
+ * hwaddr - pointer to 6 bytes to receive hardware address
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int arp_enumerate(int entrynum,uint8_t *ipaddr,uint8_t *hwaddr)
+{
+ if (!netctx) return -1;
+ return _arp_enumerate(netctx->ipinfo,entrynum,ipaddr,hwaddr);
+}
+
+/* *********************************************************************
+ * arp_delete(ipaddr)
+ *
+ * Delete an entry from the ARP table.
+ *
+ * Input parameters:
+ * ipaddr - pointer to 4-byte IP address
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int arp_delete(uint8_t *ipaddr)
+{
+ if (!netctx) return -1;
+ return _arp_delete(netctx->ipinfo,ipaddr);
+}
+
+/* *********************************************************************
+ * ICMP FUNCTIONS
+ ********************************************************************* */
+
+/* *********************************************************************
+ * icmp_ping(dest,seq,len)
+ *
+ * Ping a remote host, transmitting the ICMP_ECHO message and
+ * waiting for the corresponding ICMP_ECHO_REPLY.
+ *
+ * Input parameters:
+ * dest - pointer to 4-byte destination IP address
+ * seq - sequence number to put in to the ICMP packet
+ * len - length of data to place in ICMP packet
+ *
+ * Return value:
+ * 0 if ok (remote host responded)
+ * else error code
+ ********************************************************************* */
+
+int icmp_ping(uint8_t *dest,int seq,int len)
+{
+ if (!netctx) return -1;
+ return _icmp_ping(netctx->icmpinfo,dest,seq,len);
+}
+
+/* *********************************************************************
+ * INIT/CONFIG FUNCTIONS
+ ********************************************************************* */
+
+/* *********************************************************************
+ * net_getparam(param)
+ *
+ * Return a parameter from the current IP configuration. This is
+ * the main call to set the IP address, netmask, gateway,
+ * name server, host name, etc.
+ *
+ * Input parameters:
+ * param - parameter number (see net_api.h)
+ *
+ * Return value:
+ * pointer to value of parameter, or NULL if parameter
+ * ID is invalid
+ ********************************************************************* */
+
+uint8_t *net_getparam(int param)
+{
+ if (!netctx) return NULL;
+ if (param == NET_DEVNAME) return (uint8_t *) netctx->devname;
+ return _ip_getparam(netctx->ipinfo,param);
+
+}
+
+/* *********************************************************************
+ * net_setparam(param,ptr)
+ *
+ * Set the value of an IP configuration parameter
+ *
+ * Input parameters:
+ * param - parameter number (see net_api.h)
+ * ptr - pointer to parameter's new value
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int net_setparam(int param,uint8_t *ptr)
+{
+ if (!netctx) return NULL;
+ return _ip_setparam(netctx->ipinfo,param,ptr);
+}
+
+/* *********************************************************************
+ * net_poll()
+ *
+ * Process background tasks for the network stack, maintaining
+ * the ARP table, receive queues, etc.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void net_poll(void *arg)
+{
+ if (netctx) {
+ eth_poll(netctx->ethinfo);
+ if (TIMER_EXPIRED(netctx->timer)) {
+ _ip_timer_tick(netctx->ipinfo);
+ TIMER_SET(netctx->timer,CFE_HZ);
+ }
+ }
+}
+
+/* *********************************************************************
+ * net_init(devname)
+ *
+ * Initialize the network interface. This is the main call, once
+ * completed you should call net_setparam to set up the network
+ * addresses and stuff.
+ *
+ * Input parameters:
+ * devname - CFE device name for network device
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int net_init(char *devname)
+{
+ net_ctx_t *ctx;
+
+ if (netctx) net_uninit();
+
+ ctx = KMALLOC(sizeof(net_ctx_t),0);
+
+ if (!ctx) return -1;
+
+ ctx->devname = strdup(devname);
+
+ ctx->ethinfo = eth_init(devname);
+ if (ctx->ethinfo == NULL) {
+ return -1;
+ }
+
+ ctx->ipinfo = _ip_init(ctx->ethinfo);
+ if (ctx->ipinfo == NULL) {
+ eth_uninit(ctx->ethinfo);
+ return -1;
+ }
+
+ ctx->udpinfo = _udp_init(ctx->ipinfo,ctx->ipinfo);
+ if (ctx->udpinfo == NULL) {
+ _ip_uninit(ctx->ipinfo);
+ eth_uninit(ctx->ethinfo);
+ return -1;
+ }
+
+ ctx->icmpinfo = _icmp_init(ctx->ipinfo);
+ if (ctx->icmpinfo == NULL) {
+ _udp_uninit(ctx->udpinfo);
+ _ip_uninit(ctx->ipinfo);
+ eth_uninit(ctx->ethinfo);
+ return -1;
+ }
+
+ cfe_bg_add(net_poll,ctx);
+ TIMER_SET(ctx->timer,CFE_HZ);
+
+#if CFG_TCP
+ ctx->tcpinfo = _tcp_init(ctx->ipinfo,ctx->ipinfo);
+ cfe_bg_add(_tcp_poll,ctx->tcpinfo);
+#endif
+
+ netctx = ctx;
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * net_uninit()
+ *
+ * Uninitialize the network, deallocating all resources allocated
+ * to the network and closing all open device handles
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void net_uninit(void)
+{
+ if (netctx) {
+#if CFG_TCP
+ cfe_bg_remove(_tcp_poll);
+ _tcp_uninit(netctx->tcpinfo);
+#endif
+ TIMER_CLEAR(netctx->timer);
+ _icmp_uninit(netctx->icmpinfo);
+ _udp_uninit(netctx->udpinfo);
+ _ip_uninit(netctx->ipinfo);
+ eth_uninit(netctx->ethinfo);
+ KFREE(netctx->devname);
+ KFREE(netctx);
+ netctx = NULL;
+ cfe_bg_remove(net_poll);
+ }
+}
+
+
+/* *********************************************************************
+ * net_setnetvars()
+ *
+ * Set environment variables related to the network.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void net_setnetvars(void)
+{
+ char *x;
+ uint8_t *addr;
+ char str[60];
+
+ /* Clear out all the environment variables */
+ env_delenv("NET_DEVICE");
+ env_delenv("NET_IPADDR");
+ env_delenv("NET_NETMASK");
+ env_delenv("NET_GATEWAY");
+ env_delenv("NET_NAMESERVER");
+ env_delenv("NET_DOMAIN");
+
+ x = (char *) net_getparam(NET_DEVNAME);
+ if (!x) {
+ return;
+ }
+
+ x = (char *) net_getparam(NET_DEVNAME);
+ if (x) env_setenv("NET_DEVICE",x,ENV_FLG_BUILTIN);
+
+ x = (char *) net_getparam(NET_DOMAIN);
+ if (x) env_setenv("NET_DOMAIN",x,ENV_FLG_BUILTIN);
+
+ addr = net_getparam(NET_IPADDR);
+ if (addr) {
+ xsprintf(str,"%I",addr);
+ env_setenv("NET_IPADDR",str,ENV_FLG_BUILTIN);
+ }
+
+ addr = net_getparam(NET_NETMASK);
+ if (addr) {
+ xsprintf(str,"%I",addr);
+ env_setenv("NET_NETMASK",str,ENV_FLG_BUILTIN);
+ }
+
+ addr = net_getparam(NET_GATEWAY);
+ if (addr) {
+ xsprintf(str,"%I",addr);
+ env_setenv("NET_GATEWAY",str,ENV_FLG_BUILTIN);
+ }
+
+ addr = net_getparam(NET_NAMESERVER);
+ if (addr) {
+ xsprintf(str,"%I",addr);
+ env_setenv("NET_NAMESERVER",str,ENV_FLG_BUILTIN);
+ }
+
+}
+
diff --git a/cfe/cfe/net/net_api.h b/cfe/cfe/net/net_api.h
new file mode 100755
index 0000000..f28b917
--- /dev/null
+++ b/cfe/cfe/net/net_api.h
@@ -0,0 +1,179 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * High-level network API defs File: net_api.h
+ *
+ * This module contains prototypes and constants for the
+ * network (TCP/IP) interface.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#ifndef IP_ADDR_LEN
+#define IP_ADDR_LEN 4
+#endif
+
+/* *********************************************************************
+ * DHCP Protocol
+ ********************************************************************* */
+
+typedef struct dhcpreply_s {
+ uint8_t dr_ipaddr[IP_ADDR_LEN];
+ uint8_t dr_netmask[IP_ADDR_LEN];
+ uint8_t dr_gateway[IP_ADDR_LEN];
+ uint8_t dr_nameserver[IP_ADDR_LEN];
+ uint8_t dr_dhcpserver[IP_ADDR_LEN];
+ uint8_t dr_bootserver[IP_ADDR_LEN];
+ char *dr_hostname;
+ char *dr_domainname;
+ char *dr_bootfile;
+ char *dr_rootpath;
+ char *dr_swapserver;
+ char *dr_script;
+ char *dr_options;
+} dhcpreply_t;
+
+
+int dhcp_bootrequest(dhcpreply_t **reply);
+void dhcp_free_reply(dhcpreply_t *reply);
+void dhcp_set_envvars(dhcpreply_t *reply);
+
+/* *********************************************************************
+ * IP Layer
+ ********************************************************************* */
+
+void ip_uninit(void);
+int ip_init(char *,uint8_t *);
+ebuf_t *ip_alloc(void);
+void ip_free(ebuf_t *buf);
+int ip_send(ebuf_t *buf,uint8_t *destaddr,uint8_t proto);
+uint16_t ip_chksum(uint16_t initchksum,uint8_t *ptr,int len);
+
+/* *********************************************************************
+ * UDP Layer
+ ********************************************************************* */
+
+ebuf_t *udp_alloc(void);
+void udp_free(ebuf_t *buf);
+
+int udp_socket(uint16_t port);
+int udp_bind(int portnum,uint16_t port);
+int udp_connect(int portnum,uint16_t port);
+void udp_close(int portnum);
+int udp_send(int portnum,ebuf_t *buf,uint8_t *dest);
+ebuf_t *udp_recv_with_timeout(int portnum,int seconds);
+ebuf_t *udp_recv(int portnum);
+
+/* *********************************************************************
+ * TCP Layer
+ ********************************************************************* */
+
+#if CFG_TCP
+#ifndef TCPFLG_NODELAY /* XXX should be kept in sync with net_tcp.h */
+#define TCPFLG_NODELAY 1 /* disable nagle */
+#define TCPFLG_NBIO 2 /* non-blocking I/O */
+
+#define TCPSTATUS_NOTCONN 0
+#define TCPSTATUS_CONNECTING 1
+#define TCPSTATUS_CONNECTED 2
+#endif
+int tcp_socket(void);
+void tcp_destroy(int portnum);
+int tcp_connect(int s,uint8_t *dest,uint16_t port);
+int tcp_close(int s);
+int tcp_send(int s,uint8_t *buf,int len);
+int tcp_recv(int s,uint8_t *buf,int len);
+int tcp_bind(int s,uint16_t port);
+int tcp_peeraddr(int s,uint8_t *addr,uint16_t *port);
+int tcp_listen(int s,uint16_t port);
+int tcp_status(int s,unsigned int *connflag,int *rxready,int *rxeof);
+int tcp_debug(int s,int arg);
+int tcp_setflags(int s,unsigned int flags);
+int tcp_getflags(int s,unsigned int *flags);
+#endif
+
+/* *********************************************************************
+ * ARP Layer
+ ********************************************************************* */
+
+uint8_t *arp_lookup(uint8_t *destip);
+void arp_add(uint8_t *destip,uint8_t *desthw);
+int arp_enumerate(int entrynum,uint8_t *ipaddr,uint8_t *hwaddr);
+int arp_delete(uint8_t *ipaddr);
+
+/* *********************************************************************
+ * Network Configuration
+ ********************************************************************* */
+
+#ifndef NET_IPADDR
+#define NET_IPADDR 0
+#define NET_NETMASK 1
+#define NET_GATEWAY 2
+#define NET_NAMESERVER 3
+#define NET_HWADDR 4
+#define NET_DOMAIN 5
+#define NET_HOSTNAME 6
+#define NET_SPEED 7
+#define NET_LOOPBACK 8
+#endif
+#define NET_DEVNAME 10
+
+uint8_t *net_getparam(int param);
+int net_setparam(int param,uint8_t *ptr);
+int net_init(char *devname);
+void net_uninit(void);
+void net_setnetvars(void);
+
+/* *********************************************************************
+ * DNS
+ ********************************************************************* */
+
+int dns_lookup(char *hostname,uint8_t *ipaddr);
+
+/* *********************************************************************
+ * ICMP
+ ********************************************************************* */
+
+int icmp_ping(uint8_t *dest,int seq,int len);
+
diff --git a/cfe/cfe/net/net_arp.c b/cfe/cfe/net/net_arp.c
new file mode 100755
index 0000000..1c12457
--- /dev/null
+++ b/cfe/cfe/net/net_arp.c
@@ -0,0 +1,865 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Address Resolution Protocol File: net_arp.c
+ *
+ * This module implements RFC826, the Address Resolution Protocol.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "net_ip.h"
+#include "net_ip_internal.h"
+
+
+/* *********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+static int arp_tx_query(ip_info_t *ipi,uint8_t *destaddr);
+static void arp_delete(arpentry_t *ae);
+static void arp_tx_waiting(arpentry_t *ae);
+static arpentry_t *arp_new_entry(ip_info_t *ipi);
+static arpentry_t *arp_find_entry(ip_info_t *ipi,uint8_t *ipaddr);
+static int arp_rx_query(ip_info_t *ipi,uint8_t *srcaddr,
+ uint8_t *targethw,uint8_t *targetip);
+static int arp_rx_response(ip_info_t *ipi,uint8_t *senderhw,
+ uint8_t *senderip);
+static int arp_rx_callback(ebuf_t *buf,void *ref);
+
+
+/* *********************************************************************
+ * arp_tx_query(ipi,destaddr)
+ *
+ * Transmit an ARP QUERY message. ARP QUERY messages are sent
+ * to the Ethernet broadcast address.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * destaddr - IP address to query
+ *
+ * Return value:
+ * 0 - success
+ * <0 - failure
+ ********************************************************************* */
+
+static int arp_tx_query(ip_info_t *ipi,uint8_t *destaddr)
+{
+ ebuf_t *buf;
+ uint8_t hwaddr[ENET_ADDR_LEN];
+
+ /*
+ * Get a buffer.
+ */
+
+ buf = eth_alloc(ipi->eth_info,ipi->arp_port);
+ if (!buf) return -1;
+
+ /*
+ * fill in the fields
+ */
+
+ ebuf_append_u16_be(buf,ARP_HWADDRSPACE_ETHERNET);
+ ebuf_append_u16_be(buf,PROTOSPACE_IP);
+ ebuf_append_u8(buf,ENET_ADDR_LEN);
+ ebuf_append_u8(buf,IP_ADDR_LEN);
+ ebuf_append_u16_be(buf,ARP_OPCODE_REQUEST);
+ ebuf_append_bytes(buf,ipi->arp_hwaddr,ENET_ADDR_LEN);
+ ebuf_append_bytes(buf,ipi->net_info.ip_addr,IP_ADDR_LEN);
+ memset(hwaddr,0,ENET_ADDR_LEN);
+ ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN);
+ ebuf_append_bytes(buf,destaddr,IP_ADDR_LEN);
+
+ /*
+ * Transmit the packet
+ */
+
+ eth_send(buf,(uint8_t *)eth_broadcast);
+ eth_free(buf);
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * arp_delete(ae)
+ *
+ * Delete an ARP entry. The usual reason for calling this routine
+ * is to reclaim unused ARP entries, but an ARP entry may be
+ * manually deleted as well.
+ *
+ * Input parameters:
+ * ae - arp entry
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void arp_delete(arpentry_t *ae)
+{
+ ebuf_t *buf;
+
+ /*
+ * Free any buffers associated with the ARP entry.
+ */
+
+ while ((buf = (ebuf_t *) q_deqnext(&(ae->ae_txqueue)))) {
+ eth_free(buf);
+ }
+
+ /*
+ * Reset the important fields
+ */
+
+ ae->ae_timer = 0;
+ ae->ae_usage = 0;
+ ae->ae_retries = 0;
+ ae->ae_state = ae_unused;
+}
+
+
+/* *********************************************************************
+ * _arp_add(ipi,destip,desthw)
+ *
+ * Add a new ARP entry to the ARP table [internal routine]. If
+ * there is no room in the table, some other entry is kicked
+ * out.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * destip - target IP address
+ * desthw - target hardware address
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _arp_add(ip_info_t *ipi,uint8_t *destip,uint8_t *desthw)
+{
+ arpentry_t *ae;
+
+ ae = arp_find_entry(ipi,desthw);
+ if (!ae) {
+ ae = arp_new_entry(ipi);
+ }
+
+ memcpy(ae->ae_ipaddr,destip,IP_ADDR_LEN);
+ memcpy(ae->ae_ethaddr,desthw,ENET_ADDR_LEN);
+
+ ae->ae_retries = 0;
+ ae->ae_timer = 0; /* keep forever */
+ ae->ae_permanent = TRUE;
+ ae->ae_state = ae_established;
+
+ arp_tx_waiting(ae);
+}
+
+
+/* *********************************************************************
+ * _arp_lookup(ipi,destip)
+ *
+ * Look up an ARP entry [internal routine]. Given an IP address,
+ * return the hardware address to send the packets to, or
+ * NULL if no ARP entry exists.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * destip - destination IP address
+ *
+ * Return value:
+ * pointer to Ethernet hardware address, or NULL if not found
+ ********************************************************************* */
+
+uint8_t *_arp_lookup(ip_info_t *ipi,uint8_t *destip)
+{
+ arpentry_t *ae;
+
+ ae = arp_find_entry(ipi,destip);
+ if (ae == NULL) return NULL;
+
+ return ae->ae_ethaddr;
+}
+
+/* *********************************************************************
+ * _arp_lookup_and_send(ipi,buf,dest)
+ *
+ * Transmit a packet [internal routine]. This routine is called
+ * by the IP layer when it wants to send a packet. We look
+ * through the ARP table to find a suitable destination host and
+ * transmit the packet. If there is no ARP entry, an ARP request
+ * is transmitted and the packet is saved on a queue for when
+ * the address is resolved.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * buf - ebuf to transmit
+ * dest - destination IP address
+ *
+ * Return value:
+ * 0 if ok
+ * <0 if error
+ ********************************************************************* */
+
+int _arp_lookup_and_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *dest)
+{
+ arpentry_t *ae;
+
+ ae = arp_find_entry(ipi,dest);
+
+ if (ae == NULL) {
+ /*
+ * No ARP entry yet, create one and send the query
+ */
+ ae = arp_new_entry(ipi);
+ memcpy(ae->ae_ipaddr,dest,IP_ADDR_LEN);
+ q_enqueue(&(ae->ae_txqueue),(queue_t *) buf);
+ ae->ae_retries = ARP_QUERY_RETRIES;
+ ae->ae_timer = ARP_QUERY_TIMER;
+ ae->ae_state = ae_arping;
+ arp_tx_query(ipi,ae->ae_ipaddr);
+ }
+ else {
+ /*
+ * have an ARP entry. If established, just send the
+ * packet now. Otherwise, queue on arp queue if there's room.
+ */
+ if (ae->ae_state == ae_established) {
+ ae->ae_usage++;
+ if (!ae->ae_permanent) {
+ ae->ae_timer = ARP_KEEP_TIMER;
+ }
+ eth_send(buf,ae->ae_ethaddr);
+ eth_free(buf);
+ }
+ else {
+ if (q_count(&(ae->ae_txqueue)) < ARP_TXWAIT_MAX) {
+ q_enqueue(&(ae->ae_txqueue),(queue_t *) buf);
+ }
+ else {
+ /* no room, silently drop */
+ eth_free(buf);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * arp_tx_waiting(ae)
+ *
+ * Transmit all pending packets on the specified ARP entry's
+ * queue. Packets get queued to an ARP entry when the address
+ * has not completed resolution. Once resolved, this routine
+ * is called to flush the packets out.
+ *
+ * Input parameters:
+ * ae - arp entry
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void arp_tx_waiting(arpentry_t *ae)
+{
+ ebuf_t *buf;
+
+ while ((buf = (ebuf_t *) q_deqnext(&(ae->ae_txqueue)))) {
+ eth_send(buf,ae->ae_ethaddr);
+ eth_free(buf);
+ }
+}
+
+
+/* *********************************************************************
+ * arp_new_entry(ipi)
+ *
+ * Create a new ARP entry, deleting an active entry if necessary.
+ *
+ * Input parameters:
+ * ipi - IP information
+ *
+ * Return value:
+ * arp entry pointer
+ ********************************************************************* */
+
+static arpentry_t *arp_new_entry(ip_info_t *ipi)
+{
+ arpentry_t *ae;
+ arpentry_t *victim = NULL;
+ int idx;
+ int minusage = 0x7FFFFFFF;
+
+ /*
+ * First scan the table and find an empty entry.
+ */
+
+ ae = ipi->arp_table;
+ for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) {
+ if (ae->ae_state == ae_unused) {
+ return ae;
+ }
+ }
+
+ /*
+ * If all entries are in use, pick the one with the
+ * lowest usage count. This isn't very scientific,
+ * and perhaps should use a timer of some sort.
+ */
+
+ ae = ipi->arp_table;
+ for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) {
+ if (ae->ae_usage < minusage) {
+ victim = ae;
+ minusage = ae->ae_usage;
+ }
+ }
+
+ /*
+ * In the highly unlikely event that all entries have
+ * overflow values in their usage counters, just take the
+ * first table entry.
+ */
+
+ if (victim == NULL) victim = ipi->arp_table;
+
+ /*
+ * Clear out the old entry and use it.
+ */
+
+ arp_delete(victim);
+
+ return victim;
+}
+
+/* *********************************************************************
+ * arp_find_entry(ipi,ipaddr)
+ *
+ * Find an ARP entry in the table. Given an IP address, this
+ * routine locates the corresponding ARP table entry. We also
+ * reset the expiration timer for the ARP entry, to prevent
+ * it from from being deleted.
+ *
+ * Input parameters:
+ * ipi - IP info
+ * ipaddr - IP address we're looking for
+ *
+ * Return value:
+ * arp entry pointer, or NULL if not found
+ ********************************************************************* */
+
+static arpentry_t *arp_find_entry(ip_info_t *ipi,uint8_t *ipaddr)
+{
+ arpentry_t *ae;
+ int idx;
+
+ ae = ipi->arp_table;
+
+ for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) {
+ if (ae->ae_state != ae_unused) {
+ if (memcmp(ae->ae_ipaddr,ipaddr,IP_ADDR_LEN) == 0) {
+ if (ae->ae_state == ae_established)
+ ae->ae_timer = ARP_KEEP_TIMER;
+ return ae;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/* *********************************************************************
+ * arp_rx_query(ipi,srcaddr,targethw,targetip)
+ *
+ * Process a received ARP QUERY message. When we get an ARP,
+ * transmit a reply to the sender.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * srcaddr - source IP address
+ * targethw - target hardware address
+ * targetip - target IP address (should be our address)
+ *
+ * Input parameters:
+ * 0 if ok
+ * else <0 = error
+ ********************************************************************* */
+
+static int arp_rx_query(ip_info_t *ipi,uint8_t *srcaddr,
+ uint8_t *targethw,uint8_t *targetip)
+{
+ ebuf_t *txbuf;
+
+ /*
+ * Allocate a packet and form the reply
+ */
+
+ txbuf = eth_alloc(ipi->eth_info,ipi->arp_port);
+ if (!txbuf) return -1;
+
+ ebuf_append_u16_be(txbuf,ARP_HWADDRSPACE_ETHERNET);
+ ebuf_append_u16_be(txbuf,PROTOSPACE_IP);
+ ebuf_append_u8(txbuf,ENET_ADDR_LEN);
+ ebuf_append_u8(txbuf,IP_ADDR_LEN);
+ ebuf_append_u16_be(txbuf,ARP_OPCODE_REPLY);
+
+ ebuf_append_bytes(txbuf,ipi->arp_hwaddr,ENET_ADDR_LEN);
+ ebuf_append_bytes(txbuf,ipi->net_info.ip_addr,IP_ADDR_LEN);
+
+ ebuf_append_bytes(txbuf,targethw,ENET_ADDR_LEN);
+ ebuf_append_bytes(txbuf,targetip,IP_ADDR_LEN);
+
+ eth_send(txbuf,srcaddr);
+ eth_free(txbuf);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * arp_rx_response(ipi,senderhw,senderip)
+ *
+ * Process a received ARP RESPONSE packet. This packet contains
+ * the hardware address of some host we were querying. Fill
+ * in the rest of the entries in the ARP table and
+ * transmit any pending packets.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * senderhw - sender's hardware address
+ * senderip - sender's IP address
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int arp_rx_response(ip_info_t *ipi,uint8_t *senderhw,uint8_t *senderip)
+{
+ int idx;
+ arpentry_t *ae;
+
+ ae = ipi->arp_table;
+
+ for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) {
+ if (ae->ae_state != ae_unused) {
+ if (memcmp(ae->ae_ipaddr,senderip,IP_ADDR_LEN) == 0) {
+ memcpy(ae->ae_ethaddr,senderhw,ENET_ADDR_LEN);
+ ae->ae_state = ae_established;
+ ae->ae_timer = ARP_KEEP_TIMER;
+ ae->ae_retries = 0;
+ ae->ae_permanent = FALSE;
+ arp_tx_waiting(ae);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * arp_rx_callback(buf,ref)
+ *
+ * Callback for ARP protocol packets. This routine is called
+ * by the datalink layer when we receive an ARP packet. Parse
+ * the packet and call any packet-specific processing routines
+ *
+ * Input parameters:
+ * buf - ebuf that we received
+ * ref - reference data when we opened the port. This is
+ * our IP information structure
+ *
+ * Return value:
+ * ETH_DROP or ETH_KEEP.
+ ********************************************************************* */
+
+static int arp_rx_callback(ebuf_t *buf,void *ref)
+{
+ ip_info_t *ipi = ref;
+ uint16_t t16;
+ uint8_t t8;
+ uint16_t opcode;
+ uint8_t senderip[IP_ADDR_LEN];
+ uint8_t senderhw[ENET_ADDR_LEN];
+ uint8_t targetip[IP_ADDR_LEN];
+ uint8_t targethw[ENET_ADDR_LEN];
+
+ /*
+ * ARP packets have to be at least 28 bytes
+ */
+
+ if (ebuf_length(buf) < 28) goto drop;
+
+ /*
+ * We only do the Ethernet hardware space
+ */
+
+ ebuf_get_u16_be(buf,t16);
+ if (t16 != ARP_HWADDRSPACE_ETHERNET) goto drop;
+
+ /*
+ * We only do the IP protocol space
+ */
+
+ ebuf_get_u16_be(buf,t16);
+ if (t16 != PROTOSPACE_IP) goto drop;
+
+ /*
+ * The IP and Ethernet address lengths had better be right.
+ */
+
+ ebuf_get_u8(buf,t8);
+ if (t8 != ENET_ADDR_LEN) goto drop;
+
+ ebuf_get_u8(buf,t8);
+ if (t8 != IP_ADDR_LEN) goto drop;
+
+ /*
+ * Get the opcode and other fields.
+ */
+
+ ebuf_get_u16_be(buf,opcode);
+
+ ebuf_get_bytes(buf,senderhw,ENET_ADDR_LEN);
+ ebuf_get_bytes(buf,senderip,IP_ADDR_LEN);
+ ebuf_get_bytes(buf,targethw,ENET_ADDR_LEN);
+ ebuf_get_bytes(buf,targetip,IP_ADDR_LEN);
+
+ /*
+ * If it's not for us, just drop it.
+ */
+
+ if (memcmp(targetip,ipi->net_info.ip_addr,IP_ADDR_LEN) != 0) goto drop;
+
+ /*
+ * Dispatch to an appropriate routine.
+ */
+
+ switch (opcode) {
+ case ARP_OPCODE_REQUEST:
+ arp_rx_query(ipi,ebuf_srcaddr(buf),senderhw,senderip);
+ break;
+ case ARP_OPCODE_REPLY:
+ arp_rx_response(ipi,senderhw,senderip);
+ break;
+ }
+
+drop:
+ return ETH_DROP;
+}
+
+/* *********************************************************************
+ * _arp_timer_tick(ipi)
+ *
+ * ARP timer processing [internal routine]. This routine
+ * counts down timer ticks in the ARP entries, causing retransmits
+ * or ARP entry expirations to happen.
+ *
+ * Input parameters:
+ * ipi - IP information
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _arp_timer_tick(ip_info_t *ipi)
+{
+ int idx;
+ arpentry_t *ae;
+
+ ae = ipi->arp_table;
+
+ /*
+ * Walk through the ARP table.
+ */
+
+ for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) {
+
+ switch (ae->ae_state) {
+ case ae_unused:
+ /*
+ * Unused entry. Do nothing.
+ */
+ break;
+
+ case ae_arping:
+ /*
+ * Entry is arping. Count down the timer, and retransmit
+ * the ARP message.
+ */
+ ae->ae_timer--;
+ if (ae->ae_timer <= 0) {
+ if (ae->ae_retries == 0) {
+ arp_delete(ae);
+ }
+ else {
+ ae->ae_retries--;
+ ae->ae_timer = ARP_QUERY_TIMER;
+ arp_tx_query(ipi,ae->ae_ipaddr);
+ }
+ }
+ break;
+
+ case ae_established:
+ /*
+ * Established entry. Count down the timer and
+ * delete the ARP entry. If the timer is zero
+ * already, it's a permanent ARP entry.
+ */
+ if (ae->ae_timer == 0) break;
+ ae->ae_timer--;
+ if (ae->ae_timer == 0) arp_delete(ae);
+ break;
+ }
+ }
+
+}
+
+/* *********************************************************************
+ * _arp_send_gratuitous(ipi)
+ *
+ * Transmit the "gratuitous arp" (an ARP for our own IP address).
+ * This is done customarily when an interface is initialized.
+ *
+ * Input parameters:
+ * ipi - IP information
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _arp_send_gratuitous(ip_info_t *ipi)
+{
+ if (!ip_addriszero(ipi->net_info.ip_addr)) {
+ arp_tx_query(ipi,ipi->net_info.ip_addr);
+ }
+}
+
+/* *********************************************************************
+ * _arp_init(ipi)
+ *
+ * Initialize the ARP layer [internal routine]
+ *
+ * Input parameters:
+ * ipi - IP information
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _arp_init(ip_info_t *ipi)
+{
+ int8_t arpproto[2];
+ int idx;
+ arpentry_t *ae;
+
+ /*
+ * Allocate space for the ARP table
+ */
+
+ ipi->arp_table = KMALLOC(ARP_TABLE_SIZE*sizeof(arpentry_t),0);
+
+ if (ipi->arp_table == NULL) return NULL;
+
+ /*
+ * Initialize the ARP table.
+ */
+
+ ae = ipi->arp_table;
+ for (idx = 0; idx < ARP_TABLE_SIZE; idx++) {
+ ae->ae_state = ae_unused;
+ ae->ae_timer = 0;
+ ae->ae_usage = 0;
+ ae->ae_retries = 0;
+ ae->ae_permanent = 0;
+ q_init(&(ae->ae_txqueue));
+ ae++;
+ }
+
+ /*
+ * Open the Ethernet portal for ARP packets
+ */
+
+ arpproto[0] = (PROTOSPACE_ARP >> 8) & 0xFF;
+ arpproto[1] = (PROTOSPACE_ARP & 0xFF);
+ ipi->arp_port = eth_open(ipi->eth_info,ETH_PTYPE_DIX,arpproto,arp_rx_callback,ipi);
+
+ if (ipi->arp_port < 0) {
+ KFREE(ipi->arp_table);
+ ipi->arp_table = NULL;
+ return -1;
+ }
+
+ /*
+ * Remember our hardware address
+ */
+
+ eth_gethwaddr(ipi->eth_info,ipi->arp_hwaddr);
+
+ /*
+ * Send a query for ourselves if our IP address is set
+ */
+
+ _arp_send_gratuitous(ipi);
+
+ return 0;
+
+}
+
+
+/* *********************************************************************
+ * _arp_uninit(ipi)
+ *
+ * Uninitialize the ARP interface. This is called when the
+ * network module is shut down.
+ *
+ * Input parameters:
+ * ipi - IP information
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _arp_uninit(ip_info_t *ipi)
+{
+ int idx;
+ arpentry_t *ae;
+
+ /*
+ * Close the Ethernet portal
+ */
+
+ eth_close(ipi->eth_info,ipi->arp_port);
+
+ /*
+ * Clear out the ARP Table.
+ */
+
+ ae = ipi->arp_table;
+ for (idx = 0; idx < ARP_TABLE_SIZE; idx++) {
+ if (ae->ae_state != ae_unused) arp_delete(ae);
+ ae++;
+ }
+
+ /*
+ * Free up the memory.
+ */
+
+ KFREE(ipi->arp_table);
+ ipi->arp_table = NULL;
+ ipi->arp_port = -1;
+}
+
+
+/* *********************************************************************
+ * _arp_enumerate(ipi,entrynum,ipaddr,hwaddr)
+ *
+ * Enumerate the ARP table. This is used by user-interface
+ * routines to display the current contents of the ARP table.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * entrynum - entry index
+ * ipaddr - buffer to copy entry's IP address to
+ * hwaddr - buffer to copy entry's hardware address to
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _arp_enumerate(ip_info_t *ipi,int entrynum,uint8_t *ipaddr,uint8_t *hwaddr)
+{
+ arpentry_t *ae;
+ int idx;
+
+ ae = ipi->arp_table;
+ for (idx = 0; idx < ARP_TABLE_SIZE; idx++) {
+ if (ae->ae_state != ae_unused) {
+ if (entrynum == 0) {
+ memcpy(ipaddr,ae->ae_ipaddr,IP_ADDR_LEN);
+ memcpy(hwaddr,ae->ae_ethaddr,ENET_ADDR_LEN);
+ return 0;
+ }
+ entrynum--;
+ }
+ ae++;
+ }
+
+ return -1;
+}
+
+
+/* *********************************************************************
+ * _arp_delete(ipi,ipaddr)
+ *
+ * Delete an ARP entry. This routine takes an IP address, looks
+ * up its ARP table entry, and removes it from the table.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * ipaddr - IP address whose entry to delete
+ *
+ * Return value:
+ * 0 if entry was deleted
+ * <0 if entry was not found
+ ********************************************************************* */
+
+int _arp_delete(ip_info_t *ipi,uint8_t *ipaddr)
+{
+ arpentry_t *ae;
+
+ ae = arp_find_entry(ipi,ipaddr);
+
+ if (ae) {
+ arp_delete(ae);
+ return 0;
+ }
+ return -1;
+}
diff --git a/cfe/cfe/net/net_dhcp.c b/cfe/cfe/net/net_dhcp.c
new file mode 100644
index 0000000..84a39e6
--- /dev/null
+++ b/cfe/cfe/net/net_dhcp.c
@@ -0,0 +1,869 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * DHCP Client File: net_dhcp.c
+ *
+ * This module contains a DHCP client.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "env_subr.h"
+
+#include "cfe_iocb.h"
+#include "cfe_devfuncs.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+#include "cfe_error.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "cfe.h"
+
+#include "net_api.h"
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+
+#define UDP_PORT_BOOTPS 67
+#define UDP_PORT_BOOTPC 68
+
+#define DHCP_REQ_TIMEOUT (1*CFE_HZ)
+#define DHCP_NUM_RETRIES 8
+
+#define DHCP_OP_BOOTREQUEST 1
+#define DHCP_OP_BOOTREPLY 2
+
+#define DHCP_HWTYPE_ETHERNET 1
+
+#define DHCP_TAG_FUNCTION 53
+#define DHCP_FUNCTION_DISCOVER 1
+#define DHCP_FUNCTION_OFFER 2
+#define DHCP_FUNCTION_REQUEST 3
+#define DHCP_FUNCTION_ACK 5
+
+#define DHCP_TAG_NETMASK 1
+#define DHCP_TAG_DOMAINNAME 0x0F
+#define DHCP_TAG_GATEWAY 0x03
+#define DHCP_TAG_NAMESERVER 0x06
+#define DHCP_TAG_SWAPSERVER 0x10
+#define DHCP_TAG_ROOTPATH 0x11
+#define DHCP_TAG_EXTENSIONS 0x12
+#define DHCP_TAG_SERVERIDENT 54
+#define DHCP_TAG_PARAMLIST 55
+#define DHCP_TAG_CLIENTID 61
+#define DHCP_TAG_CLASSID 60
+#define DHCP_TAG_REQADDR 50
+#define DHCP_TAG_LEASE_TIME 51
+#define DHCP_TAG_SCRIPT 130 /* CFE extended option */
+#define DHCP_TAG_OPTIONS 131 /* CFE extended option */
+
+#define DHCP_TAG_END 0xFF
+
+#define DHCP_MAGIC_NUMBER 0x63825363
+
+/*#define _DEBUG_*/
+
+
+/* *********************************************************************
+ * dhcp_set_envvars(reply)
+ *
+ * Using the supplied DHCP reply data, set environment variables
+ * to contain data from the reply.
+ *
+ * Input parameters:
+ * reply - dhcp reply
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void dhcp_set_envvars(dhcpreply_t *reply)
+{
+ char buffer[50];
+
+ env_delenv("BOOT_SERVER");
+ env_delenv("BOOT_FILE");
+ env_delenv("BOOT_SCRIPT");
+ env_delenv("BOOT_OPTIONS");
+
+ if (reply->dr_bootserver[0] | reply->dr_bootserver[1] |
+ reply->dr_bootserver[2] | reply->dr_bootserver[3]) {
+ sprintf(buffer,"%I",reply->dr_bootserver);
+ env_setenv("BOOT_SERVER",buffer,ENV_FLG_BUILTIN);
+ }
+
+ if (reply->dr_bootfile && reply->dr_bootfile[0]) {
+ env_setenv("BOOT_FILE",reply->dr_bootfile,ENV_FLG_BUILTIN);
+ }
+
+ if (reply->dr_script && reply->dr_script[0]) {
+ env_setenv("BOOT_SCRIPT",reply->dr_script,ENV_FLG_BUILTIN);
+ }
+
+ if (reply->dr_options && reply->dr_options[0]) {
+ env_setenv("BOOT_OPTIONS",reply->dr_options,ENV_FLG_BUILTIN);
+ }
+}
+
+/* *********************************************************************
+ * dhcp_dumptag(tag,len,buf)
+ *
+ * Dump out information from a DHCP tag
+ *
+ * Input parameters:
+ * tag - tag ID
+ * len - length of data
+ * buf - data
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+#ifdef _DEBUG_
+static void dhcp_dumptag(uint8_t tag,uint8_t len,uint8_t *buf)
+{
+ unsigned int idx;
+
+ xprintf("DHCP: ");
+
+ switch (tag) {
+ case DHCP_TAG_FUNCTION:
+ xprintf("DHCP Function: %d\n",buf[0]);
+ break;
+ case DHCP_TAG_LEASE_TIME:
+ idx = (((unsigned int) buf[0]) << 24) |
+ (((unsigned int) buf[1]) << 16) |
+ (((unsigned int) buf[2]) << 8) |
+ (((unsigned int) buf[3]) << 0);
+ xprintf("Lease Time: %d seconds\n",idx);
+ break;
+ case DHCP_TAG_SERVERIDENT:
+ xprintf("DHCP Server ID: %d.%d.%d.%d\n",
+ buf[0],buf[1],buf[2],buf[3]);
+ break;
+ case DHCP_TAG_NETMASK:
+ xprintf("Netmask: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]);
+ break;
+ case DHCP_TAG_DOMAINNAME:
+ buf[len] = 0;
+ xprintf("Domain: %s\n",buf);
+ break;
+ case DHCP_TAG_GATEWAY:
+ xprintf("Gateway: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]);
+ break;
+ case DHCP_TAG_NAMESERVER:
+ xprintf("Nameserver: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]);
+ break;
+ case DHCP_TAG_SWAPSERVER:
+ buf[len] = 0;
+ xprintf("Swapserver: %s\n",buf);
+ break;
+ case DHCP_TAG_ROOTPATH:
+ buf[len] = 0;
+ xprintf("Rootpath: %s\n",buf);
+ break;
+ case DHCP_TAG_SCRIPT:
+ buf[len] = 0;
+ xprintf("CFE Script: %s\n",buf);
+ break;
+ case DHCP_TAG_OPTIONS:
+ buf[len] = 0;
+ xprintf("CFE Boot Options: %s\n",buf);
+ break;
+ default:
+ xprintf("Tag %d len %d [",tag,len);
+ for (idx = 0; idx < len; idx++) {
+ if ((buf[idx] >= 32) && (buf[idx] < 127)) xprintf("%c",buf[idx]);
+ }
+ xprintf("]\n");
+ break;
+
+ }
+}
+#endif
+
+/* *********************************************************************
+ * dhcp_free_reply(reply)
+ *
+ * Free memory associated with a DHCP reply.
+ *
+ * Input parameters:
+ * reply - pointer to DHCP reply
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void dhcp_free_reply(dhcpreply_t *reply)
+{
+ if (reply->dr_hostname) KFREE(reply->dr_hostname);
+ if (reply->dr_domainname) KFREE(reply->dr_domainname);
+ if (reply->dr_bootfile) KFREE(reply->dr_bootfile);
+ if (reply->dr_rootpath) KFREE(reply->dr_rootpath);
+ if (reply->dr_swapserver) KFREE(reply->dr_swapserver);
+ if (reply->dr_script) KFREE(reply->dr_script);
+ if (reply->dr_options) KFREE(reply->dr_options);
+ KFREE(reply);
+}
+
+/* *********************************************************************
+ * dhcp_build_discover()
+ *
+ * Build a DHCP DISCOVER packet
+ *
+ * Input parameters:
+ * hwaddr - our hardware address
+ * idptr - pointer to int to receive the DHCP packet ID
+ * serveraddr - pointer to server address (REQUEST) or
+ * NULL (DISCOVER)
+ * ebufptr - receives pointer to ebuf
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int dhcp_build_discover(uint8_t *hwaddr,
+ uint32_t id,
+ ebuf_t **ebufptr)
+{
+ uint8_t ipaddr[IP_ADDR_LEN];
+ ebuf_t *buf;
+ uint8_t junk[128];
+
+ /*
+ * Get a buffer and fill it in.
+ */
+
+ ipaddr[0] = 0; ipaddr[1] = 0; ipaddr[2] = 0; ipaddr[3] = 0;
+ memset(junk,0,sizeof(junk));
+
+ buf = udp_alloc();
+
+ if (buf == NULL) {
+ return CFE_ERR_NOMEM;
+ }
+
+ memset(buf->eb_ptr,0,548);
+
+ ebuf_append_u8(buf,DHCP_OP_BOOTREQUEST);
+ ebuf_append_u8(buf,DHCP_HWTYPE_ETHERNET);
+ ebuf_append_u8(buf,ENET_ADDR_LEN);
+ ebuf_append_u8(buf,0); /* hops */
+ ebuf_append_u32_be(buf,id);
+ ebuf_append_u16_be(buf,0); /* sec since boot */
+ ebuf_append_u16_be(buf,0); /* flags */
+
+ ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* ciaddr */
+ ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* yiaddr */
+ ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* siaddr */
+ ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* giaddr */
+
+ ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); /* chaddr */
+ ebuf_append_bytes(buf,junk,10); /* rest of chaddr */
+ ebuf_append_bytes(buf,junk,64); /* sname */
+ ebuf_append_bytes(buf,junk,128); /* file */
+
+ ebuf_append_u32_be(buf,DHCP_MAGIC_NUMBER);
+
+ ebuf_append_u8(buf,DHCP_TAG_FUNCTION); /* function code */
+ ebuf_append_u8(buf,1);
+ ebuf_append_u8(buf,DHCP_FUNCTION_DISCOVER);
+
+ ebuf_append_u8(buf,DHCP_TAG_PARAMLIST);
+ ebuf_append_u8(buf,8); /* count of tags that follow */
+ ebuf_append_u8(buf,DHCP_TAG_NETMASK);
+ ebuf_append_u8(buf,DHCP_TAG_DOMAINNAME);
+ ebuf_append_u8(buf,DHCP_TAG_GATEWAY);
+ ebuf_append_u8(buf,DHCP_TAG_NAMESERVER);
+ ebuf_append_u8(buf,DHCP_TAG_SWAPSERVER);
+ ebuf_append_u8(buf,DHCP_TAG_ROOTPATH);
+ ebuf_append_u8(buf,DHCP_TAG_SCRIPT);
+ ebuf_append_u8(buf,DHCP_TAG_OPTIONS);
+
+
+ ebuf_append_u8(buf,DHCP_TAG_END); /* terminator */
+
+ /*
+ * Return the packet
+ */
+
+ *ebufptr = buf;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * dhcp_build_request()
+ *
+ * Build a DHCP DISCOVER or REQUEST packet
+ *
+ * Input parameters:
+ * hwaddr - our hardware address
+ * idptr - pointer to int to receive the DHCP packet ID
+ * serveraddr - pointer to server address (REQUEST) or
+ * NULL (DISCOVER)
+ * ebufptr - receives pointer to ebuf
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int dhcp_build_request(uint8_t *hwaddr,
+ uint32_t id,
+ uint8_t *serveraddr,
+ uint8_t *reqip,
+ ebuf_t **ebufptr)
+{
+ uint8_t ipaddr[IP_ADDR_LEN];
+ ebuf_t *buf;
+ uint8_t junk[128];
+
+ /*
+ * Get a buffer and fill it in.
+ */
+
+ ipaddr[0] = 0; ipaddr[1] = 0; ipaddr[2] = 0; ipaddr[3] = 0;
+ memset(junk,0,sizeof(junk));
+
+ buf = udp_alloc();
+
+ if (buf == NULL) {
+ return CFE_ERR_NOMEM;
+ }
+
+ memset(buf->eb_ptr,0,548);
+
+ ebuf_append_u8(buf,DHCP_OP_BOOTREQUEST);
+ ebuf_append_u8(buf,DHCP_HWTYPE_ETHERNET);
+ ebuf_append_u8(buf,ENET_ADDR_LEN);
+ ebuf_append_u8(buf,0); /* hops */
+ ebuf_append_u32_be(buf,id);
+ ebuf_append_u16_be(buf,0); /* sec since boot */
+ ebuf_append_u16_be(buf,0); /* flags */
+
+ ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* ciaddr */
+ ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* yiaddr */
+ ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* siaddr */
+ ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* giaddr */
+
+ ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); /* chaddr */
+ ebuf_append_bytes(buf,junk,10); /* rest of chaddr */
+
+ ebuf_append_bytes(buf,junk,64); /* sname */
+
+ ebuf_append_bytes(buf,junk,128); /* file */
+
+ ebuf_append_u32_be(buf,DHCP_MAGIC_NUMBER);
+
+ ebuf_append_u8(buf,DHCP_TAG_FUNCTION); /* function code */
+ ebuf_append_u8(buf,1);
+
+ ebuf_append_u8(buf,DHCP_FUNCTION_REQUEST);
+
+ ebuf_append_u8(buf,DHCP_TAG_REQADDR);
+ ebuf_append_u8(buf,IP_ADDR_LEN);
+ ebuf_append_bytes(buf,reqip,IP_ADDR_LEN);
+
+ ebuf_append_u8(buf,DHCP_TAG_SERVERIDENT); /* server ID */
+ ebuf_append_u8(buf,IP_ADDR_LEN);
+ ebuf_append_bytes(buf,serveraddr,IP_ADDR_LEN);
+
+ ebuf_append_u8(buf,DHCP_TAG_CLIENTID); /* client ID */
+ ebuf_append_u8(buf,7);
+ ebuf_append_u8(buf,1);
+ ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN);
+
+ ebuf_append_u8(buf,DHCP_TAG_PARAMLIST);
+ ebuf_append_u8(buf,8); /* count of tags that follow */
+ ebuf_append_u8(buf,DHCP_TAG_NETMASK);
+ ebuf_append_u8(buf,DHCP_TAG_DOMAINNAME);
+ ebuf_append_u8(buf,DHCP_TAG_GATEWAY);
+ ebuf_append_u8(buf,DHCP_TAG_NAMESERVER);
+ ebuf_append_u8(buf,DHCP_TAG_SWAPSERVER);
+ ebuf_append_u8(buf,DHCP_TAG_ROOTPATH);
+ ebuf_append_u8(buf,DHCP_TAG_SCRIPT);
+ ebuf_append_u8(buf,DHCP_TAG_OPTIONS);
+
+
+ ebuf_append_u8(buf,DHCP_TAG_END); /* terminator */
+
+ /*
+ * Return the packet
+ */
+
+ *ebufptr = buf;
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * dhcp_wait_reply(s,id,reply,serveraddr)
+ *
+ * Wait for a reply from the DHCP server
+ *
+ * Input parameters:
+ * s - socket
+ * id - ID of request we sent
+ * reply - structure to store results in
+ * expfcode - expected DHCP_FUNCTION tag value
+ *
+ * Return value:
+ * 0 if ok (reply found)
+ * else error
+ ********************************************************************* */
+
+static int dhcp_wait_reply(int s,uint32_t id,dhcpreply_t *reply,int expfcode)
+{
+ uint32_t tmpd;
+ uint8_t tmpb;
+ int64_t timer;
+ int nres = 0;
+ uint8_t ciaddr[IP_ADDR_LEN];
+ uint8_t yiaddr[IP_ADDR_LEN];
+ uint8_t siaddr[IP_ADDR_LEN];
+ uint8_t giaddr[IP_ADDR_LEN];
+ uint8_t junk[128];
+ char *hostname;
+ char *bootfile;
+ ebuf_t *buf;
+ int fcode = -1;
+
+ /*
+ * Set a timer for the response
+ */
+
+ TIMER_SET(timer,DHCP_REQ_TIMEOUT);
+
+ /*
+ * Start waiting...
+ */
+
+ while (!TIMER_EXPIRED(timer)) {
+ POLL();
+
+ buf = udp_recv(s);
+ if (!buf) continue;
+
+ ebuf_get_u8(buf,tmpb);
+ if (tmpb != DHCP_OP_BOOTREPLY) {
+ goto drop;
+ }
+
+ ebuf_get_u8(buf,tmpb);
+ if (tmpb != DHCP_HWTYPE_ETHERNET) {
+ goto drop;
+ }
+
+ ebuf_get_u8(buf,tmpb);
+ if (tmpb != ENET_ADDR_LEN) {
+ goto drop;
+ }
+
+ ebuf_skip(buf,1); /* hops */
+
+ ebuf_get_u32_be(buf,tmpd); /* check ID */
+ if (tmpd != id) {
+ goto drop;
+ }
+
+ ebuf_skip(buf,2); /* seconds since boot */
+ ebuf_skip(buf,2); /* flags */
+
+ ebuf_get_bytes(buf,ciaddr,IP_ADDR_LEN);
+ ebuf_get_bytes(buf,yiaddr,IP_ADDR_LEN);
+ ebuf_get_bytes(buf,siaddr,IP_ADDR_LEN);
+ ebuf_get_bytes(buf,giaddr,IP_ADDR_LEN);
+
+ ebuf_skip(buf,16); /* hardware address */
+ hostname = ebuf_ptr(buf);
+ ebuf_skip(buf,64);
+ bootfile = ebuf_ptr(buf);
+
+ ebuf_skip(buf,128);
+
+#ifdef _DEBUG_
+ xprintf("Client IP: %d.%d.%d.%d\n",ciaddr[0],ciaddr[1],ciaddr[2],ciaddr[3]);
+ xprintf("Your IP: %d.%d.%d.%d\n",yiaddr[0],yiaddr[1],yiaddr[2],yiaddr[3]);
+ xprintf("Server IP: %d.%d.%d.%d\n",siaddr[0],siaddr[1],siaddr[2],siaddr[3]);
+ xprintf("Gateway IP: %d.%d.%d.%d\n",giaddr[0],giaddr[1],giaddr[2],giaddr[3]);
+ xprintf("hostname: %s\n",hostname);
+ xprintf("boot file: %s\n",bootfile);
+#endif
+
+ memcpy(reply->dr_ipaddr,yiaddr,IP_ADDR_LEN);
+ memcpy(reply->dr_gateway,giaddr,IP_ADDR_LEN);
+ memcpy(reply->dr_bootserver,siaddr,IP_ADDR_LEN);
+ if (*hostname) reply->dr_hostname = strdup(hostname);
+ if (*bootfile) reply->dr_bootfile = strdup(bootfile);
+
+ /*
+ * Test for options - look for magic number
+ */
+
+ ebuf_get_u32_be(buf,tmpd);
+
+ memcpy(reply->dr_dhcpserver,buf->eb_usrptr,IP_ADDR_LEN);
+
+ if (tmpd == DHCP_MAGIC_NUMBER) {
+ uint8_t tag;
+ uint8_t len;
+
+ while (buf->eb_length > 0) {
+ ebuf_get_u8(buf,tag);
+ if (tag == DHCP_TAG_END) break;
+ ebuf_get_u8(buf,len);
+ ebuf_get_bytes(buf,junk,len);
+
+#ifdef _DEBUG_
+ dhcp_dumptag(tag,len,junk);
+#endif
+
+ switch (tag) {
+ case DHCP_TAG_FUNCTION:
+ fcode = (uint8_t) junk[0];
+ break;
+ case DHCP_TAG_NETMASK:
+ memcpy(reply->dr_netmask,junk,IP_ADDR_LEN);
+ break;
+ case DHCP_TAG_GATEWAY:
+ memcpy(reply->dr_gateway,junk,IP_ADDR_LEN);
+ break;
+ case DHCP_TAG_NAMESERVER:
+ memcpy(reply->dr_nameserver,junk,IP_ADDR_LEN);
+ break;
+ case DHCP_TAG_DOMAINNAME:
+ junk[len] = 0;
+ if (len) reply->dr_domainname = strdup(junk);
+ break;
+ case DHCP_TAG_SWAPSERVER:
+ junk[len] = 0;
+ if (len) reply->dr_swapserver = strdup(junk);
+ break;
+ case DHCP_TAG_SERVERIDENT:
+ if (len == IP_ADDR_LEN) {
+ memcpy(reply->dr_dhcpserver,junk,len);
+ }
+ break;
+ case DHCP_TAG_ROOTPATH:
+ junk[len] = 0;
+ if (len) reply->dr_rootpath = strdup(junk);
+ break;
+ case DHCP_TAG_SCRIPT:
+ junk[len] = 0;
+ if (len) reply->dr_script = strdup(junk);
+ break;
+ case DHCP_TAG_OPTIONS:
+ junk[len] = 0;
+ if (len) reply->dr_options = strdup(junk);
+ break;
+ }
+ }
+ }
+
+ if (fcode != expfcode) {
+ goto drop;
+ }
+
+ udp_free(buf);
+ nres++;
+ break;
+
+ drop:
+ udp_free(buf);
+ }
+
+ if (nres > 0) return 0;
+ else return CFE_ERR_TIMEOUT;
+}
+
+
+/* *********************************************************************
+ * dhcp_do_dhcpdiscover(s,hwaddr,reply)
+ *
+ * Request an IP address from the DHCP server. On success, the
+ * dhcpreply_t structure will be filled in
+ *
+ * Input parameters:
+ * s - udp socket
+ * hwaddr - our hardware address
+ * reply - pointer to reply buffer.
+ *
+ * Return value:
+ * 0 if a response was received
+ * else error code
+ ********************************************************************* */
+
+static int dhcp_do_dhcpdiscover(int s,uint8_t *hwaddr,dhcpreply_t *reply)
+{
+ ebuf_t *buf;
+ uint32_t id;
+ uint8_t ipaddr[IP_ADDR_LEN];
+ int res;
+
+ /*
+ * Packet ID is the current time
+ */
+
+ id = (uint32_t)cfe_ticks;
+
+ /*
+ * Build the DISCOVER request
+ */
+
+ res = dhcp_build_discover(hwaddr,id,&buf);
+ if (res != 0) return res;
+
+ /*
+ * Send the packet to the IP broadcast (255.255.255.255)
+ */
+
+ ipaddr[0] = 0xFF; ipaddr[1] = 0xFF; ipaddr[2] = 0xFF; ipaddr[3] = 0xFF;
+ udp_send(s,buf,ipaddr);
+
+ /*
+ * Wait for a reply
+ */
+
+ res = dhcp_wait_reply(s,id,reply,DHCP_FUNCTION_OFFER);
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * dhcp_do_dhcprequest(s,hwaddr,reply,discover_reply)
+ *
+ * Request an IP address from the DHCP server. On success, the
+ * dhcpreply_t structure will be filled in
+ *
+ * Input parameters:
+ * s - udp socket
+ * hwaddr - our hardware address
+ * reply - pointer to reply buffer.
+ * discover_reply - pointer to previously received DISCOVER data
+ *
+ * Return value:
+ * 0 if a response was received
+ * else error code
+ ********************************************************************* */
+
+static int dhcp_do_dhcprequest(int s,uint8_t *hwaddr,
+ dhcpreply_t *reply,
+ dhcpreply_t *discover_reply)
+{
+ ebuf_t *buf;
+ uint32_t id;
+ uint8_t ipaddr[IP_ADDR_LEN];
+ int res;
+
+ /*
+ * Packet ID is the current time
+ */
+
+ id = (uint32_t)cfe_ticks;
+
+ /*
+ * Build the DHCP REQUEST request
+ */
+
+ res = dhcp_build_request(hwaddr,
+ id,
+ discover_reply->dr_dhcpserver,
+ discover_reply->dr_ipaddr,
+ &buf);
+
+ if (res != 0) return res;
+
+ /*
+ * Send the packet to the IP broadcast (255.255.255.255)
+ */
+
+ ipaddr[0] = 0xFF; ipaddr[1] = 0xFF; ipaddr[2] = 0xFF; ipaddr[3] = 0xFF;
+ udp_send(s,buf,ipaddr);
+
+ /*
+ * Wait for a reply
+ */
+
+ res = dhcp_wait_reply(s,id,reply,DHCP_FUNCTION_ACK);
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * dhcp_bootrequest(reply)
+ *
+ * Request an IP address from the DHCP server. On success, the
+ * dhcpreply_t structure will be allocated.
+ *
+ * Input parameters:
+ * reply - pointer to pointer to reply.
+ *
+ * Return value:
+ * 0 if no responses received
+ * >0 for some responses received
+ * else error code
+ ********************************************************************* */
+
+int dhcp_bootrequest(dhcpreply_t **rep)
+{
+ uint8_t *hwaddr;
+ int s;
+ dhcpreply_t *discover_reply;
+ dhcpreply_t *request_reply;
+ int nres = 0;
+ int retries;
+ uint32_t id;
+
+ id = (uint32_t) cfe_ticks;
+
+ /*
+ * Start with empty reply buffers. Since we use a portion of the
+ * discover reply in the request, we'll keep two of them.
+ */
+
+ discover_reply = KMALLOC(sizeof(dhcpreply_t),0);
+ if (discover_reply == NULL) {
+ return CFE_ERR_NOMEM;
+ }
+ memset(discover_reply,0,sizeof(dhcpreply_t));
+
+ request_reply = KMALLOC(sizeof(dhcpreply_t),0);
+ if (request_reply == NULL) {
+ KFREE(discover_reply);
+ return CFE_ERR_NOMEM;
+ }
+ memset(request_reply,0,sizeof(dhcpreply_t));
+
+
+ /*
+ * Get our hw addr
+ */
+
+ hwaddr = net_getparam(NET_HWADDR);
+ if (!hwaddr) {
+ KFREE(discover_reply);
+ KFREE(request_reply);
+ return CFE_ERR_NETDOWN;
+ }
+
+ /*
+ * Open UDP port
+ */
+
+ s = udp_socket(UDP_PORT_BOOTPS);
+ if (s < 0) {
+ KFREE(discover_reply);
+ KFREE(request_reply);
+ return CFE_ERR_NOHANDLES;
+ }
+
+ udp_bind(s,UDP_PORT_BOOTPC);
+
+ /*
+ * Do the boot request. Start by sending the OFFER message
+ */
+
+ nres = CFE_ERR_TIMEOUT;
+ for (retries = 0; retries < DHCP_NUM_RETRIES; retries++) {
+ nres = dhcp_do_dhcpdiscover(s,hwaddr,discover_reply);
+ if (nres == 0) break;
+ if (nres == CFE_ERR_TIMEOUT) continue;
+ break;
+ }
+
+ /*
+ * If someone sent us a response, send the REQUEST message
+ * to get a lease.
+ */
+
+ if (nres == 0) {
+
+ /*
+ * Now, send the REQUEST message and get a response.
+ */
+
+ for (retries = 0; retries < DHCP_NUM_RETRIES; retries++) {
+ nres = dhcp_do_dhcprequest(s,hwaddr,
+ request_reply,
+ discover_reply);
+ if (nres == 0) break;
+ if (nres == CFE_ERR_TIMEOUT) continue;
+ break;
+ }
+ }
+
+ /*
+ * All done with the discover reply.
+ */
+
+ dhcp_free_reply(discover_reply);
+
+ /*
+ * All done with UDP
+ */
+
+ udp_close(s);
+
+ /*
+ * Return the reply info.
+ */
+
+ if (nres == 0) {
+ *rep = request_reply;
+ }
+ else {
+ *rep = NULL;
+ dhcp_free_reply(request_reply);
+ }
+
+ return nres;
+}
diff --git a/cfe/cfe/net/net_dns.c b/cfe/cfe/net/net_dns.c
new file mode 100755
index 0000000..89b50b1
--- /dev/null
+++ b/cfe/cfe/net/net_dns.c
@@ -0,0 +1,354 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Domain Name System Resolver File: net_dns.c
+ *
+ * This module provides minimal support for looking up IP addresses
+ * from DNS name servers (RFCxxxx)
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_timer.h"
+#include "cfe_error.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "cfe.h"
+
+#include "net_api.h"
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0)
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define UDP_PORT_DNS 53
+
+#define DNS_FLG_QUERY 0x0000
+#define DNS_FLG_RESPONSE 0x8000
+#define DNS_OPCODE_QUERY 0x0000
+#define DNS_FLG_AA 0x0400
+#define DNS_FLG_TC 0x0200
+#define DNS_FLG_RD 0x0100
+#define DNS_FLG_RA 0x0080
+#define DNS_RCODE_MASK 0x000F
+#define DNS_RCODE_OK 0x0000
+#define DNS_RCODE_NAMEERR 0x0003
+
+
+#define QTYPE_HOSTADDR 1
+#define QCLASS_INTERNET 1
+
+#define DNS_QUERY_TIMEOUT 1 /* seconds */
+#define DNS_RETRY_COUNT 8
+
+
+/* *********************************************************************
+ * dns_dolookup(s,hostname,ipaddr)
+ *
+ * Look up a host name and return its IP address.
+ *
+ * Input parameters:
+ * s - udp socket
+ * server - name server to query
+ * hostname - host name to find
+ * ipaddr - buffer to place IP address
+ *
+ * Return value:
+ * 0 if no responses found
+ * >0 to indicate number of response records (usually 1)
+ * else error code
+ ********************************************************************* */
+
+static int dns_dolookup(int s,uint8_t *server,char *hostname,uint8_t *ipaddr)
+{
+ ebuf_t *buf;
+ uint16_t id;
+ uint16_t tmp;
+ char *tok;
+ char *ptr;
+ int64_t timer;
+ int nres = 0;
+ uint16_t nqr,nar,nns,nxr;
+ uint8_t tmpb;
+ int expired;
+
+
+ /*
+ * Use the current time for our request ID
+ */
+
+ id = (uint16_t) cfe_ticks;
+
+ /*
+ * Get a buffer and fill it in.
+ */
+
+ buf = udp_alloc();
+
+ ebuf_append_u16_be(buf,id);
+ ebuf_append_u16_be(buf,(DNS_FLG_QUERY | DNS_OPCODE_QUERY | DNS_FLG_RD));
+ ebuf_append_u16_be(buf,1); /* one question */
+ ebuf_append_u16_be(buf,0); /* no answers */
+ ebuf_append_u16_be(buf,0); /* no server resource records */
+ ebuf_append_u16_be(buf,0); /* no additional records */
+
+ /*
+ * Chop up the hostname into pieces, basically replacing
+ * the dots with length indicators.
+ */
+
+ ptr = hostname;
+
+ while ((tok = strchr(ptr,'.'))) {
+ ebuf_append_u8(buf,(tok-ptr));
+ ebuf_append_bytes(buf,ptr,(tok-ptr));
+ ptr = tok + 1;
+ }
+
+ ebuf_append_u8(buf,strlen(ptr));
+ ebuf_append_bytes(buf,ptr,strlen(ptr));
+ ebuf_append_u8(buf,0);
+ ebuf_append_u16_be(buf,QTYPE_HOSTADDR);
+ ebuf_append_u16_be(buf,QCLASS_INTERNET);
+
+ /*
+ * Send the request to the name server
+ */
+
+ udp_send(s,buf,server);
+
+ /*
+ * Set a timer for the response
+ */
+
+ TIMER_SET(timer,DNS_QUERY_TIMEOUT*CFE_HZ);
+
+ /*
+ * Start waiting...
+ */
+
+ while (!(expired = TIMER_EXPIRED(timer))) {
+ POLL();
+
+ buf = udp_recv(s);
+ if (!buf) continue;
+
+ /* IDs must match */
+
+ ebuf_get_u16_be(buf,tmp);
+ if (id != tmp) goto drop;
+
+ /* It must be a response */
+
+ ebuf_get_u16_be(buf,tmp);
+
+ if ((tmp & DNS_FLG_RESPONSE) == 0) goto drop;
+
+ if ((tmp & DNS_RCODE_MASK) != DNS_RCODE_OK) {
+ udp_free(buf);
+ /* name error */
+ break;
+ }
+
+ ebuf_get_u16_be(buf,nqr);
+ ebuf_get_u16_be(buf,nar);
+ ebuf_get_u16_be(buf,nns);
+ ebuf_get_u16_be(buf,nxr);
+
+ if (nar == 0) {
+ goto drop;
+ }
+
+ while (nqr > 0) {
+ if (ebuf_length(buf) <= 0) {
+ goto drop;
+ }
+ for (;;) {
+ ebuf_get_u8(buf,tmpb);
+ if (tmpb == 0) break;
+ ebuf_skip(buf,tmpb);
+ if (ebuf_length(buf) <= 0) {
+ goto drop;
+ }
+ }
+ ebuf_skip(buf,2); /* skip QTYPE */
+ ebuf_skip(buf,2); /* skip QCLASS */
+ nqr--; /* next question record */
+ }
+
+ /*
+ * Loop through the answer records to find
+ * a HOSTADDR record. Ignore any other records
+ * we find.
+ */
+
+ while (nar > 0) {
+ uint16_t rname,rtype,rclass,dlen;
+
+ ebuf_get_u16_be(buf,rname); /* resource name */
+
+ ebuf_get_u16_be(buf,rtype); /* resource type */
+
+ ebuf_get_u16_be(buf,rclass); /* resource class */
+
+ ebuf_skip(buf,4); /* time to live */
+
+ ebuf_get_u16_be(buf,dlen); /* length of data */
+
+ if (rtype != QTYPE_HOSTADDR) {
+ ebuf_skip(buf,dlen);
+ nar--;
+ continue;
+ }
+ if (rclass != QCLASS_INTERNET) {
+ ebuf_skip(buf,dlen);
+ nar--;
+ continue;
+ }
+
+ if (dlen != IP_ADDR_LEN) {
+ ebuf_skip(buf,dlen);
+ nar--;
+ continue;
+ }
+
+ ebuf_get_bytes(buf,ipaddr,IP_ADDR_LEN);
+ break;
+ }
+
+ if (nar == 0) goto drop;
+
+ udp_free(buf);
+ nres++;
+ break;
+
+ drop:
+ udp_free(buf);
+ }
+
+ if (expired) return CFE_ERR_TIMEOUT;
+ if (nres == 0) return CFE_ERR_HOSTUNKNOWN;
+ return nres;
+}
+
+
+/* *********************************************************************
+ * dns_lookup(hostname,ipaddr)
+ *
+ * Look up a host name and return its IP address.
+ *
+ * Input parameters:
+ * hostname - host name to find
+ * ipaddr - buffer to place IP address
+ *
+ * Return value:
+ * 0 if no responses found
+ * >0 to indicate number of response records (usually 1)
+ * else error code
+ ********************************************************************* */
+
+int dns_lookup(char *hostname,uint8_t *ipaddr)
+{
+ int s;
+ int nres = 0;
+ int retries;
+ char temphostname[100];
+ uint8_t *server;
+ uint8_t *tok;
+
+ /*
+ * If it's a valid IP address, don't look it up.
+ */
+
+ if (parseipaddr(hostname,ipaddr) == 0) return 1;
+
+ /*
+ * Add default domain if no domain was specified
+ */
+
+ if (strchr(hostname,'.') == NULL) {
+ tok = net_getparam(NET_DOMAIN);
+ if (tok) {
+ xsprintf(temphostname,"%s.%s",hostname,tok);
+ hostname = temphostname;
+ }
+ }
+
+ /*
+ * Figure out who the name server is
+ */
+
+ server = net_getparam(NET_NAMESERVER);
+
+ if (!server) return CFE_ERR_NETDOWN;
+ if (ip_addriszero(server)) return CFE_ERR_NONAMESERVER;
+
+ /*
+ * Go do the name server lookup
+ */
+
+ s = udp_socket(UDP_PORT_DNS);
+ if (s < 0) return CFE_ERR_NOHANDLES;
+
+ for (retries = 0; retries < DNS_RETRY_COUNT; retries++) {
+ nres = dns_dolookup(s,server,hostname,ipaddr);
+ if (nres == CFE_ERR_TIMEOUT) continue;
+ if (nres >= 0) break;
+ }
+
+ udp_close(s);
+
+ return nres;
+
+}
diff --git a/cfe/cfe/net/net_ebuf.h b/cfe/cfe/net/net_ebuf.h
new file mode 100644
index 0000000..11d83c1
--- /dev/null
+++ b/cfe/cfe/net/net_ebuf.h
@@ -0,0 +1,165 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Network EBUF macros File: net_ebuf.h
+ *
+ * This file contains macros and function prototypes for
+ * messing with "ebuf" buffers. ebufs describe network
+ * packets. They're sort of like poor-man's mbufs :-)
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+
+#define ENET_MAX_PKT 1514
+#define ENET_CRC_SIZE 4
+#define ENET_ADDR_LEN 6
+#define ENET_DIX_HEADER 14
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+
+typedef struct ebuf_s {
+ queue_t eb_qblock; /* linkage */
+ unsigned int eb_length; /* length of area at eb_ptr */
+ unsigned int eb_status; /* rx/tx status */
+ int eb_port; /* eth port that owns buffer */
+ void *eb_device; /* underlying net device */
+ int eb_usrdata; /* user-defined stuff */
+ uint8_t *eb_usrptr; /* user-defined stuff */
+ uint8_t *eb_ptr; /* current ptr within pkt */
+ uint8_t eb_data[0x5F0]; /* data, must be > ENET_MAX_PKT */
+ /* and divisible by sizeof(uint) */
+} ebuf_t;
+
+/*
+ * Macros to initialize ebufs
+ */
+
+#define ebuf_init_rx(eb) (eb)->eb_ptr = (eb)->eb_data; \
+ (eb)->eb_length = 0; \
+ (eb)->eb_status = 0
+
+#define ebuf_init_tx(eb) (eb)->eb_ptr = (eb)->eb_data; \
+ (eb)->eb_length = 0; \
+ (eb)->eb_status = 0
+
+/*
+ * Macros to move the currens position within an ebuf
+ */
+
+#define ebuf_prepend(eb,amt) (eb)->eb_ptr -= amt; (eb)->eb_length += (amt)
+#define ebuf_adjust(eb,amt) (eb)->eb_ptr += (amt); (eb)->eb_length += (amt)
+#define ebuf_seek(eb,amt) (eb)->eb_ptr += (amt)
+
+#define ebuf_remlen(eb) ((eb)->eb_length)
+#define ebuf_length(eb) ((eb)->eb_length)
+#define ebuf_ptr(eb) ((eb)->eb_ptr)
+#define ebuf_setlength(eb,amt) (eb)->eb_length = (amt)
+
+/*
+ * ebuf_append_xxx macros - these macros add data to the
+ * end of a packet, adjusting the length
+ */
+
+#define ebuf_append_u8(eb,b) ((eb)->eb_ptr[(eb)->eb_length++]) = (b) ;
+#define ebuf_append_u16_be(eb,w) ebuf_append_u8(eb,((w) >> 8) & 0xFF) ; \
+ ebuf_append_u8(eb,((w) & 0xFF))
+
+#define ebuf_append_u32_be(eb,w) ebuf_append_u8(eb,((w) >> 24) & 0xFF) ; \
+ ebuf_append_u8(eb,((w) >> 16) & 0xFF) ; \
+ ebuf_append_u8(eb,((w) >> 8) & 0xFF) ; \
+ ebuf_append_u8(eb,((w) & 0xFF))
+
+#define ebuf_append_bytes(eb,b,l) memcpy(&((eb)->eb_ptr[(eb)->eb_length]),(b),(l)); \
+ (eb)->eb_length += (l)
+
+/*
+ * ebuf_put_xxx macros - these macros modify data in the middle
+ * of a packet, typically in an area already allocated with
+ * ebuf_adjust. The length is not updated, but the pointer is.
+ */
+
+#define ebuf_put_u8(eb,b) *((eb)->eb_ptr++) = (b)
+#define ebuf_put_u16_be(eb,w) ebuf_put_u8(eb,((w) >> 8) & 0xFF) ; \
+ ebuf_put_u8(eb,((w) & 0xFF))
+
+#define ebuf_put_u32_be(eb,w) ebuf_put_u8(eb,((w) >> 24) & 0xFF) ; \
+ ebuf_put_u8(eb,((w) >> 16) & 0xFF) ; \
+ ebuf_put_u8(eb,((w) >> 8) & 0xFF) ; \
+ ebuf_put_u8(eb,((w) & 0xFF))
+
+#define ebuf_put_bytes(eb,b,l) memcpy((buf)->eb_ptr,(b),(l)) ; (buf)->eb_ptr += (l)
+
+#define ebuf_srcaddr(eb) &((eb)->eb_data[6])
+#define ebuf_destaddr(eb) &((eb)->eb_data[0])
+
+/* return next byte from the ebuf, and advance pointer */
+
+#define ebuf_skip(eb,amt) (eb)->eb_length -= (amt); (eb)->eb_ptr += (amt)
+
+#define ebuf_get_u8(eb,v) (eb)->eb_length--; \
+ v = (*((eb)->eb_ptr++))
+
+/* return next u16 from the ebuf, big-endian */
+
+#define ebuf_get_u16_be(eb,v) (eb)->eb_ptr+=2; \
+ (eb)->eb_length-=2; \
+ v = ( ((uint16_t)*((eb)->eb_ptr-1)) | \
+ (((uint16_t)*((eb)->eb_ptr-2)) << 8) )
+
+/* return next u32 from the ebuf, big-endian */
+
+#define ebuf_get_u32_be(eb,v) (eb)->eb_ptr+=4; \
+ (eb)->eb_length-=4; \
+ v = ( ((uint32_t)*((eb)->eb_ptr-1)) | \
+ (((uint32_t)*((eb)->eb_ptr-2)) << 8) | \
+ (((uint32_t)*((eb)->eb_ptr-3)) << 16) | \
+ (((uint32_t)*((eb)->eb_ptr-4)) << 24) )
+
+#define ebuf_get_bytes(eb,b,l) memcpy((b),(buf)->eb_ptr,(l)) ; (eb)->eb_ptr += (l) ; (eb)->eb_length -= (l)
+
+
diff --git a/cfe/cfe/net/net_ether.c b/cfe/cfe/net/net_ether.c
new file mode 100644
index 0000000..0dec6e8
--- /dev/null
+++ b/cfe/cfe/net/net_ether.c
@@ -0,0 +1,705 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Ethernet Datalink File: net_ether.c
+ *
+ * This module provides a simple datalink (LLC1) interface
+ * capable of demultiplexing standard DIX-style Ethernet packets.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_iocb.h"
+#include "cfe_devfuncs.h"
+#include "cfe_ioctl.h"
+#include "cfe_error.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define ETH_MAX_PORTS 4
+#define ETH_MAX_BUFFERS 8
+
+/* *********************************************************************
+ * Types
+ ********************************************************************* */
+
+typedef struct ether_port_s {
+ int ep_dev;
+ uint8_t ep_proto[8];
+ int ep_ptype;
+ int ep_mtu;
+ int (*ep_rxcallback)(ebuf_t *buf,void *ref);
+ void *ep_ref;
+} ether_port_t;
+
+struct ether_info_s {
+ ether_port_t *eth_ports;
+ queue_t eth_freelist;
+ uint8_t eth_hwaddr[6];
+ int eth_devhandle;
+ ebuf_t *eth_bufpool;
+};
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+const uint8_t eth_broadcast[ENET_ADDR_LEN] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
+
+
+/* *********************************************************************
+ * eth_open(eth,ptye,pdata,cb)
+ *
+ * Open an Ethernet portal.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * ptype - protocol type (ETH_PTYPE_xxx)
+ * pdata - protocol data (two bytes for DIX protocols)
+ * cb - callback for receive packets
+ *
+ * Return value:
+ * portal number
+ * or <0 if error occured
+ ********************************************************************* */
+
+int eth_open(ether_info_t *eth,int ptype,char *pdata,
+ int (*cb)(ebuf_t *buf,void *ref),void *ref)
+{
+ ether_port_t *p;
+ int portnum;
+
+ p = eth->eth_ports;
+
+ for (portnum = 0; portnum < ETH_MAX_PORTS; portnum++,p++) {
+ if (p->ep_rxcallback == NULL) break;
+ }
+
+ if (portnum == ETH_MAX_PORTS) {
+ return CFE_ERR_NOHANDLES; /* no ports left */
+ }
+
+ switch (ptype) {
+ case ETH_PTYPE_DIX:
+ p->ep_proto[0] = pdata[0];
+ p->ep_proto[1] = pdata[1];
+ p->ep_mtu = ENET_MAX_PKT - ENET_DIX_HEADER;
+ break;
+
+ case ETH_PTYPE_802SAP:
+ case ETH_PTYPE_802SNAP:
+ default:
+ /*
+ * we only support DIX etypes right now. If we ever want to support
+ * non-IP stacks (unlikely) this will need to change.
+ */
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ p->ep_ptype = ptype;
+ p->ep_rxcallback = cb;
+ p->ep_dev = eth->eth_devhandle;
+ p->ep_ref = ref;
+
+ return portnum;
+}
+
+
+/* *********************************************************************
+ * eth_close(eth,port)
+ *
+ * Close an Ethernet portal, freeing resources allocated to it.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * port - portal number
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void eth_close(ether_info_t *eth,int port)
+{
+ ether_port_t *p = &(eth->eth_ports[port]);
+
+ p->ep_ptype = 0;
+ p->ep_rxcallback = NULL;
+ p->ep_dev = 0;
+ memset(&(p->ep_proto[0]),0,sizeof(p->ep_proto));
+}
+
+
+/* *********************************************************************
+ * eth_findport(eth,buf)
+ *
+ * Locate the portal associated with a particular Ethernet packet.
+ * Parse the packet enough to determine if it's addressed
+ * correctly and to a valid protocol, and then look up the
+ * corresponding portal.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * buf - ethernet buffer to check
+ *
+ * Return value:
+ * eth_port_t structure or NULL if packet should be dropped
+ ********************************************************************* */
+
+static ether_port_t *eth_findport(ether_info_t *eth,ebuf_t *buf)
+{
+ int idx;
+ ether_port_t *p;
+
+ /*
+ * A few pre-flight checks: packets *from* multicast addresses
+ * are not allowed.
+ */
+
+ if (buf->eb_ptr[6] & 1) return NULL;
+
+ /*
+ * Packets smaller than minimum size are not allowed.
+ */
+
+ if (buf->eb_length < 60) return NULL;
+
+ /*
+ * Packets with bad status are not allowed
+ */
+
+ /* XXX if (buf->eb_status != 0) return NULL; */
+
+ /*
+ * Okay, scan the port list and find the matching portal.
+ */
+
+ for (idx = 0, p = eth->eth_ports; idx < ETH_MAX_PORTS; idx++,p++) {
+ if (!p->ep_rxcallback) continue; /* port not in use */
+
+ switch (p->ep_ptype) {
+ case ETH_PTYPE_DIX:
+ if ((p->ep_proto[0] == buf->eb_ptr[12]) &&
+ (p->ep_proto[1] == buf->eb_ptr[13])) {
+ ebuf_skip(buf,ENET_DIX_HEADER);
+ return p;
+ }
+ break;
+ case ETH_PTYPE_802SAP:
+ case ETH_PTYPE_802SNAP:
+ default:
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/* *********************************************************************
+ * eth_poll(eth)
+ *
+ * Poll devices and process inbound packets. If new packets arrive,
+ * call the appropriate callback routine.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void eth_poll(ether_info_t *eth)
+{
+ ebuf_t *buf;
+ ether_port_t *p;
+ int res;
+
+ /* XXX should this loop until all packets are processed? */
+
+ /*
+ * If no packets, just get out now
+ */
+
+ if (cfe_inpstat(eth->eth_devhandle) == 0) return;
+
+ /*
+ * get a packet from the free list
+ */
+
+ buf = (ebuf_t *) q_deqnext(&(eth->eth_freelist));
+ if (!buf) return;
+
+ /*
+ * Receive network data into the packet buffer
+ */
+
+ ebuf_init_rx(buf);
+ res = cfe_read(eth->eth_devhandle,buf->eb_ptr,ENET_MAX_PKT);
+
+ /*
+ * if receive error, get out now.
+ */
+
+ if (res <= 0) {
+ q_enqueue(&(eth->eth_freelist),(queue_t *) buf);
+ return;
+ }
+
+ /*
+ * init the rest of the fields in the ebuf
+ */
+
+ buf->eb_length = res;
+ buf->eb_status = 0;
+ buf->eb_device = eth;
+ buf->eb_usrdata = 0;
+
+ /*
+ * Look up the portal to receive the new packet
+ */
+
+ p = eth_findport(eth,buf);
+
+ /*
+ * Call the callback routine if we want to keep this
+ * buffer. Otherwise, drop it on the floor
+ */
+
+ if (p) {
+ buf->eb_port = p - eth->eth_ports;
+ res = (*(p->ep_rxcallback))(buf,p->ep_ref);
+ if (res == ETH_DROP) eth_free(buf);
+ }
+ else {
+ eth_free(buf);
+ }
+}
+
+
+/* *********************************************************************
+ * eth_gethwaddr(eth,hwaddr)
+ *
+ * Obtain the hardware address of the Ethernet interface.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * hwaddr - place to put hardware address - 6 bytes
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void eth_gethwaddr(ether_info_t *eth,uint8_t *hwaddr)
+{
+ memcpy(hwaddr,eth->eth_hwaddr,ENET_ADDR_LEN);
+}
+
+/* *********************************************************************
+ * eth_sethwaddr(eth,hwaddr)
+ *
+ * Set the hardware address of the Ethernet interface.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * hwaddr - new hardware address - 6 bytes
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void eth_sethwaddr(ether_info_t *eth,uint8_t *hwaddr)
+{
+ int retlen;
+
+ memcpy(eth->eth_hwaddr,hwaddr,ENET_ADDR_LEN);
+ cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_SETHWADDR,&(eth->eth_hwaddr[0]),
+ sizeof(eth->eth_hwaddr),&retlen,0);
+
+}
+
+
+
+/* *********************************************************************
+ * eth_setspeed(eth,speed)
+ *
+ * Set the speed of the Ethernet interface.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * speed - target speed (or auto for automatic)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+int eth_setspeed(ether_info_t *eth,int speed)
+{
+ int retlen;
+
+ return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_SETSPEED,
+ (uint8_t *) &speed,sizeof(speed),&retlen,0);
+
+}
+
+/* *********************************************************************
+ * eth_setloopback(eth,loop)
+ *
+ * Configure loopback mode options for the Ethernet
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * loop - loopback mode to set
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+int eth_setloopback(ether_info_t *eth,int loop)
+{
+ int retlen;
+
+ return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_SETLOOPBACK,
+ (uint8_t *) &loop,sizeof(loop),&retlen,0);
+
+}
+
+/* *********************************************************************
+ * eth_getspeed(eth,speed)
+ *
+ * Get the current setting for the Ethernet speed (note that this
+ * is the speed we want to achieve, not the current speed)
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * speed - pointer to int to receive speed
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+int eth_getspeed(ether_info_t *eth,int *speed)
+{
+ int retlen;
+
+ return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_GETSPEED,
+ (uint8_t *) speed,sizeof(*speed),&retlen,0);
+
+}
+
+/* *********************************************************************
+ * eth_getloopback(eth,loop)
+ *
+ * Read the loopback state of the Ethernet interface
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * loop - pointer to int to receive loopback state
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+int eth_getloopback(ether_info_t *eth,int *loop)
+{
+ int retlen;
+
+ return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_GETLOOPBACK,
+ (uint8_t *) loop,sizeof(*loop),&retlen,0);
+
+}
+
+/* *********************************************************************
+ * eth_send(buf,dest)
+ *
+ * Transmit a packet.
+ *
+ * Input parameters:
+ * buf - ebuf structure describing packet
+ * dest - destination hardware address
+ *
+ * Return value:
+ * 0 - no error
+ * else error code
+ ********************************************************************* */
+
+int eth_send(ebuf_t *buf,uint8_t *dest)
+{
+ ether_info_t *eth = buf->eb_device;
+ ether_port_t *p = &(eth->eth_ports[buf->eb_port]);
+ int res;
+
+ switch (p->ep_ptype) {
+ case ETH_PTYPE_DIX:
+ ebuf_seek(buf,-ENET_DIX_HEADER);
+ ebuf_put_bytes(buf,dest,ENET_ADDR_LEN);
+ ebuf_put_bytes(buf,eth->eth_hwaddr,ENET_ADDR_LEN);
+ ebuf_put_bytes(buf,p->ep_proto,2);
+ /* adjust pointer and add in DIX header length */
+ ebuf_prepend(buf,ENET_DIX_HEADER);
+ break;
+ case ETH_PTYPE_802SAP:
+ case ETH_PTYPE_802SNAP:
+ default:
+ eth_free(buf); /* should not happen */
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ res = cfe_write(p->ep_dev,ebuf_ptr(buf),ebuf_length(buf));
+
+ /* XXX - should we free buffers here? */
+
+ return res;
+}
+
+/* *********************************************************************
+ * eth_alloc(eth,port)
+ *
+ * Allocate an Ethernet buffer. Ethernet buffers know what
+ * ports they are associated with, since we need to reserve
+ * space for the EThernet header, which might vary in size
+ * for DIX, 802, etc.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * port - portal ID
+ *
+ * Return value:
+ * ebuf, or NULL if no ebufs left
+ ********************************************************************* */
+
+ebuf_t *eth_alloc(ether_info_t *eth,int port)
+{
+ ebuf_t *buf;
+ ether_port_t *p = &(eth->eth_ports[port]);
+
+ buf = (ebuf_t *) q_deqnext(&(eth->eth_freelist));
+ if (buf == NULL) return NULL;
+
+ buf->eb_status = 0;
+ buf->eb_port = port;
+ buf->eb_device = eth;
+ ebuf_init_tx(buf);
+
+ switch (p->ep_ptype) {
+ case ETH_PTYPE_NONE:
+ break;
+ case ETH_PTYPE_DIX:
+ ebuf_seek(buf,ENET_DIX_HEADER);
+ break;
+ case ETH_PTYPE_802SAP:
+ case ETH_PTYPE_802SNAP:
+ default:
+ /* XXX Other ether types here */
+ break;
+ }
+
+ /*
+ * 'eb_ptr' points at new data, length is cleared.
+ * We will add the length back in at send time when the
+ * ethernet header is filled in.
+ */
+ buf->eb_length = 0;
+
+ return buf;
+}
+
+/* *********************************************************************
+ * eth_free(buf)
+ *
+ * Free an ebuf.
+ *
+ * Input parameters:
+ * buf - ebuf to free
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void eth_free(ebuf_t *buf)
+{
+ ether_info_t *eth = buf->eb_device;
+
+ q_enqueue(&(eth->eth_freelist),(queue_t *) buf);
+}
+
+
+/* *********************************************************************
+ * eth_getmtu(eth,port)
+ *
+ * Return the mtu of the specified Ethernet port. The mtu
+ * is the maximum number of bytes you can put in the buffer,
+ * excluding the Ethernet header.
+ *
+ * Input parameters:
+ * eth - ethernet context
+ * port - portal ID
+ *
+ * Return value:
+ * number of bytes
+ ********************************************************************* */
+
+
+int eth_getmtu(ether_info_t *eth,int port)
+{
+ ether_port_t *p = &(eth->eth_ports[port]);
+
+ return p->ep_mtu;
+}
+
+
+/* *********************************************************************
+ * eth_init(devname)
+ *
+ * Create an Ethernet context for a particular Ethernet device.
+ *
+ * Input parameters:
+ * devname - device name for underlying Ethernet driver
+ *
+ * Return value:
+ * ethernet context, or NULL of it could not be created.
+ ********************************************************************* */
+
+ether_info_t *eth_init(char *devname)
+{
+ int idx;
+ ebuf_t *buf;
+ ether_info_t *eth;
+ int devhandle;
+ int retlen;
+
+ /*
+ * Open the device driver
+ */
+
+ devhandle = cfe_open(devname);
+ if (devhandle < 0) return NULL;
+
+ eth = KMALLOC(sizeof(ether_info_t),0);
+ if (!eth) {
+ cfe_close(devhandle);
+ return NULL;
+ }
+
+ memset(eth,0,sizeof(ether_info_t));
+
+ /*
+ * Obtain hardware address
+ */
+
+ cfe_ioctl(devhandle,IOCTL_ETHER_GETHWADDR,&(eth->eth_hwaddr[0]),
+ sizeof(eth->eth_hwaddr),&retlen,0);
+
+ /*
+ * Allocate portal table
+ */
+
+ eth->eth_ports = KMALLOC(ETH_MAX_PORTS*sizeof(ether_port_t),0);
+ if (!eth->eth_ports) {
+ cfe_close(devhandle);
+ KFREE(eth);
+ return NULL;
+ }
+
+ memset(eth->eth_ports,0,ETH_MAX_PORTS*sizeof(ether_port_t));
+
+ /*
+ * Allocate buffer pool
+ */
+
+ eth->eth_bufpool = (ebuf_t *) KMALLOC(sizeof(ebuf_t)*ETH_MAX_BUFFERS,0);
+ if (!eth->eth_bufpool) {
+ cfe_close(devhandle);
+ KFREE(eth->eth_ports);
+ KFREE(eth);
+ return NULL;
+ }
+
+ /*
+ * Chain buffers onto the free list
+ */
+
+ q_init(&(eth->eth_freelist));
+ buf = eth->eth_bufpool;
+ for (idx = 0; idx < ETH_MAX_BUFFERS; idx++) {
+ q_enqueue(&(eth->eth_freelist),(queue_t *) buf);
+ buf++;
+ }
+
+ /*
+ * Remember the device handle
+ */
+
+ eth->eth_devhandle = devhandle;
+
+ return eth;
+}
+
+
+/* *********************************************************************
+ * eth_uninit(eth)
+ *
+ * Close and free up an Ethernet context
+ *
+ * Input parameters:
+ * eth - ethernet context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void eth_uninit(ether_info_t *eth)
+{
+ cfe_close(eth->eth_devhandle);
+ KFREE(eth->eth_bufpool);
+ KFREE(eth->eth_ports);
+ KFREE(eth);
+}
+
+
diff --git a/cfe/cfe/net/net_ether.h b/cfe/cfe/net/net_ether.h
new file mode 100644
index 0000000..a94130b
--- /dev/null
+++ b/cfe/cfe/net/net_ether.h
@@ -0,0 +1,89 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Ethernet protocol demux defns File: net_ether.h
+ *
+ * constants and prototypes for the Ethernet datalink
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define ETH_PTYPE_NONE 0
+#define ETH_PTYPE_DIX 1
+#define ETH_PTYPE_802SAP 2
+#define ETH_PTYPE_802SNAP 3
+
+#define ETH_KEEP 1
+#define ETH_DROP 0
+
+/* *********************************************************************
+ * types
+ ********************************************************************* */
+
+typedef struct ether_info_s ether_info_t;
+
+/* *********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+int eth_open(ether_info_t *eth,int ptype,char *pdata,int (*cb)(ebuf_t *buf,void *ref),void *ref);
+void eth_close(ether_info_t *eth,int port);
+void eth_poll(ether_info_t *eth);
+int eth_send(ebuf_t *buf,uint8_t *dest);
+ebuf_t *eth_alloc(ether_info_t *eth,int port);
+void eth_free(ebuf_t *buf);
+ether_info_t *eth_init(char *devname);
+void eth_uninit(ether_info_t *eth);
+int eth_getmtu(ether_info_t *,int port);
+void eth_gethwaddr(ether_info_t *,uint8_t *hwaddr);
+void eth_sethwaddr(ether_info_t *,uint8_t *hwaddr);
+int eth_getspeed(ether_info_t *,int *speed);
+int eth_setspeed(ether_info_t *,int speed);
+int eth_getloopback(ether_info_t *,int *loop);
+int eth_setloopback(ether_info_t *,int loop);
+extern const uint8_t eth_broadcast[ENET_ADDR_LEN];
+
+
+
diff --git a/cfe/cfe/net/net_icmp.c b/cfe/cfe/net/net_icmp.c
new file mode 100644
index 0000000..e98bc87
--- /dev/null
+++ b/cfe/cfe/net/net_icmp.c
@@ -0,0 +1,312 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * ICMP Protocol File: net_icmp.c
+ *
+ * This module implements portions of the ICMP protocol. Note
+ * that it is not a complete implementation, just enough to
+ * generate and respond to ICMP echo requests.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_timer.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "net_ip.h"
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define ICMP_CODE_ECHO 0
+#define ICMP_TYPE_ECHOREPLY 0
+#define ICMP_TYPE_ECHOREQ 8
+
+#define ICMPMSG(type,code) (((type)<<8)|(code))
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+struct icmp_info_s {
+ ip_info_t *icmp_ipinfo;
+ queue_t icmp_echoreplies;
+ int icmp_maxreplies;
+};
+
+/* *********************************************************************
+ * ICMP_RX_CALLBACK(ref,buf,dst,src)
+ *
+ * This routine is called by the IP layer when we receive
+ * ICMP protocol messages.
+ *
+ * Input parameters:
+ * ref - reference data (an icmp_info_t)
+ * buf - the ebuf containing the buffer
+ * dst - destination IP address (us, usually)
+ * src - source IP address
+ *
+ * Return value:
+ * ETH_KEEP to keep packet, ETH_DROP to cause packet to be freed
+ ********************************************************************* */
+
+static int icmp_rx_callback(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src)
+{
+ icmp_info_t *icmp = (icmp_info_t *)ref;
+ ip_info_t *ipi = icmp->icmp_ipinfo;
+ uint16_t imsg;
+ uint16_t cksum;
+ ebuf_t *txbuf;
+ uint8_t *icmphdr;
+ int res;
+
+ imsg = ICMPMSG(buf->eb_ptr[0],buf->eb_ptr[1]);
+
+ res = ETH_DROP; /* assume we're dropping the pkt */
+
+ switch (imsg) {
+ case ICMPMSG(ICMP_TYPE_ECHOREQ,ICMP_CODE_ECHO):
+ txbuf = _ip_alloc(ipi);
+ if (txbuf) {
+ /* Construct reply from the original packet. */
+ icmphdr = txbuf->eb_ptr;
+ ebuf_append_bytes(txbuf,buf->eb_ptr,buf->eb_length);
+ icmphdr[0] = ICMP_TYPE_ECHOREPLY;
+ icmphdr[1] = ICMP_CODE_ECHO;
+ icmphdr[2] = 0; icmphdr[3] = 0;
+ cksum = ~ip_chksum(0,icmphdr,ebuf_length(txbuf));
+ icmphdr[2] = (cksum >> 8) & 0xFF;
+ icmphdr[3] = (cksum & 0xFF);
+ if (_ip_send(ipi,txbuf,src,IPPROTO_ICMP) < 0) {
+ _ip_free(ipi,txbuf);
+ }
+ }
+ break;
+
+ case ICMPMSG(ICMP_TYPE_ECHOREPLY,ICMP_CODE_ECHO):
+ if (q_count(&(icmp->icmp_echoreplies)) < icmp->icmp_maxreplies) {
+ /* We're keeping this packet, put it on the queue and don't
+ free it in the driver. */
+ q_enqueue(&(icmp->icmp_echoreplies),(queue_t *) buf);
+ res = ETH_KEEP;
+ }
+ break;
+
+ default:
+ res = ETH_DROP;
+ }
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * _ICMP_INIT(ipi)
+ *
+ * Initialize the ICMP layer.
+ *
+ * Input parameters:
+ * ipi - ipinfo structure of IP layer to attach to
+ *
+ * Return value:
+ * icmp_info_t structure or NULL if error occurs
+ ********************************************************************* */
+
+icmp_info_t *_icmp_init(ip_info_t *ipi)
+{
+ icmp_info_t *icmp;
+
+ icmp = (icmp_info_t *) KMALLOC(sizeof(icmp_info_t),0);
+ if (!icmp) return NULL;
+
+ icmp->icmp_ipinfo = ipi;
+ q_init(&(icmp->icmp_echoreplies));
+ icmp->icmp_maxreplies = 0;
+
+ _ip_register(ipi,IPPROTO_ICMP,icmp_rx_callback,icmp);
+
+ return icmp;
+}
+
+/* *********************************************************************
+ * _ICMP_UNINIT(icmp)
+ *
+ * Un-initialize the ICMP layer.
+ *
+ * Input parameters:
+ * icmp - icmp_info_t structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _icmp_uninit(icmp_info_t *icmp)
+{
+ _ip_deregister(icmp->icmp_ipinfo,IPPROTO_ICMP);
+
+ KFREE(icmp);
+}
+
+
+/* *********************************************************************
+ * _ICMP_PING(icmp,dest,seq,len)
+ *
+ * Transmit an ICMP echo request and wait for a reply.
+ *
+ * Input parameters:
+ * icmp - icmp_info_t structure
+ * dest - destination IP address
+ * seq - sequence number for ICMP packet
+ * len - length of data portion of ICMP packet
+ *
+ * Return value:
+ * <0 = error
+ * 0 = timeout
+ * >0 = reply received
+ ********************************************************************* */
+
+int _icmp_ping(icmp_info_t *icmp,uint8_t *dest,int seq,int len)
+{
+ ebuf_t *buf;
+ int64_t timer;
+ uint16_t cksum;
+ uint8_t *icmphdr;
+ uint16_t id;
+ int idx;
+ int result = 0;
+
+ /*
+ * Get an ebuf
+ */
+
+ buf = _ip_alloc(icmp->icmp_ipinfo);
+ if (buf == NULL) return -1;
+
+ /*
+ * Remember where the ICMP header is going to be so we can
+ * calculate the checksum later.
+ */
+
+ icmphdr = buf->eb_ptr;
+
+ id = (uint16_t) cfe_ticks;
+
+ /*
+ * Construct the ICMP header and data portion.
+ */
+
+ ebuf_append_u8(buf,8); /* echo message */
+ ebuf_append_u8(buf,0); /* code = 0 */
+ ebuf_append_u16_be(buf,0); /* empty checksum for now */
+ ebuf_append_u16_be(buf,id); /* packet ID */
+ ebuf_append_u16_be(buf,((uint16_t)seq)); /* sequence # */
+
+ for (idx = 0; idx < len; idx++) {
+ ebuf_append_u8(buf,((idx+0x40)&0xFF)); /* data */
+ }
+
+ /*
+ * Calculate and install the checksum
+ */
+
+ cksum = ~ip_chksum(0,icmphdr,ebuf_length(buf));
+ icmphdr[2] = (cksum >> 8) & 0xFF;
+ icmphdr[3] = (cksum & 0xFF);
+
+ /*
+ * Transmit the ICMP echo
+ */
+
+ icmp->icmp_maxreplies = 1; /* allow ICMP replies */
+ _ip_send(icmp->icmp_ipinfo,buf,dest,IPPROTO_ICMP);
+ buf = NULL;
+
+ /*
+ * Wait for a reply
+ */
+
+ TIMER_SET(timer,2*CFE_HZ);
+
+ while (!TIMER_EXPIRED(timer)) {
+
+ POLL();
+ buf = (ebuf_t *) q_deqnext(&(icmp->icmp_echoreplies));
+
+ /* If we get a packet, make sure it matches. */
+
+ if (buf) {
+ uint16_t rxid,rxseq;
+
+ cksum = ip_chksum(0,buf->eb_ptr,ebuf_length(buf));
+ if (cksum == 0xFFFF) {
+ ebuf_skip(buf,2);
+ ebuf_skip(buf,2); /* skip checksum */
+ ebuf_get_u16_be(buf,rxid);
+ ebuf_get_u16_be(buf,rxseq);
+
+ if ((id == rxid) && ((uint16_t) seq == rxseq)) {
+ result = 1;
+ break;
+ }
+ }
+ _ip_free(icmp->icmp_ipinfo,buf);
+ }
+ }
+
+ /*
+ * Don't accept any more replies.
+ */
+
+ icmp->icmp_maxreplies = 0; /* allow ICMP replies */
+
+ if (buf) _ip_free(icmp->icmp_ipinfo,buf);
+
+ return result;
+
+}
diff --git a/cfe/cfe/net/net_ip.c b/cfe/cfe/net/net_ip.c
new file mode 100755
index 0000000..86303e2
--- /dev/null
+++ b/cfe/cfe/net/net_ip.c
@@ -0,0 +1,722 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Internet Protocol File: net_ip.c
+ *
+ * This module implements the IP layer (RFC791)
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "net_ip.h"
+#include "net_ip_internal.h"
+
+#include "cfe_error.h"
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+static int ip_rx_callback(ebuf_t *buf,void *ref);
+
+/* *********************************************************************
+ * _ip_alloc(ipi)
+ *
+ * Allocate an ebuf and reserve space for the IP header in it.
+ *
+ * Input parameters:
+ * ipi - IP stack information
+ *
+ * Return value:
+ * ebuf - an ebuf, or NULL if there are none left
+ ********************************************************************* */
+
+ebuf_t *_ip_alloc(ip_info_t *ipi)
+{
+ ebuf_t *buf;
+
+ buf = eth_alloc(ipi->eth_info,ipi->ip_port);
+
+ if (buf == NULL) return buf;
+
+ ebuf_seek(buf,IPHDR_LENGTH);
+ ebuf_setlength(buf,0);
+
+ return buf;
+}
+
+
+/* *********************************************************************
+ * ip_chksum(initcksum,ptr,len)
+ *
+ * Do an IP checksum for the specified buffer. You can pass
+ * an initial checksum if you're continuing a previous checksum
+ * calculation, such as for UDP headers and pseudoheaders.
+ *
+ * Input parameters:
+ * initcksum - initial checksum (usually zero)
+ * ptr - pointer to buffer to checksum
+ * len - length of data in bytes
+ *
+ * Return value:
+ * checksum (16 bits)
+ ********************************************************************* */
+
+uint16_t ip_chksum(uint16_t initcksum,uint8_t *ptr,int len)
+{
+ unsigned int cksum;
+ int idx;
+ int odd;
+
+ cksum = (unsigned int) initcksum;
+
+ odd = len & 1;
+ len -= odd;
+
+ for (idx = 0; idx < len; idx += 2) {
+ cksum += ((unsigned long) ptr[idx] << 8) + ((unsigned long) ptr[idx+1]);
+ }
+
+ if (odd) { /* buffer is odd length */
+ cksum += ((unsigned long) ptr[idx] << 8);
+ }
+
+ /*
+ * Fold in the carries
+ */
+
+ while (cksum >> 16) {
+ cksum = (cksum & 0xFFFF) + (cksum >> 16);
+ }
+
+ return cksum;
+}
+
+
+/* *********************************************************************
+ * _ip_send(ipi,buf,destaddr,proto)
+ *
+ * Send an IP datagram. We only support non-fragmented datagrams
+ * at this time.
+ *
+ * Input parameters:
+ * ipi - IP stack information
+ * buf - an ebuf
+ * destaddr - destination IP address
+ * proto - IP protocol number
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _ip_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *destaddr,uint8_t proto)
+{
+ uint16_t cksum;
+ uint8_t masksrc[IP_ADDR_LEN];
+ uint8_t maskdest[IP_ADDR_LEN];
+ int pktlen;
+ uint8_t *ptr;
+
+ /* Move to the beginning of the IP hdeader */
+
+ ebuf_seek(buf,-IPHDR_LENGTH);
+
+ pktlen = ebuf_length(buf) + IPHDR_LENGTH;
+
+ ipi->ip_id++;
+
+ /* Insert the IP header */
+
+ ebuf_put_u8(buf,IPHDR_VER_4 | IPHDR_LEN_20);
+ ebuf_put_u8(buf,IPHDR_TOS_DEFAULT);
+ ebuf_put_u16_be(buf,pktlen);
+ ebuf_put_u16_be(buf,ipi->ip_id);
+ ebuf_put_u16_be(buf,0);
+ ebuf_put_u8(buf,IPHDR_TTL_DEFAULT);
+ ebuf_put_u8(buf,proto);
+ ebuf_put_u16_be(buf,0); /* checksum */
+ ebuf_put_bytes(buf,ipi->net_info.ip_addr,IP_ADDR_LEN);
+ ebuf_put_bytes(buf,destaddr,IP_ADDR_LEN);
+
+ /* adjust pointer and add in the header length */
+
+ ebuf_prepend(buf,IPHDR_LENGTH);
+
+ /* Checksum the header */
+
+ ptr = ebuf_ptr(buf);
+ cksum = ip_chksum(0,ptr,IPHDR_LENGTH);
+ cksum = ~cksum;
+ ptr[10] = (cksum >> 8) & 0xFF;
+ ptr[11] = (cksum >> 0) & 0xFF;
+
+ /*
+ * If sending to the IP broadcast address,
+ * send to local broadcast.
+ */
+
+ if (ip_addrisbcast(destaddr)) {
+ eth_send(buf,(uint8_t *) eth_broadcast);
+ eth_free(buf);
+ return 0;
+ }
+
+ /*
+ * If the mask has not been set, don't try to
+ * determine if we should use the gateway or not.
+ */
+
+ if (ip_addriszero(ipi->net_info.ip_netmask)) {
+ return _arp_lookup_and_send(ipi,buf,destaddr);
+ }
+
+ /*
+ * Compute (dest-addr & netmask) and (my-addr & netmask)
+ */
+
+ ip_mask(masksrc,destaddr,ipi->net_info.ip_netmask);
+ ip_mask(maskdest,ipi->net_info.ip_addr,ipi->net_info.ip_netmask);
+
+ /*
+ * if destination and my address are on the same subnet,
+ * send the packet directly. Otherwise, send via
+ * the gateway.
+ */
+
+ if (ip_compareaddr(masksrc,maskdest) == 0) {
+ return _arp_lookup_and_send(ipi,buf,destaddr);
+ }
+ else {
+ /* if no gw configured, drop packet */
+ if (ip_addriszero(ipi->net_info.ip_gateway)) {
+ eth_free(buf); /* silently drop */
+ return 0;
+ }
+ else {
+ return _arp_lookup_and_send(ipi,buf,ipi->net_info.ip_gateway);
+ }
+ }
+
+}
+
+
+/* *********************************************************************
+ * ip_rx_callback(buf,ref)
+ *
+ * Receive callback for IP packets. This routine is called
+ * by the Ethernet datalink. We look up a suitable protocol
+ * handler and pass the packet off.
+ *
+ * Input parameters:
+ * buf - ebuf we received
+ * ref - reference data from the ethernet datalink
+ *
+ * Return value:
+ * ETH_KEEP to keep the packet
+ * ETH_DROP to drop the packet
+ ********************************************************************* */
+
+static int ip_rx_callback(ebuf_t *buf,void *ref)
+{
+ ip_info_t *ipi = ref;
+ uint8_t tmp;
+ int hdrlen;
+ uint8_t *hdr;
+ uint16_t origchksum;
+ uint16_t calcchksum;
+ uint16_t length;
+ uint16_t tmp16;
+ uint8_t proto;
+ uint8_t srcip[IP_ADDR_LEN];
+ uint8_t dstip[IP_ADDR_LEN];
+ ip_protodisp_t *pdisp;
+ int res;
+ int idx;
+
+ hdr = ebuf_ptr(buf); /* save current posn */
+
+ ebuf_get_u8(buf,tmp); /* version and header length */
+
+ /*
+ * Check IP version
+ */
+
+ if ((tmp & 0xF0) != IPHDR_VER_4) {
+ goto drop; /* not IPV4 */
+ }
+ hdrlen = (tmp & 0x0F) * 4;
+
+ /*
+ * Check header size
+ */
+
+ if (hdrlen < IPHDR_LENGTH) {
+ goto drop; /* header < 20 bytes */
+ }
+
+ /*
+ * Check the checksum
+ */
+ origchksum = ((uint16_t) hdr[10] << 8) | (uint16_t) hdr[11];
+ hdr[10] = hdr[11] = 0;
+ calcchksum = ~ip_chksum(0,hdr,hdrlen);
+ if (calcchksum != origchksum) {
+ goto drop;
+ }
+
+ /*
+ * Okay, now go back and check other fields.
+ */
+
+ ebuf_skip(buf,1); /* skip TOS field */
+
+ ebuf_get_u16_be(buf,length);
+ ebuf_skip(buf,2); /* skip ID field */
+
+ ebuf_get_u16_be(buf,tmp16); /* get Fragment Offset field */
+
+ /*
+ * If the fragment offset field is nonzero, or the
+ * "more fragments" bit is set, then this is a packet
+ * fragment. Our trivial IP implementation does not
+ * deal with fragments, so drop the packets.
+ */
+ if ((tmp16 & (IPHDR_FRAGOFFSET | IPHDR_MOREFRAGMENTS)) != 0) {
+ goto drop; /* packet is fragmented */
+ }
+
+ ebuf_skip(buf,1); /* skip TTL */
+ ebuf_get_u8(buf,proto); /* get protocol */
+ ebuf_skip(buf,2); /* skip checksum */
+
+ ebuf_get_bytes(buf,srcip,IP_ADDR_LEN);
+ ebuf_get_bytes(buf,dstip,IP_ADDR_LEN);
+
+ ebuf_skip(buf,hdrlen-IPHDR_LENGTH); /* skip rest of header */
+
+ ebuf_setlength(buf,length-hdrlen); /* set length to just data portion */
+
+ /*
+ * If our address is not set, let anybody in. We need this to
+ * properly pass up DHCP replies that get forwarde through routers.
+ * Otherwise, only let in matching addresses or broadcasts.
+ */
+
+ if (!ip_addriszero(ipi->net_info.ip_addr)) {
+ if ((ip_compareaddr(dstip,ipi->net_info.ip_addr) != 0) &&
+ !(ip_addrisbcast(dstip))) {
+ goto drop; /* not for us */
+ }
+ }
+
+ /*
+ * ebuf's pointer now starts at beginning of protocol data
+ */
+
+ /*
+ * Find matching protocol dispatch
+ */
+
+ pdisp = ipi->ip_protocols;
+ res = ETH_DROP;
+ for (idx = 0; idx < IP_MAX_PROTOCOLS; idx++) {
+ if (pdisp->cb && (pdisp->protocol == proto)) {
+ res = (*(pdisp->cb))(pdisp->ref,buf,dstip,srcip);
+ break;
+ }
+ pdisp++;
+ }
+
+
+ return res;
+
+drop:
+ return ETH_DROP;
+}
+
+
+/* *********************************************************************
+ * _ip_init(eth)
+ *
+ * Initialize the IP layer, attaching it to an underlying Ethernet
+ * datalink interface.
+ *
+ * Input parameters:
+ * eth - Ethernet datalink information
+ *
+ * Return value:
+ * ip_info pointer (IP stack information) or NULL if error
+ ********************************************************************* */
+
+ip_info_t *_ip_init(ether_info_t *eth)
+{
+ ip_info_t *ipi;
+ int8_t ipproto[2];
+
+ /*
+ * Allocate IP stack info
+ */
+
+ ipi = KMALLOC(sizeof(ip_info_t),0);
+ if (ipi == NULL) return NULL;
+
+ memset(ipi,0,sizeof(ip_info_t));
+
+ ipi->eth_info = eth;
+
+ /*
+ * Initialize ARP
+ */
+
+ if (_arp_init(ipi) < 0) {
+ KFREE(ipi);
+ return NULL;
+ }
+
+ /*
+ * Open the Ethernet portal for IP packets
+ */
+
+ ipproto[0] = (PROTOSPACE_IP >> 8) & 0xFF; ipproto[1] = PROTOSPACE_IP & 0xFF;
+ ipi->ip_port = eth_open(ipi->eth_info,ETH_PTYPE_DIX,ipproto,ip_rx_callback,ipi);
+
+ if (ipi->ip_port < 0) {
+ _arp_uninit(ipi);
+ KFREE(ipi);
+ return NULL;
+ }
+
+ return ipi;
+}
+
+
+/* *********************************************************************
+ * _ip_uninit(ipi)
+ *
+ * Un-initialize the IP layer, freeing resources
+ *
+ * Input parameters:
+ * ipi - IP stack information
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _ip_uninit(ip_info_t *ipi)
+{
+ /*
+ * Close the IP portal
+ */
+
+ eth_close(ipi->eth_info,ipi->ip_port);
+
+ /*
+ * Turn off the ARP layer.
+ */
+
+ _arp_uninit(ipi);
+
+
+ /*
+ * free strings containing the domain and host names
+ */
+
+ if (ipi->net_info.ip_domain) {
+ KFREE(ipi->net_info.ip_domain);
+ }
+
+ if (ipi->net_info.ip_hostname) {
+ KFREE(ipi->net_info.ip_hostname);
+ }
+
+ /*
+ * Free the stack information
+ */
+
+ KFREE(ipi);
+}
+
+
+/* *********************************************************************
+ * _ip_timer_tick(ipi)
+ *
+ * Called once per second while the IP stack is active.
+ *
+ * Input parameters:
+ * ipi - ip stack information
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+
+void _ip_timer_tick(ip_info_t *ipi)
+{
+ _arp_timer_tick(ipi);
+}
+
+
+/* *********************************************************************
+ * _ip_free(ipi,buf)
+ *
+ * Free an ebuf allocated via _ip_alloc
+ *
+ * Input parameters:
+ * ipi - IP stack information
+ * buf - ebuf to free
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _ip_free(ip_info_t *ipi,ebuf_t *buf)
+{
+ eth_free(buf);
+}
+
+/* *********************************************************************
+ * _ip_getaddr(ipi,buf)
+ *
+ * Return our IP address (is this used?)
+ *
+ * Input parameters:
+ * ipi - IP stack information
+ * buf - pointer to 4-byte buffer to receive IP address
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _ip_getaddr(ip_info_t *ipi,uint8_t *buf)
+{
+ memcpy(buf,ipi->net_info.ip_addr,IP_ADDR_LEN);
+}
+
+/* *********************************************************************
+ * _ip_getparam(ipi,param)
+ *
+ * Return the value of an IP parameter (address, netmask, etc.).
+ * The return value may need to be coerced if it's not normally
+ * a uint8_t* pointer.
+ *
+ * Input parameters:
+ * ipi - IP stack information
+ * param - parameter number
+ *
+ * Return value:
+ * parameter value, or NULL if the parameter is invalid or
+ * not set.
+ ********************************************************************* */
+
+uint8_t *_ip_getparam(ip_info_t *ipinfo,int param)
+{
+ uint8_t *ret = NULL;
+
+ switch (param) {
+ case NET_IPADDR:
+ ret = ipinfo->net_info.ip_addr;
+ break;
+ case NET_NETMASK:
+ ret = ipinfo->net_info.ip_netmask;
+ break;
+ case NET_GATEWAY:
+ ret = ipinfo->net_info.ip_gateway;
+ break;
+ case NET_NAMESERVER:
+ ret = ipinfo->net_info.ip_nameserver;
+ break;
+ case NET_HWADDR:
+ ret = ipinfo->arp_hwaddr;
+ break;
+ case NET_DOMAIN:
+ ret = ipinfo->net_info.ip_domain;
+ break;
+ case NET_HOSTNAME:
+ ret = ipinfo->net_info.ip_hostname;
+ break;
+ case NET_SPEED:
+ return NULL;
+ break;
+ case NET_LOOPBACK:
+ return NULL;
+ break;
+ }
+
+ return ret;
+}
+
+/* *********************************************************************
+ * _ip_getparam(ipi,param,value)
+ *
+ * Set the value of an IP parameter (address, netmask, etc.).
+ * The value may need to be coerced if it's not normally
+ * a uint8_t* pointer.
+ *
+ * Input parameters:
+ * ipi - IP stack information
+ * param - parameter number
+ * value - parameter's new value
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int _ip_setparam(ip_info_t *ipinfo,int param,uint8_t *ptr)
+{
+ int res = -1;
+
+ switch (param) {
+ case NET_IPADDR:
+ memcpy(ipinfo->net_info.ip_addr,ptr,IP_ADDR_LEN);
+ _arp_send_gratuitous(ipinfo);
+ res = 0;
+ break;
+ case NET_NETMASK:
+ memcpy(ipinfo->net_info.ip_netmask,ptr,IP_ADDR_LEN);
+ res = 0;
+ break;
+ case NET_GATEWAY:
+ memcpy(ipinfo->net_info.ip_gateway,ptr,IP_ADDR_LEN);
+ res = 0;
+ break;
+ case NET_NAMESERVER:
+ memcpy(ipinfo->net_info.ip_nameserver,ptr,IP_ADDR_LEN);
+ res = 0;
+ break;
+ case NET_DOMAIN:
+ if (ipinfo->net_info.ip_domain) {
+ KFREE(ipinfo->net_info.ip_domain);
+ ipinfo->net_info.ip_domain = NULL;
+ }
+ if (ptr) ipinfo->net_info.ip_domain = (uint8_t*)strdup((char *) ptr);
+ break;
+ case NET_HOSTNAME:
+ if (ipinfo->net_info.ip_hostname) {
+ KFREE(ipinfo->net_info.ip_hostname);
+ ipinfo->net_info.ip_hostname = NULL;
+ }
+ if (ptr) ipinfo->net_info.ip_hostname = (uint8_t*)strdup((char *) ptr);
+ break;
+ case NET_HWADDR:
+ memcpy(ipinfo->arp_hwaddr,ptr,ENET_ADDR_LEN);
+ eth_sethwaddr(ipinfo->eth_info,ptr);
+ res = 0;
+ break;
+ case NET_SPEED:
+ res = eth_setspeed(ipinfo->eth_info,*(int *)ptr);
+ break;
+ case NET_LOOPBACK:
+ res = eth_setloopback(ipinfo->eth_info,*(int *)ptr);
+ break;
+ }
+
+ return res;
+}
+
+/* *********************************************************************
+ * _ip_register(ipinfo,proto,cb)
+ *
+ * Register a protocol handler with the IP layer. IP client
+ * protocols such as UDP, ICMP, etc. call this to register their
+ * callbacks.
+ *
+ * Input parameters:
+ * ipinfo - IP stack information
+ * proto - IP protocol number
+ * cb - callback routine to register
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _ip_register(ip_info_t *ipinfo,
+ int proto,
+ int (*cb)(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src),void *ref)
+{
+ int idx;
+
+ for (idx = 0; idx < IP_MAX_PROTOCOLS; idx++) {
+ if (ipinfo->ip_protocols[idx].cb == NULL) break;
+ }
+
+ if (idx == IP_MAX_PROTOCOLS) return;
+
+ ipinfo->ip_protocols[idx].protocol = (uint8_t) proto;
+ ipinfo->ip_protocols[idx].cb = cb;
+ ipinfo->ip_protocols[idx].ref = ref;
+}
+
+
+/* *********************************************************************
+ * _ip_deregister(ipinfo,proto)
+ *
+ * Deregister an IP protocol.
+ *
+ * Input parameters:
+ * ipinfo - IP stack information
+ * proto - protocol number
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _ip_deregister(ip_info_t *ipinfo,int proto)
+{
+ int idx;
+
+ for (idx = 0; idx < IP_MAX_PROTOCOLS; idx++) {
+ if (ipinfo->ip_protocols[idx].protocol == (uint8_t) proto) {
+ ipinfo->ip_protocols[idx].protocol = 0;
+ ipinfo->ip_protocols[idx].ref = 0;
+ ipinfo->ip_protocols[idx].cb = NULL;
+ }
+ }
+}
+
diff --git a/cfe/cfe/net/net_ip.h b/cfe/cfe/net/net_ip.h
new file mode 100755
index 0000000..7b1b4be
--- /dev/null
+++ b/cfe/cfe/net/net_ip.h
@@ -0,0 +1,159 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * IP Protocol Definitions File: net_ip.h
+ *
+ * This is the main include file for the CFE network stack.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+/* *********************************************************************
+ * Global info
+ ********************************************************************* */
+
+#ifndef IP_ADDR_LEN
+#define IP_ADDR_LEN 4
+#endif
+
+typedef struct ip_info_s ip_info_t;
+
+typedef struct net_info_s {
+ /* Configuration info for IP interface */
+ uint8_t ip_addr[IP_ADDR_LEN];
+ uint8_t ip_netmask[IP_ADDR_LEN];
+ uint8_t ip_gateway[IP_ADDR_LEN];
+ uint8_t ip_nameserver[IP_ADDR_LEN];
+ uint8_t *ip_domain;
+ uint8_t *ip_hostname;
+} net_info_t;
+
+/* *********************************************************************
+ * ARP Information
+ ********************************************************************* */
+
+int _arp_lookup_and_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *dest);
+void _arp_timer_tick(ip_info_t *ipi);
+int _arp_init(ip_info_t *ipi);
+void _arp_uninit(ip_info_t *ipi);
+void _arp_add(ip_info_t *ipi,uint8_t *destip,uint8_t *desthw);
+void _arp_send_gratuitous(ip_info_t *ipi);
+uint8_t *_arp_lookup(ip_info_t *ipi,uint8_t *destip);
+int _arp_enumerate(ip_info_t *ipi,int entrynum,uint8_t *ipaddr,uint8_t *hwaddr);
+int _arp_delete(ip_info_t *ipi,uint8_t *ipaddr);
+
+
+/* *********************************************************************
+ * IP protocol
+ ********************************************************************* */
+
+
+#define IPPROTO_TCP 6
+#define IPPROTO_UDP 17
+#define IPPROTO_ICMP 1
+
+int _ip_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *destaddr,uint8_t proto);
+ip_info_t *_ip_init(ether_info_t *);
+void _ip_timer_tick(ip_info_t *ipi);
+void _ip_uninit(ip_info_t *ipi);
+ebuf_t *_ip_alloc(ip_info_t *ipi);
+void _ip_free(ip_info_t *ipi,ebuf_t *buf);
+void _ip_getaddr(ip_info_t *ipi,uint8_t *buf);
+uint8_t *_ip_getparam(ip_info_t *ipinfo,int param);
+int _ip_setparam(ip_info_t *ipinfo,int param,uint8_t *ptr);
+uint16_t ip_chksum(uint16_t initcksum,uint8_t *ptr,int len);
+void _ip_deregister(ip_info_t *ipinfo,int proto);
+void _ip_register(ip_info_t *ipinfo,
+ int proto,
+ int (*cb)(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src),void *ref);
+
+
+#define ip_mask(dest,a,b) (dest)[0] = (a)[0] & (b)[0] ; \
+ (dest)[1] = (a)[1] & (b)[1] ; \
+ (dest)[2] = (a)[2] & (b)[2] ; \
+ (dest)[3] = (a)[3] & (b)[3]
+
+#define ip_compareaddr(a,b) memcmp(a,b,IP_ADDR_LEN)
+
+#define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0)
+#define ip_addrisbcast(a) ((a[0] == 0xFF) && (a[1] == 0xFF) && (a[2] == 0xFF) && (a[3] == 0xFF))
+
+#ifndef NET_IPADDR
+#define NET_IPADDR 0
+#define NET_NETMASK 1
+#define NET_GATEWAY 2
+#define NET_NAMESERVER 3
+#define NET_HWADDR 4
+#define NET_DOMAIN 5
+#define NET_HOSTNAME 6
+#define NET_SPEED 7
+#define NET_LOOPBACK 8
+#endif
+
+/* *********************************************************************
+ * UDP Protocol
+ ********************************************************************* */
+
+typedef struct udp_info_s udp_info_t;
+
+int _udp_socket(udp_info_t *info,uint16_t port);
+void _udp_close(udp_info_t *info,int s);
+int _udp_send(udp_info_t *info,int s,ebuf_t *buf,uint8_t *dest);
+udp_info_t *_udp_init(ip_info_t *ipi,void *ref);
+void _udp_uninit(udp_info_t *info);
+int _udp_bind(udp_info_t *info,int s,uint16_t port);
+int _udp_connect(udp_info_t *info,int s,uint16_t port);
+ebuf_t *_udp_recv(udp_info_t *info,int s);
+ebuf_t *_udp_alloc(udp_info_t *info);
+void _udp_free(udp_info_t *info,ebuf_t *buf);
+
+/* *********************************************************************
+ * ICMP protocol
+ ********************************************************************* */
+
+typedef struct icmp_info_s icmp_info_t;
+
+icmp_info_t *_icmp_init(ip_info_t *ipi);
+void _icmp_uninit(icmp_info_t *icmp);
+
+int _icmp_ping(icmp_info_t *icmp,uint8_t *ipaddr,int seq,int len);
+
+
diff --git a/cfe/cfe/net/net_ip_internal.h b/cfe/cfe/net/net_ip_internal.h
new file mode 100644
index 0000000..94401e2
--- /dev/null
+++ b/cfe/cfe/net/net_ip_internal.h
@@ -0,0 +1,128 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Internal IP structures File: net_ip_internal.h
+ *
+ * This module contains non-public IP stack constants,
+ * structures, and function prototypes.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+/* *********************************************************************
+ * ARP Protocol
+ ********************************************************************* */
+
+#define ARP_OPCODE_REQUEST 1
+#define ARP_OPCODE_REPLY 2
+
+#define ARP_HWADDRSPACE_ETHERNET 1
+
+#define PROTOSPACE_IP 0x0800
+#define PROTOSPACE_ARP 0x0806
+
+/* Foxconn add start by Cliff Wang, 03/23/2010 */
+#define PROTOSPACE_NMRP 0x0912
+/* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+#define ARP_KEEP_TIMER 60
+#define ARP_QUERY_TIMER 1
+#define ARP_QUERY_RETRIES 4
+#define ARP_TXWAIT_MAX 2
+#define ARP_TABLE_SIZE 8
+
+typedef enum { ae_unused, ae_arping, ae_established } arpstate_t;
+
+typedef struct arpentry_s {
+ arpstate_t ae_state;
+ int ae_usage;
+ int ae_timer;
+ int ae_retries;
+ int ae_permanent;
+ uint8_t ae_ipaddr[IP_ADDR_LEN];
+ uint8_t ae_ethaddr[ENET_ADDR_LEN];
+ queue_t ae_txqueue;
+} arpentry_t;
+
+
+/* *********************************************************************
+ * IP Protocol
+ ********************************************************************* */
+
+#define IPHDR_VER_4 0x40
+#define IPHDR_LEN_20 0x05
+#define IPHDR_LENGTH 20
+#define IPHDR_TOS_DEFAULT 0x00
+#define IPHDR_TTL_DEFAULT 100
+
+#define IPHDR_RESERVED 0x8000
+#define IPHDR_DONTFRAGMENT 0x4000
+#define IPHDR_MOREFRAGMENTS 0x2000
+#define IPHDR_FRAGOFFSET 0x01FFF
+
+typedef struct ip_protodisp_s {
+ uint8_t protocol;
+ int (*cb)(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src);
+ void *ref;
+} ip_protodisp_t;
+
+#define IP_MAX_PROTOCOLS 4
+
+
+struct ip_info_s {
+ net_info_t net_info;
+
+ /* Ethernet info */
+ ether_info_t *eth_info;
+
+ /* Info specific to IP */
+ uint16_t ip_id;
+ int ip_port;
+
+ /* IP protocol dispatch table */
+ ip_protodisp_t ip_protocols[IP_MAX_PROTOCOLS];
+
+ /* Info specific to ARP */
+ arpentry_t *arp_table;
+ int arp_port;
+ uint8_t arp_hwaddr[ENET_ADDR_LEN];
+};
+
+
diff --git a/cfe/cfe/net/net_nmrp.c b/cfe/cfe/net/net_nmrp.c
new file mode 100755
index 0000000..696d04d
--- /dev/null
+++ b/cfe/cfe/net/net_nmrp.c
@@ -0,0 +1,656 @@
+#include "bsp_config.h"
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_iocb.h"
+#include "cfe_devfuncs.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+
+#include "cfe_error.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "cfe_timer.h"
+
+#include "net_ip.h"
+#include "net_ip_internal.h"
+#include "net_api.h"
+
+#include "env_subr.h"
+
+#if CFG_TCP
+#include "net_tcp.h"
+#endif
+
+#include "ui_command.h"
+
+typedef struct net_ctx_s {
+ /* Global info */
+ int64_t timer;
+
+ /* device name */
+ char *devname;
+
+ /* Run-time info for IP interface */
+ ip_info_t *ipinfo;
+
+ /* Info for Ethernet interface */
+ ether_info_t *ethinfo;
+
+ /* Info specific to UDP */
+ udp_info_t *udpinfo;
+
+ /* Info specific to ICMP */
+ icmp_info_t *icmpinfo;
+
+#if CFG_TCP
+ /* Info specific to TCP */
+ tcp_info_t *tcpinfo;
+#endif
+} net_ctx_t;
+
+
+#pragma pack(1)
+
+typedef uint8_t BYTE;
+typedef uint16_t WORD;
+typedef uint32_t DWORD;
+
+/* NMRP timeouts */
+enum _nmrp_timeouts_ {
+ NMRP_TIMEOUT_REQ = 1/2, /* 0.5 sec */
+ NMRP_TIMEOUT_LISTEN = 3, /* 3 sec */
+ NMRP_TIMEOUT_ACTIVE = 60000, /* 1 minute */
+ NMRP_TIMEOUT_CLOSE = 6000, /* 6 sec */
+ NMRP_TIMEOUT_ADVERTISE = 500 /* 0.5 sec */
+};
+
+enum _nmrp_errors_ {
+ NMRP_ERR_NONE = 0,
+ NMRP_ERR_MSG_INVALID_LEN,
+ NMRP_ERR_MSG_TOO_LONG,
+ NMRP_ERR_MSG_TOO_MANY_OPT,
+ NMRP_ERR_MSG_UNKNOWN_OPT,
+ NMRP_ERR_MSG_INVALID_OPT,
+ NMRP_ERR_NO_BUF,
+ NMRP_ERR_GENERAL
+};
+
+/* NMRP codes */
+enum _nmrp_codes_ {
+ NMRP_CODE_ADVERTISE = 0x01,
+ NMRP_CODE_CONF_REQ = 0x02,
+ NMRP_CODE_CONF_ACK = 0x03,
+ NMRP_CODE_CLOSE_REQ = 0x04,
+ NMRP_CODE_CLOSE_ACK = 0x05,
+ NMRP_CODE_KEEP_ALIVE_REQ = 0x06,
+ NMRP_CODE_KEEP_ALIVE_ACK = 0x07,
+ NMRP_CODE_TFTP_UL_REQ = 0x10
+};
+
+/* NMRP option types */
+enum _nmrp_option_types_ {
+ NMRP_OPT_MAGIC_NO = 0x0001,
+ NMRP_OPT_DEV_IP = 0x0002,
+ NMRP_OPT_FW_UP = 0x0101
+};
+
+typedef enum {
+ NMRPC_L2_NO_ERROR = 0,
+ NMRPC_L2_TX_PKT_TOO_LONG,
+ NMRPC_L2_TX_ETHER_PREPEND_FAIL,
+ NMRPC_L2_TX_ERROR,
+ NMRPC_L2_GEN_ERR
+} NMRPC_L2_RET_CODE;
+
+/* NMRP REQ max retries */
+enum _nmrp_req_max_retries_ {
+ NMRP_MAX_RETRY_CONF = 5,
+ NMRP_MAX_RETRY_CLOSE = 9999,
+ NMRP_MAX_RETRY_TFTP_UL = 4
+};
+
+
+enum _nmrp_state_ {
+ NMRP_STATE_LISTEN = 0,
+ NMRP_STATE_CONFIGURE,
+ NMRP_STATE_TRANSFER,
+ NMRP_STATE_CLOSE
+};
+
+#define NMRP_MAX_OPT_PER_MSG (6)
+#define ETHER_NMRP (0x0912)
+
+#define NMRP_HDR_LEN (sizeof(NMRP_MSG) - sizeof(NMRP_OPT))
+#define NMRP_MIN_OPT_LEN (sizeof(NMRP_OPT) - 1)
+
+#define NMRP_MAGIC_NO "\x4E\x54\x47\x52"
+#define NMRP_MAGIC_NO_LEN (sizeof(NMRP_MAGIC_NO) - 1)
+
+typedef struct {
+ uint8_t destMAC[6];
+ uint8_t srcMAC[6];
+ uint16_t etherType;
+} ETHER_HDR;
+
+typedef struct {
+ uint16_t type;
+ uint16_t len;
+ uint8_t value;
+} NMRP_OPT;
+
+typedef struct {
+ uint16_t reserved;
+ uint8_t code;
+ uint8_t id;
+ uint16_t length;
+
+ NMRP_OPT opt;
+} NMRP_MSG;
+
+typedef struct {
+ ETHER_HDR etherHdr;
+ NMRP_MSG nmrpMsg;
+} ETHER_NMRP_PKT;
+
+typedef struct {
+ uint16_t type;
+ uint16_t len;
+
+ union {
+ uint8_t byteVal;
+ uint16_t wordVal;
+ uint32_t dwordVal;
+ const uint8_t *streamVal;
+ } value;
+} NMRP_PARSED_OPT;
+
+typedef struct {
+ uint8_t code;
+ uint8_t id;
+ uint16_t length;
+
+ int numOptions;
+ NMRP_PARSED_OPT options[NMRP_MAX_OPT_PER_MSG];
+} NMRP_PARSED_MSG;
+
+typedef struct {
+ int reqCode;
+ const char reqName[32], respName[32];
+
+ int (* RespParser) (const void *pkt, int pktLen, const BYTE *serverMac, void *userData);
+} NMRP_REQ_CUSTOM;
+
+typedef struct {
+
+ BYTE peerMac[6];
+ BYTE myMac[6];
+
+ DWORD peerIp;
+ DWORD myIp;
+ WORD ipId;
+
+ WORD peerPort;
+ WORD myPort;
+} NET_INFO;
+
+#pragma pack()
+
+#define MIN_ETHER_NMRP_LEN (sizeof(ETHER_HDR) + NMRP_HDR_LEN)
+
+#if 0
+#define HTONCS(constWord) ((((constWord) & 0xff00) >> 8) | (((constWord) & 0xff) << 8))
+#define NTOHCS(constWord) HTONCS(constWord)
+#define HTONCL(constDword) ((((constDword) & 0xff000000) >> 24) | (((constDword) & 0xff0000) >> 8) | (((constDword) & 0xff00) << 8) | (((constDword) & 0xff) << 24))
+#define NTOHCL(constDword) HTONCL(constDword)
+#endif
+
+#define HTONCS(constWord) constWord
+#define NTOHCS(constWord) constWord
+#define HTONCL(constDword) constDword
+#define NTOHCL(constDword) constDword
+/*
+#define IS_NMRP_PKT(etherNmrpPkt, pktLen, parsedNmrpMsg, sourceMAC) \
+ ((pktLen) > MIN_ETHER_NMRP_LEN && (etherNmrpPkt)->etherHdr.etherType == HTONCS(ETHER_NMRP) && \
+ ((sourceMAC) == NULL || memcmp((sourceMAC), (etherNmrpPkt)->etherHdr.srcMAC, 6) == 0) && \
+ NMRP_MsgParsing(&(etherNmrpPkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), (parsedNmrpMsg)) == NMRP_ERR_NONE)
+*/
+
+#define IS_NMRP_PKT(etherNmrpPkt, pktLen, parsedNmrpMsg, sourceMAC) \
+ ((pktLen) > MIN_ETHER_NMRP_LEN && (etherNmrpPkt)->etherHdr.etherType == HTONCS(ETHER_NMRP) && \
+ ((sourceMAC) == NULL || memcmp((sourceMAC), (etherNmrpPkt)->etherHdr.srcMAC, 6) == 0))
+
+static int nmrp_rx_callback(ebuf_t *buf,void *ref);
+int NMRP_MsgParsing(const NMRP_MSG *pkt, int pktLen, NMRP_PARSED_MSG *msg);
+NMRP_PARSED_OPT *NMRP_MsgGetOpt(NMRP_PARSED_MSG *msg, uint16_t optType);
+//int NMRPRequest( const BYTE *serverMac, const BYTE *clientMac, NMRP_REQ_CUSTOM *custom, void *userData);
+static int NMRPConfiguring( const BYTE *serverMac, const BYTE *clientMac, DWORD *ipAddr, DWORD *ipSubnetMask, int *fwUpgrade);
+static int NMRPConfAckParser(const void *pkt, int pktLen, const BYTE *serverMac, void *userData);
+//int NMRPTFTPWaiting(const NET_INFO *netInfo, DWORD *peerIp, WORD *peerPort, WORD *ipId);
+int NMRPTFTPWaiting(void);
+int NMRPKeepAlive(void);
+static int NMRPClosing(void);
+static int NMRPSend(NMRP_REQ_CUSTOM *custom);
+
+int nmrp_server_detected;
+int g_nmrp_config_acked;
+int g_nmrp_close_acked;
+//int g_Listening;
+int g_NMRP_State;
+extern net_ctx_t *netctx;
+
+NET_INFO g_NetInfo;
+//ebuf_t *g_nmrp_txbuf = NULL;
+int g_portal_number;
+NMRP_PARSED_MSG g_nmrpMsg;
+int g_tftp_upgrade_success;
+int g_nmrp_keepalive;//jenny add for fixed NMRP server timeout issue
+unsigned char g_received_packet[1600];
+
+int gpio_control(int gpio, int value);
+extern int32_t _getticks(void); /* return value of CP0 COUNT */
+static unsigned long seed = 1;
+
+void srand(unsigned long local_seed);
+unsigned long rand(void);
+int _start_nmrp(void);
+
+void srand(unsigned long local_seed)
+{
+ seed = local_seed;
+}
+
+unsigned long rand(void)
+{
+
+ long x, hi, lo, t;
+
+ x = seed;
+ hi = x / 127773;
+ lo = x % 127773;
+ t = 16807 * lo - 2836 * hi;
+ if (t <= 0) t += 0x7fffffff;
+ seed = t;
+ return t;
+}
+
+int _start_nmrp (void)
+{
+ uint8_t nmrpproto[2];
+
+ int ret = 0;
+ int ui_cmd_status;
+ int fwUpgrade;
+ int64_t timer;
+ DWORD ipSubnetMask;
+ char buf[512];
+ unsigned char *pIP, *pMask;
+
+ srand( (unsigned long)_getticks());
+
+ //net_init("eth0");
+ nmrpproto[0] = (PROTOSPACE_NMRP >> 8) & 0xFF;
+ nmrpproto[1] = (PROTOSPACE_NMRP & 0xFF);
+ g_tftp_upgrade_success = 0;
+ g_nmrp_keepalive = 0;//jenny add for timeout
+
+ g_portal_number = eth_open(netctx->ethinfo, ETH_PTYPE_DIX, (char*)nmrpproto, nmrp_rx_callback, NULL);
+ if(g_portal_number < 0)
+ {
+ ret = -1;
+ goto _clean_and_exit;
+ }
+
+ eth_gethwaddr(netctx->ethinfo, g_NetInfo.myMac);
+//_retry:
+ g_NMRP_State = NMRP_STATE_LISTEN;
+ nmrp_server_detected = 0;
+ TIMER_SET(timer, NMRP_TIMEOUT_LISTEN*CFE_HZ);
+ while (!TIMER_EXPIRED(timer))
+ {
+ POLL();
+ if(nmrp_server_detected)
+ {
+ xprintf ("find server.\n");
+ break;
+ }
+ }
+
+ if(!nmrp_server_detected)
+ {
+ ret = -1;
+ goto _clean_and_exit;
+ }
+
+ g_nmrp_config_acked = 0;
+
+ if (NMRPConfiguring( g_NetInfo.peerMac, g_NetInfo.myMac, &g_NetInfo.myIp, &ipSubnetMask, &fwUpgrade) == -1)
+ {
+ ret = -1;
+ goto _clean_and_exit;
+ }
+
+ pIP = (unsigned char *)&g_NetInfo.myIp;
+ pMask = (unsigned char *)&ipSubnetMask;
+
+ sprintf(buf, "ifconfig eth0 -addr=%u.%u.%u.%u -mask=%u.%u.%u.%u", *(pIP), *(pIP+1), *(pIP+2), *(pIP+3),
+ *(pMask), *(pMask+1), *(pMask+2), *(pMask+3) );
+ ui_docommand(buf);
+
+
+_retry_tftp:
+
+ NMRPTFTPWaiting();
+ //eth_close(netctx->ethinfo, g_portal_number);
+ //g_portal_number = 0;
+ //net_init("eth0");
+ ui_cmd_status = ui_docommand("tftpd nmrp");
+
+
+ sprintf(buf, "ifconfig eth0 -addr=%u.%u.%u.%u -mask=%u.%u.%u.%u", *(pIP), *(pIP+1), *(pIP+2), *(pIP+3),
+ *(pMask), *(pMask+1), *(pMask+2), *(pMask+3) );
+
+ ui_docommand(buf);
+
+ //net_init("eth0");
+ g_portal_number = eth_open(netctx->ethinfo, ETH_PTYPE_DIX, (char*)nmrpproto, nmrp_rx_callback, NULL);
+
+ if(ui_cmd_status != 0)
+ {
+ goto _retry_tftp;
+ }
+
+ g_nmrp_close_acked = 0;
+ /* Foxconn modified start, zacker,04/07/2008 */
+ /* ui_docommand("nvram erase"); */
+ // nvram_unset("restore_defaults");
+ // nvram_commit();
+ /* Foxconn modified end, zacker,04/07/2008 */
+
+ NMRPClosing();
+ g_tftp_upgrade_success = 1;
+ // gpio_control(7, 1); //turn off power led
+
+_clean_and_exit:
+
+ if(g_portal_number > 0)
+ eth_close(netctx->ethinfo, g_portal_number);
+
+ return ret;
+}
+
+extern void setPowerOnLedOn(void);
+static int nmrp_rx_callback(ebuf_t *buf,void *ref)
+{
+ int pktLen = 0;
+ NMRP_PARSED_MSG nmrpMsg;
+ const ETHER_NMRP_PKT *pkt;
+ unsigned char *p;
+
+ pkt = (const ETHER_NMRP_PKT *)buf->eb_data;
+ pktLen = buf->eb_length + sizeof(ETHER_HDR) - 4;
+
+ p=(unsigned char *)pkt;
+
+ if(g_NMRP_State == NMRP_STATE_LISTEN)
+ {
+ if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_ADVERTISE ) )
+ {
+ if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE)
+ {
+ if(NMRP_MsgGetOpt(&nmrpMsg, NMRP_OPT_MAGIC_NO) != NULL)
+ {
+ memcpy(g_NetInfo.peerMac, buf->eb_data+6, 6);
+ g_NMRP_State = NMRP_STATE_CONFIGURE;
+ nmrp_server_detected = 1;
+ setPowerOnLedOn(); /* Foxconn added for U12H154, turn on TEST LED */
+ }
+ }
+ }
+ }
+ else if(g_NMRP_State == NMRP_STATE_CONFIGURE)
+ {
+ if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_CONF_ACK ) )
+ {
+ memcpy(g_received_packet, pkt, pktLen);
+ pkt = (const ETHER_NMRP_PKT *)g_received_packet;
+ if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE)
+ {
+ if(NMRPConfAckParser(pkt, pktLen, g_NetInfo.peerMac, &nmrpMsg))
+ {
+ g_nmrpMsg = nmrpMsg;
+ g_nmrp_config_acked = 1;
+ g_NMRP_State = NMRP_STATE_TRANSFER;
+ }
+ }
+ }
+ }
+ else if(g_NMRP_State == NMRP_STATE_TRANSFER)
+ {
+ if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_CLOSE_ACK ) )
+ {
+ if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE)
+ {
+ g_NMRP_State =NMRP_STATE_CLOSE;
+ g_nmrp_close_acked = 1;
+ }
+ }
+ }
+
+ return ETH_DROP;
+}
+
+static int NMRP_OptValParsing(NMRP_PARSED_OPT *optParsed, const uint8_t *value)
+{
+ int retVal = NMRP_ERR_NONE;
+
+ switch (optParsed->type) {
+ case NMRP_OPT_MAGIC_NO: /* We require the lenght MUST be correct for the MAGIC-NO option */
+ if (optParsed->len != (NMRP_MIN_OPT_LEN + NMRP_MAGIC_NO_LEN) || memcmp(value, NMRP_MAGIC_NO, NMRP_MAGIC_NO_LEN))
+ {
+ retVal = NMRP_ERR_MSG_INVALID_OPT;
+ }
+ else
+ {
+ optParsed->value.streamVal = value;
+ }
+ break;
+
+ case NMRP_OPT_DEV_IP: /* save the value of IP in the byte stream format, the actual IP is streamVal[0].streamVal[1].streamVal[2].streamVal[3]. */
+ //if ( optParsed->len != (NMRP_MIN_OPT_LEN + 8) || !IsIPAddrValid(ntohl(*(DWORD *) value), ntohl(*(DWORD *) (value + 4))) )
+ if ( optParsed->len != (NMRP_MIN_OPT_LEN + 8) )
+ retVal = NMRP_ERR_MSG_INVALID_OPT;
+ else
+ optParsed->value.streamVal = value;
+ break;
+
+ case NMRP_OPT_FW_UP: /* don't check the length of FW-UP option for future compatibility */
+ break;
+
+ default:
+ retVal = NMRP_ERR_MSG_UNKNOWN_OPT;
+ break;
+ }
+
+ return retVal;
+}
+
+int NMRP_MsgParsing(const NMRP_MSG *pkt, int pktLen, NMRP_PARSED_MSG *msg)
+{
+ if (pktLen < NMRP_HDR_LEN)
+ return NMRP_ERR_MSG_INVALID_LEN;
+
+ msg->code = pkt->code;
+ msg->id = pkt->id;
+
+ if ((msg->length = NTOHCS(pkt->length)) <= pktLen && msg->length >= NMRP_HDR_LEN) {
+ int retVal;
+ uint16_t optLen;
+ NMRP_OPT *opt;
+ NMRP_PARSED_OPT *optParsed;
+
+ opt = (NMRP_OPT *)(((uint8_t *) pkt) + NMRP_HDR_LEN);
+ optParsed = msg->options;
+ msg->numOptions = 0;
+
+ /* use the length indicated in the NMRP header */
+ for (pktLen = msg->length - NMRP_HDR_LEN; pktLen >= NMRP_MIN_OPT_LEN; )
+ {
+ optParsed->type = NTOHCS(opt->type);
+ optParsed->len = optLen = NTOHCS(opt->len);
+
+ if (optParsed->len > pktLen)
+ return NMRP_ERR_MSG_INVALID_OPT;
+
+ if ((retVal = NMRP_OptValParsing(optParsed, &opt->value)) == NMRP_ERR_NONE)
+ {
+ optParsed++;
+
+ if (++msg->numOptions >= NMRP_MAX_OPT_PER_MSG)
+ return NMRP_ERR_MSG_TOO_MANY_OPT;
+ }
+ else if (retVal != NMRP_ERR_MSG_UNKNOWN_OPT)
+ {
+ return NMRP_ERR_MSG_INVALID_OPT;
+ }
+
+ pktLen -= optLen;
+ opt = (NMRP_OPT *)(((uint8_t *) opt) + optLen);
+ }
+ } /* end if the msg->length is larger than the received packet length */
+
+ return pktLen == 0 ? NMRP_ERR_NONE : NMRP_ERR_MSG_INVALID_LEN;
+}
+
+NMRP_PARSED_OPT *NMRP_MsgGetOpt(NMRP_PARSED_MSG *msg, uint16_t optType)
+{
+ NMRP_PARSED_OPT *opt, *optEnd;
+
+ optEnd = &msg->options[msg->numOptions];
+
+ for (opt = msg->options; opt != optEnd; opt++)
+ if (opt->type == optType)
+ break;
+
+ return msg->numOptions == 0 ? NULL : (opt == optEnd ? NULL : opt);
+}
+
+static int NMRPClosing(void)
+{
+ int ret, retries=0;
+ static NMRP_REQ_CUSTOM reqClose = { NMRP_CODE_CLOSE_REQ, "CLOSE-REQ", "CLOSE-ACK", NULL };
+
+ do {
+ ret = NMRPSend(&reqClose);
+ if( !ret)
+ {
+ cfe_sleep(CFE_HZ/2);
+ if(g_nmrp_close_acked)
+ {
+ break;
+ }
+ }
+ } while(++retries <= NMRP_MAX_RETRY_CLOSE);
+
+ return 0;
+}
+
+int NMRPTFTPWaiting(void)
+{
+ static NMRP_REQ_CUSTOM reqTftpUl = { NMRP_CODE_TFTP_UL_REQ, "TFTP-UL-REQ", "TFTP-WRQ", NULL };
+
+ return NMRPSend(&reqTftpUl);
+}
+
+/* Foxconn modify start by Jenny Zhao, 08/07/2008, for fixed timeout issue*/
+int NMRPKeepAlive(void)
+{
+ static NMRP_REQ_CUSTOM reqkeepalive = { NMRP_CODE_KEEP_ALIVE_REQ, "KEEPALIVE_REQ", "KEEPALIVE-ACK", NULL };
+
+ return NMRPSend(&reqkeepalive);
+}
+/* Foxconn modify end by Jenny Zhao, 08/07/2008*/
+
+static int NMRPConfAckParser(const void *pkt, int pktLen, const BYTE *serverMac, void *userData)
+{
+ NMRP_PARSED_MSG *nmrpMsg = (NMRP_PARSED_MSG *) userData;
+
+ return NMRP_MsgGetOpt(nmrpMsg, NMRP_OPT_DEV_IP) != NULL;
+ /*
+ return IS_NMRP_PKT((const ETHER_NMRP_PKT *)pkt, pktLen, nmrpMsg, serverMac) &&
+ nmrpMsg->code == NMRP_CODE_CONF_ACK &&
+ NMRP_MsgGetOpt(nmrpMsg, NMRP_OPT_DEV_IP) != NULL;
+ */
+}
+
+
+static int NMRPConfiguring( const BYTE *serverMac,
+ const BYTE *clientMac,
+ DWORD *ipAddr, DWORD *ipSubnetMask,
+ int *fwUpgrade)
+{
+ //int ret, retries=0;
+ int ret;
+ NMRP_PARSED_OPT *devIp;
+ static NMRP_REQ_CUSTOM reqConf = { NMRP_CODE_CONF_REQ, "CONF-REQ", "CONF-ACK", NMRPConfAckParser };
+
+ do {
+
+ ret = NMRPSend(&reqConf);
+ if( !ret)
+ {
+ cfe_sleep(CFE_HZ/2);
+ if(g_nmrp_config_acked)
+ {
+ break;
+ }
+ }
+
+ //}while(++retries <= NMRP_MAX_RETRY_CLOSE);
+ } while(1);
+
+ if(g_nmrp_config_acked)
+ {
+ devIp = NMRP_MsgGetOpt(&g_nmrpMsg, NMRP_OPT_DEV_IP);
+ *ipAddr = (* (DWORD *) devIp->value.streamVal);
+ *ipSubnetMask = (* (DWORD *) (devIp->value.streamVal + 4));
+ *fwUpgrade = NMRP_MsgGetOpt(&g_nmrpMsg, NMRP_OPT_FW_UP) != NULL;
+ return 0;
+ }
+ return -1;
+}
+
+static int NMRPSend(NMRP_REQ_CUSTOM *custom)
+{
+ ebuf_t *txbuf;
+ NMRP_MSG *msg;
+ unsigned long random_backoff;
+
+ txbuf = eth_alloc(netctx->ethinfo, g_portal_number);
+ if (!txbuf)
+ {
+ return -1;
+ }
+ msg = (NMRP_MSG *)(txbuf->eb_data + 14);
+ msg->reserved = 0;
+ msg->code = custom->reqCode;
+ msg->id = 0;
+ msg->length = HTONCS(NMRP_HDR_LEN); /* header only, no option */
+ txbuf->eb_length = NMRP_HDR_LEN;
+
+ random_backoff = rand();
+ random_backoff = random_backoff % 30;
+ xprintf("%s sent...Waiting for %s...\n", custom->reqName, custom->respName);
+ cfe_sleep(random_backoff);
+ eth_send(txbuf, (uint8_t *)g_NetInfo.peerMac);
+ eth_free(txbuf);
+
+ return 0;
+}
+
diff --git a/cfe/cfe/net/net_nmrp.h b/cfe/cfe/net/net_nmrp.h
new file mode 100755
index 0000000..052ff19
--- /dev/null
+++ b/cfe/cfe/net/net_nmrp.h
@@ -0,0 +1 @@
+int _start_nmrp(void);
diff --git a/cfe/cfe/net/net_tcp.c b/cfe/cfe/net/net_tcp.c
new file mode 100755
index 0000000..377c3c8
--- /dev/null
+++ b/cfe/cfe/net/net_tcp.c
@@ -0,0 +1,2215 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * TCP Protocol File: net_tcp.c
+ *
+ * This file contains a very simple TCP. The basic goals of this
+ * tcp are to be "good enough for firmware." We try to be
+ * correct in our protocol implementation, but not very fancy.
+ * In particular, we don't deal with out-of-order segments,
+ * we don't hesitate to copy data more then necessary, etc.
+ * We strive to implement important protocol features
+ * like slow start, nagle, etc., but even these things are
+ * subsetted and simplified as much as possible.
+ *
+ * Current "todo" list:
+ * slow start
+ * good testing of retransmissions,
+ * round-trip delay calculations
+ * Process received TCP options, particularly segment size
+ * Ignore urgent data (remove from datastream)
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "net_ip.h"
+#include "net_ip_internal.h"
+
+#include "cfe_timer.h"
+
+#include "cfe_error.h"
+
+#include "net_tcpbuf.h"
+#include "net_tcp_internal.h"
+#include "net_tcp.h"
+
+/* *********************************************************************
+ * Config
+ ********************************************************************* */
+
+//#define _TCP_DEBUG_
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+struct tcp_info_s {
+ void *ti_ref; /* ref data for IP layer */
+ ip_info_t *ti_ipinfo; /* IP layer handle */
+ cfe_timer_t ti_fasttimer; /* 200ms timer */
+ queue_t ti_tcblist; /* list of known TCBs */
+ int ti_onqueue; /* number of TCBs on queue */
+ uint32_t ti_iss; /* initial sequence number */
+ tcb_t *ti_ports[TCP_MAX_PORTS]; /* table of active sockets */
+};
+
+/* *********************************************************************
+ * Forward Declarations
+ ********************************************************************* */
+
+static void _tcp_protosend(tcp_info_t *ti,tcb_t *tcb);
+static int _tcp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr);
+static void _tcp_output(tcp_info_t *ti,tcb_t *tcb);
+static void _tcp_aborttcb(tcp_info_t *ti,tcb_t *tcb);
+static void _tcp_closetcb(tcp_info_t *ti,tcb_t *tcb);
+static tcb_t *_tcp_find_lclport(tcp_info_t *ti,uint16_t port);
+static void _tcp_freetcb(tcp_info_t *ti,tcb_t *tcb);
+static void _tcp_sendctlmsg(tcp_info_t *ti,tcb_t *tcb,uint16_t flags,int timeout);
+
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#ifdef _TCP_DEBUG_
+#define _tcp_setstate(tcb,state) (tcb)->tcb_state = (state); \
+ printf("tcp state = " #state "\n");
+#define DEBUGMSG(x) printf x
+#else
+#define _tcp_setstate(tcb,state) (tcb)->tcb_state = (state);
+#define DEBUGMSG(x)
+#endif
+
+#define _tcp_preparectlmsg(tcb,flags) (tcb)->tcb_txflags = (flags) ; \
+ (tcb)->tcb_flags |= TCB_FLG_SENDMSG;
+
+#define _tcp_canceltimers(tcb) \
+ TIMER_CLEAR((tcb)->tcb_timer_retx); \
+ TIMER_CLEAR((tcb)->tcb_timer_keep); \
+ TIMER_CLEAR((tcb)->tcb_timer_2msl); \
+ TIMER_CLEAR((tcb)->tcb_timer_pers);
+
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+#ifdef _TCP_DEBUG_
+int _tcp_dumpflags = 1;
+#else
+int _tcp_dumpflags = 0;
+#endif
+
+/* *********************************************************************
+ * _tcp_init(ipi,ref)
+ *
+ * Initialize the TCP module. We set up our data structures
+ * and register ourselves with the IP layer.
+ *
+ * Input parameters:
+ * ipi - IP information
+ * ref - will be passed back to IP as needed
+ *
+ * Return value:
+ * tcp_info_t structure, or NULL if problems
+ ********************************************************************* */
+
+tcp_info_t *_tcp_init(ip_info_t *ipi,void *ref)
+{
+ tcp_info_t *ti;
+ int idx;
+
+ ti = (tcp_info_t *) KMALLOC(sizeof(tcp_info_t),0);
+ if (!ti) return NULL;
+
+ ti->ti_ref = ref;
+ ti->ti_ipinfo = ipi;
+
+ /*
+ * Start the "fast" timer
+ */
+
+ TIMER_SET(ti->ti_fasttimer,TCP_FAST_TIMER);
+
+ /*
+ * Initialize the TCB list
+ */
+
+ q_init(&(ti->ti_tcblist));
+
+ for (idx = 0; idx < TCP_MAX_PORTS; idx++) {
+ ti->ti_ports[idx] = NULL;
+ }
+
+ ti->ti_onqueue = 0;
+
+ /*
+ * Set up the initial sequence number
+ */
+
+ extern int32_t _getticks(void); /* return value of CP0 COUNT */
+ ti->ti_iss = (uint32_t) _getticks(); /* XXX nonportable */
+
+ /*
+ * Register our protocol with IP
+ */
+
+ _ip_register(ipi,IPPROTO_TCP,_tcp_rx_callback,ti);
+
+ return ti;
+}
+
+
+/* *********************************************************************
+ * _tcp_uninit(info)
+ *
+ * De-initialize the TCP layer, unregistering from the IP layer.
+ *
+ * Input parameters:
+ * info - our tcp_info_t, from _tcp_init()
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _tcp_uninit(tcp_info_t *info)
+{
+ tcb_t *tcb;
+
+ /*
+ * Destroy all allocated TCBs, forcefully.
+ */
+
+ while (!q_isempty(&(info->ti_tcblist))) {
+ tcb = (tcb_t *) q_getfirst(&(info->ti_tcblist));
+ /* tcp_freetcb removes tcb from the queue */
+ _tcp_freetcb(info,tcb);
+ }
+
+ /*
+ * Deregister with IP
+ */
+
+ _ip_deregister(info->ti_ipinfo,IPPROTO_TCP);
+
+ /*
+ * Free up the info structure
+ */
+
+ KFREE(info);
+}
+
+
+/* *********************************************************************
+ * _tcp_freetcb(ti,tcb)
+ *
+ * Called when the TIME_WAIT timer expires, we use this to
+ * free up the TCB for good.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * tcb - tcb to free
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_freetcb(tcp_info_t *ti,tcb_t *tcb)
+{
+ /*
+ * Undo socket number
+ */
+
+ if (tcb->tcb_socknum >= 0) ti->ti_ports[tcb->tcb_socknum] = NULL;
+ tcb->tcb_socknum = -1;
+
+ /*
+ * Remove from queue
+ */
+
+ ti->ti_onqueue--;
+ q_dequeue(&(tcb->tcb_qb));
+
+ /*
+ * Free buffers (could probably be done in tcb_destroy)
+ */
+
+ tmb_free(&(tcb->tcb_txbuf));
+ tmb_free(&(tcb->tcb_rxbuf));
+
+ /*
+ * Free the TCB
+ */
+
+ KFREE(tcb);
+
+}
+
+/* *********************************************************************
+ * _tcp_socket(info)
+ *
+ * Create a new tcp socket (a new tcb structure is allocated
+ * and entered into the socket table)
+ *
+ * Input parameters:
+ * info - tcp information
+ *
+ * Return value:
+ * new socket number, or <0 if an error occured
+ ********************************************************************* */
+
+int _tcp_socket(tcp_info_t *info)
+{
+ int idx;
+ tcb_t *tcb;
+
+ /*
+ * Find an empty slot.
+ */
+
+ for (idx = 0; idx < TCP_MAX_PORTS; idx++) {
+ if (!info->ti_ports[idx]) break;
+ }
+
+ if (idx == TCP_MAX_PORTS) {
+ return CFE_ERR_NOHANDLES;
+ }
+
+ /*
+ * See if we can create another TCB
+ */
+
+ if (info->ti_onqueue >= TCP_MAX_TCBS) return CFE_ERR_NOMEM;
+
+ /*
+ * Allocate data structures
+ */
+
+ tcb = KMALLOC(sizeof(tcb_t),0);
+ if (!tcb) return CFE_ERR_NOMEM;
+
+ memset(tcb,0,sizeof(tcb_t));
+
+ if (tmb_alloc(&tcb->tcb_txbuf,TCP_BUF_SIZE) < 0) goto error;
+ if (tmb_alloc(&tcb->tcb_rxbuf,TCP_BUF_SIZE) < 0) goto error;
+
+ /*
+ * XXX Temp: our MTU is always 1400. We could/should
+ * XXX get this from the lower layer.
+ */
+
+ tcb->tcb_mtu = 1400;
+
+ /*
+ * Default socket flags
+ */
+
+ tcb->tcb_sockflags = TCPFLG_NBIO;
+
+ /*
+ * Set up initial state. Find an empty port number.
+ * note that the way we do this is pretty gruesome, but it will
+ * work for our small TCP, where the number of TCBs outstanding
+ * will be very small compared to the port number space.
+ *
+ * Try to look up the port number we want - if we find it, increment
+ * it and try again until we find an unused one.
+ * Stay away from ports 0..1023.
+ */
+
+ _tcp_setstate(tcb,TCPSTATE_CLOSED);
+ tcb->tcb_lclport = (uint16_t) (((uint16_t) cfe_ticks) + 1024);
+
+ while (_tcp_find_lclport(info,tcb->tcb_lclport) != NULL) {
+ tcb->tcb_lclport++;
+ if (tcb->tcb_lclport == 0) tcb->tcb_lclport = 1024;
+ }
+
+ /*
+ * Remember this socket in the table
+ */
+
+ info->ti_ports[idx] = tcb;
+ tcb->tcb_socknum = idx;
+
+ info->ti_onqueue++;
+ q_enqueue(&(info->ti_tcblist),&(tcb->tcb_qb));
+
+ return idx;
+
+error:
+ tmb_free(&(tcb->tcb_txbuf));
+ tmb_free(&(tcb->tcb_rxbuf));
+ KFREE(tcb);
+ return CFE_ERR_NOMEM;
+}
+
+
+/* *********************************************************************
+ * _tcp_connect(ti,s,dest,port)
+ *
+ * Connect a socket to a remote port.
+ *
+ * Input parameters:
+ * ti - TCP information
+ * s - socket number, allocated via _tcp_create
+ * dest - destination IP address
+ * port - destination port number
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_connect(tcp_info_t *ti,int s,uint8_t *dest,uint16_t port)
+{
+ tcb_t *tcb;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ memcpy(tcb->tcb_peeraddr,dest,IP_ADDR_LEN);
+ tcb->tcb_peerport = port;
+
+ tcb->tcb_rcvnext = 0;
+ tcb->tcb_rcvack = 0;
+
+ tcb->tcb_sendnext = ti->ti_iss;
+ tcb->tcb_sendunack = ti->ti_iss;
+ tcb->tcb_sendwindow = 0;
+
+ tmb_init(&tcb->tcb_txbuf);
+ tmb_init(&tcb->tcb_rxbuf);
+
+ TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER);
+ _tcp_setstate(tcb,TCPSTATE_SYN_SENT);
+
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_SYN,TCP_RETX_TIMER);
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * _tcp_close(ti,s)
+ *
+ * Disconnect a TCP socket nicely. Sends a FIN packet to get
+ * us into the disconnect state.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket number
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_close(tcp_info_t *ti,int s)
+{
+ tcb_t *tcb;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+#if defined(CONFIG_MIPS_BRCM)
+ /*
+ * Flush output data.
+ */
+
+ _tcp_output(ti,tcb);
+#endif
+
+ /*
+ * Reclaim this socket number for future use
+ */
+
+ ti->ti_ports[s] = NULL;
+ tcb->tcb_socknum = -1;
+
+ /*
+ * Decide what action to take based on current state
+ */
+
+ switch (tcb->tcb_state) {
+ case TCPSTATE_SYN_RECEIVED:
+ case TCPSTATE_ESTABLISHED:
+ /*
+ * Transmit the FIN/ACK and wait for a FIN/ACK.
+ *
+ * XXX probably want to wait till all unacked data is
+ * acked before sending the fin?? This would be sort
+ * of like the "linger" option
+ */
+ _tcp_setstate(tcb,TCPSTATE_FINWAIT_1);
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_FIN,TCP_RETX_TIMER);
+ break;
+
+ case TCPSTATE_CLOSED:
+ case TCPSTATE_LISTEN:
+ case TCPSTATE_SYN_SENT:
+ /*
+ * Disconnect during our attempt, or from some
+ * idle state that does not require sending anything.
+ * Go back to CLOSED.
+ */
+ _tcp_closetcb(ti,tcb);
+ _tcp_freetcb(ti,tcb);
+ break;
+
+ case TCPSTATE_CLOSE_WAIT:
+ _tcp_setstate(tcb,TCPSTATE_LAST_ACK);
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_FIN,TCP_RETX_TIMER);
+ break;
+
+ case TCPSTATE_TIME_WAIT:
+ case TCPSTATE_FINWAIT_1:
+ case TCPSTATE_FINWAIT_2:
+ case TCPSTATE_CLOSING:
+ case TCPSTATE_LAST_ACK:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+
+/* *********************************************************************
+ * _tcp_aborttcb(ti,tcb)
+ *
+ * Forcefully terminate a TCP connection. Sends an RST packet
+ * to nuke the other end. The socket is forced into the CLOSED
+ * state.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * tcb -tcb to abort
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_aborttcb(tcp_info_t *ti,tcb_t *tcb)
+{
+ DEBUGMSG(("tcp_abort from state %d\n",tcb->tcb_state));
+
+ /*
+ * Decide what action to take based on current state
+ * If we're in SYN_SENT, RECEIVED, ESTABLISHED, FINWAIT_1,
+ * FINWAIT_2, CLOSING, LAST_ACK, or CLOSE_WAIT we've sent
+ * some traffic on this TCB, so send an RST to kill off
+ * the remote TCB.
+ */
+
+ if (TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_ABORTSTATES)) {
+ /* Send RST with no timeout, don't retransmit it. */
+ _tcp_canceltimers(tcb);
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_RST,0);
+ }
+
+ /*
+ * No matter what, it's now CLOSED.
+ */
+
+ _tcp_closetcb(ti,tcb);
+
+}
+
+
+/* *********************************************************************
+ * _tcp_closetcb(ti,tcb)
+ *
+ * Close a TCB, switching the state to "closed" and resetting
+ * internal variables. The TCB is *not* freed.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * tcb - tcb to close
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_closetcb(tcp_info_t *ti,tcb_t *tcb)
+{
+ /*
+ * Set state to "closed" and reset timers
+ */
+
+ _tcp_setstate(tcb,TCPSTATE_CLOSED);
+ tcb->tcb_flags = 0;
+ _tcp_canceltimers(tcb);
+
+ /*
+ * Reinitialize the buffers to waste the stored send data and
+ * clear out any receive data
+ */
+
+ tmb_init(&tcb->tcb_txbuf);
+ tmb_init(&tcb->tcb_rxbuf);
+}
+
+/* *********************************************************************
+ * _tcp_send(ti,s,buf,len)
+ *
+ * Queue some data to be transmitted via a TCP socket
+ *
+ * Input parameters:
+ * ti - TCP information
+ * s - socket number
+ * buf - buffer of data to send
+ * len - size of buffer to send
+ *
+ * Return value:
+ * number of bytes queued
+ * <0 if an error occured
+ ********************************************************************* */
+
+int _tcp_send(tcp_info_t *ti,int s,uint8_t *buf,int len)
+{
+ tcb_t *tcb;
+ int retlen;
+ int curlen;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ /*
+ * State must be ESTABLISHED or CLOSE_WAIT. CLOSE_WAIT
+ * means we've received a fin, but we can still send in
+ * the outbound direction.
+ */
+
+ if (!TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_SEND_OK)) {
+ return CFE_ERR_NOTCONN;
+ }
+
+ /*
+ * Copy the user data into the transmit buffer.
+ */
+
+ curlen = tmb_curlen(&(tcb->tcb_txbuf));
+ retlen = tmb_copyin(&(tcb->tcb_txbuf),buf,len,TRUE);
+
+ /*
+ * Cause some output on the device.
+ */
+
+ /*
+ * Nagle: Call _tcp_output only if there is no outstanding
+ * unacknowledged data. The way our transmit buffer
+ * works, it only holds unacknowledged data, so this
+ * test is easy. It isn't really 100% correct to
+ * do it this way, but the effect is the same; we will
+ * not transmit tinygrams.
+ */
+
+ if ((curlen == 0) || (tcb->tcb_sockflags & TCPFLG_NODELAY)) {
+ _tcp_output(ti,tcb);
+ }
+
+ return retlen;
+}
+
+/* *********************************************************************
+ * _tcp_recv(ti,s,buf,len)
+ *
+ * Get buffered receive data from the TCP socket
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket number
+ * buf - pointer to receive buffer area
+ * len - size of receive buffer area
+ *
+ * Return value:
+ * number of bytes received
+ * <0 if an error occured
+ * ==0 if no data available (or tcp session is closed)
+ ********************************************************************* */
+
+int _tcp_recv(tcp_info_t *ti,int s,uint8_t *buf,int len)
+{
+ tcb_t *tcb;
+ int retlen;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ if (!TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_RECV_OK)) {
+ return CFE_ERR_NOTCONN;
+ }
+
+ retlen = tmb_copyout(&(tcb->tcb_rxbuf),buf,len,TRUE);
+
+ /*
+ * If we've drained all of the data out of the buffer
+ * send an ack. This isn't ideal, but it will
+ * prevent us from keeping the window closed.
+ */
+
+// if (retlen && (tmb_curlen(&(tcb->tcb_rxbuf)) == 0)) {
+// _tcp_preparectlmsg(tcb,TCPFLG_ACK);
+// _tcp_protosend(ti,tcb);
+// tcb->tcb_flags &= ~TCB_FLG_DLYACK;
+// }
+
+ return retlen;
+}
+
+
+/* *********************************************************************
+ * _tcp_bind(ti,s,port)
+ *
+ * "bind" a TCP socket to a particular port - this sets the
+ * outbound local (source) port number.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket number
+ * port - port number
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_bind(tcp_info_t *ti,int s,uint16_t port)
+{
+ tcb_t *tcb;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ /* XXX test state - must be in 'closed' */
+
+ if (_tcp_find_lclport(ti,port)) return CFE_ERR_ADDRINUSE;
+
+ tcb->tcb_lclport = port;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _tcp_setflags(ti,s,flags)
+ *
+ * Set per-socket flags.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket number
+ * flags - flags to set
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_setflags(tcp_info_t *ti,int s,unsigned int flags)
+{
+ tcb_t *tcb;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ tcb->tcb_sockflags = flags;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _tcp_getflags(ti,s,flags)
+ *
+ * Get per-socket flags.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket number
+ * flags - pointer to int to receive flags
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_getflags(tcp_info_t *ti,int s,unsigned int *flags)
+{
+ tcb_t *tcb;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ *flags = tcb->tcb_sockflags;
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * _tcp_peeraddr(ti,s,addr,port)
+ *
+ * Return the address of the computer on the other end of this
+ * connection.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket number
+ * addr - receives IP address of remote
+ * port - port number
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_peeraddr(tcp_info_t *ti,int s,uint8_t *addr,uint16_t *port)
+{
+ tcb_t *tcb;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ /*
+ * Test for any of the states where we believe the peeraddr in the tcb
+ * is valid.
+ */
+
+ if (!TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_PEERADDR_OK)) {
+ return CFE_ERR_NOTCONN;
+ }
+
+ if (addr) memcpy(addr,tcb->tcb_peeraddr,IP_ADDR_LEN);
+ if (port) *port = tcb->tcb_peerport;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _tcp_listen(ti,s,port)
+ *
+ * Set a socket for listening mode, allowing inbound connections
+ * to occur.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket nunber
+ * port - port number to listen for (implicit tcp_bind)
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_listen(tcp_info_t *ti,int s,uint16_t port)
+{
+ tcb_t *tcb;
+ queue_t *qb;
+
+ /*
+ * See if another TCB is listening to this port
+ */
+
+ for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
+ tcb = (tcb_t *) qb;
+
+ if ((tcb->tcb_lclport == port) &&
+ (tcb->tcb_state == TCPSTATE_LISTEN) &&
+ (tcb->tcb_peerport == 0)) return CFE_ERR_ADDRINUSE;
+
+ }
+
+ /*
+ * Otherwise, we're good to go.
+ */
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ tcb->tcb_lclport = port;
+ _tcp_setstate(tcb,TCPSTATE_LISTEN);
+
+ tcb->tcb_sendnext = 0;
+ tcb->tcb_sendunack = 0;
+ tcb->tcb_sendwindow = 0;
+ _tcp_canceltimers(tcb);
+
+ tcb->tcb_rcvnext = 0;
+ tcb->tcb_rcvack = 0;
+
+ tmb_init(&tcb->tcb_txbuf);
+ tmb_init(&tcb->tcb_rxbuf);
+
+ tcb->tcb_txflags = 0;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _tcp_status(ti,s,connflag,rxready,rxeof)
+ *
+ * Get status information about the TCP session
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket nunber
+ * connflag - points to an int to receive connection status
+ * (1=connected,0=not connected)
+ * rxready - number of bytes in receive queue
+ * rxeof - returns 1 if we've been FINed.
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_status(tcp_info_t *ti,int s,unsigned int *connflag,int *rxready,int *rxeof)
+{
+ tcb_t *tcb;
+ int rxlen;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ rxlen = tmb_curlen(&(tcb->tcb_rxbuf));
+
+ /*
+ * We consider the connection "connected" if it's established
+ * or it's in CLOSE_WAIT (FIN received) but we have not drained
+ * all of the receive data.
+ *
+ * Otherwise: If it's not in one of the connection establishment states,
+ * it's not connected.
+ */
+
+ if (connflag) {
+ if ((tcb->tcb_state == TCPSTATE_ESTABLISHED) ||
+ ((rxlen != 0) && (tcb->tcb_state == TCPSTATE_CLOSE_WAIT))) {
+ *connflag = TCPSTATUS_CONNECTED;
+ }
+ else if (TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_CONNINPROGRESS)) {
+ *connflag = TCPSTATUS_CONNECTING;
+ }
+ else {
+ *connflag = TCPSTATUS_NOTCONN;
+ }
+ }
+
+ if (rxready) {
+ *rxready = rxlen;
+ }
+
+ if (rxeof) {
+ *rxeof = 0;
+ if ((tcb->tcb_state == TCPSTATE_CLOSE_WAIT) ||
+ (tcb->tcb_state == TCPSTATE_LAST_ACK)) {
+ *rxeof = 1;
+ }
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _tcp_debug(ti,s,arg)
+ *
+ * Perform debug functions on a socket
+ *
+ * Input parameters:
+ * ti - tcp information
+ * s - socket number
+ * arg - argument
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _tcp_debug(tcp_info_t *ti,int s,int arg)
+{
+ tcb_t *tcb;
+
+ tcb = ti->ti_ports[s];
+ if (!tcb) return CFE_ERR_INV_PARAM;
+
+ printf("State=%d SendNext=%u SendUnack=%u ",
+ tcb->tcb_state,tcb->tcb_sendnext,tcb->tcb_sendunack);
+ printf("SendWin=%d Ack=%u Rxlen=%d\n",
+ tcb->tcb_sendwindow,
+ tcb->tcb_rcvack,tmb_curlen(&(tcb->tcb_rxbuf)));
+
+ return 0;
+}
+
+
+#ifdef _TCP_DEBUG_
+/* *********************************************************************
+ * _tcp_dumppktstate(label,flags,ack,seq,len)
+ *
+ * A debug function.
+ *
+ * Input parameters:
+ * label - printed before packet state
+ * flags - transmit flags for packet
+ * ack,seq,len - from the packet
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void _tcp_dumppktstate(char *label,uint16_t flags,
+ uint32_t ack,uint32_t seq,int len)
+{
+ printf("%s: ",label);
+ if (flags & TCPFLG_FIN) printf("FIN ");
+ if (flags & TCPFLG_SYN) printf("SYN ");
+ if (flags & TCPFLG_RST) printf("RST ");
+ if (flags & TCPFLG_PSH) printf("PSH ");
+ if (flags & TCPFLG_ACK) printf("ACK ");
+ if (flags & TCPFLG_URG) printf("URG ");
+ printf("Ack=%u Seq=%u Data=%d\n",ack,seq,len);
+}
+#endif
+
+
+/* *********************************************************************
+ * _tcp_output(ti,tcb)
+ *
+ * Try to perform some output on this TCB. If there is
+ * data to send and we can transmit it (i.e., the remote's
+ * receive window will allow it), segment the data from the
+ * buffer and transmit it, updating local state variables.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * tcb - the tcb to send data on
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_output(tcp_info_t *ti,tcb_t *tcb)
+{
+ ebuf_t *b;
+ int tcplen;
+ int window;
+ uint16_t flags;
+ uint8_t *cksumptr;
+ uint8_t *tcphdr;
+ uint16_t cksum;
+ int hdrlen;
+ uint8_t pseudoheader[12];
+ int offset;
+ uint32_t sendmax;
+ uint32_t windowmax;
+ uint32_t cwndmax;
+
+ /*
+ * sendmax is (one plus) the highest sequence number we have
+ * data for.
+ *
+ * windowmax is (one plus) the highest sequence number in the
+ * send window.
+ *
+ * cwndmax is (one plus) the highest sequence number in the
+ * congestion window.
+ */
+
+ sendmax = tcb->tcb_sendunack + tmb_curlen(&(tcb->tcb_txbuf));
+ windowmax = tcb->tcb_sendunack + tcb->tcb_sendwindow;
+ cwndmax = tcb->tcb_sendunack + 5*1400;
+
+ /*
+ * We'll send up to 'sendmax', 'cwndmax', or 'windowmax' bytes, whichever
+ * is sooner. Set 'sendmax' to the earliest sequence number.
+ */
+
+ if (TCPSEQ_GT(sendmax,windowmax)) sendmax = windowmax;
+ if (TCPSEQ_GT(sendmax,cwndmax)) sendmax = cwndmax;
+
+ /*
+ * The (receive) window is whatever it takes to fill the buffer.
+ */
+
+ window = tmb_remlen(&(tcb->tcb_rxbuf));
+ if (window > 65000) window = 65000;
+
+ /*
+ * Spit out packets until "sendnext" either catches up
+ * or exceeds the remote window
+ */
+
+ while (TCPSEQ_LT(tcb->tcb_sendnext,sendmax)) {
+
+ /*
+ * This is the offset into the transmit buffer to start with.
+ * Offset 0 in the transmit buffer corresponds to "send unack"
+ * received acks move this pointer.
+ */
+
+ offset = tcb->tcb_sendnext - tcb->tcb_sendunack;
+
+ /*
+ * Allocate a buffer and remember the pointer to where
+ * the header starts.
+ */
+
+ b = _ip_alloc(ti->ti_ipinfo);
+ if (!b) break;
+
+ tcphdr = ebuf_ptr(b) + ebuf_length(b);
+
+ flags = TCPFLG_ACK | TCPHDRFLG(TCP_HDR_LENGTH);
+ hdrlen = TCP_HDR_LENGTH;
+
+ /*
+ * Fill in the fields according to the RFC.
+ */
+
+ tcb->tcb_rcvack = tcb->tcb_rcvnext; /* Update our "most recent ack" */
+
+ ebuf_append_u16_be(b,tcb->tcb_lclport); /* Local and remote ports */
+ ebuf_append_u16_be(b,tcb->tcb_peerport);
+ ebuf_append_u32_be(b,tcb->tcb_sendnext); /* sequence and ack numbers */
+ ebuf_append_u32_be(b,tcb->tcb_rcvack);
+ ebuf_append_u16_be(b,flags); /* Flags */
+ ebuf_append_u16_be(b,window); /* Window size */
+ cksumptr = ebuf_ptr(b) + ebuf_length(b);
+ ebuf_append_u16_be(b,0); /* dummy checksum for calculation */
+ ebuf_append_u16_be(b,0); /* Urgent Pointer (not used) */
+
+ /*
+ * Append the data, copying pieces out of the transmit buffer
+ * without adjusting its pointers.
+ */
+
+ tcplen = tmb_copyout2(&(tcb->tcb_txbuf),
+ b->eb_ptr + b->eb_length,
+ offset,
+ tcb->tcb_mtu);
+
+ b->eb_length += tcplen;
+
+#ifdef _TCP_DEBUG_
+ if (_tcp_dumpflags) _tcp_dumppktstate("TX_DATA",flags,
+ tcb->tcb_sendnext,
+ tcb->tcb_rcvack,tcplen);
+#endif
+
+ /*
+ * Adjust the "send next" sequence number to account for what
+ * we're about to send.
+ */
+
+ tcb->tcb_sendnext += tcplen;
+
+
+ /*
+ * Build the pseudoheader, which is part of the checksum calculation
+ */
+
+ _ip_getaddr(ti->ti_ipinfo,&pseudoheader[0]);
+ memcpy(&pseudoheader[4],tcb->tcb_peeraddr,IP_ADDR_LEN);
+ pseudoheader[8] = 0;
+ pseudoheader[9] = IPPROTO_TCP;
+ pseudoheader[10] = ((tcplen+hdrlen) >> 8) & 0xFF;
+ pseudoheader[11] = ((tcplen+hdrlen) & 0xFF);
+
+ /*
+ * Checksum the packet and insert the checksum into the header
+ */
+
+ cksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader));
+ cksum = ip_chksum(cksum,tcphdr,tcplen + hdrlen);
+ cksum = ~cksum;
+ cksumptr[0] = (cksum >> 8) & 0xFF;
+ cksumptr[1] = (cksum & 0xFF);
+
+ /*
+ * Transmit the packet. The layer below us will free it.
+ */
+
+ _ip_send(ti->ti_ipinfo,b,tcb->tcb_peeraddr,IPPROTO_TCP);
+
+ /*
+ * Set the timer that we'll use to wait for an acknowledgement.
+ * If this timer goes off, we'll rewind "sendnext" back to
+ * "sendunack" and transmit stuff again.
+ */
+
+ TIMER_SET(tcb->tcb_timer_retx,TCP_RETX_TIMER);
+
+ /*
+ * We just sent an ack, so cancel the delayed ack timer.
+ */
+
+ tcb->tcb_flags &= ~TCB_FLG_DLYACK;
+
+ }
+
+}
+
+/* *********************************************************************
+ * _tcp_protosend(ti,tcb)
+ *
+ * Transmit "protocol messages" on the tcb. This is used for
+ * sending SYN, FIN, ACK, and other control packets.
+ *
+ * Input parameters:
+ * ti - tcp infomration
+ * tcb - tcb we're interested in
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_protosend(tcp_info_t *ti,tcb_t *tcb)
+{
+ ebuf_t *b;
+ int tcplen;
+ int window;
+ uint16_t flags;
+ uint8_t *cksumptr;
+ uint8_t *tcphdr;
+ uint16_t cksum;
+ int hdrlen;
+ uint8_t pseudoheader[12];
+
+ /*
+ * Allocate a buffer and remember the pointer to where
+ * the header starts.
+ */
+
+ b = _ip_alloc(ti->ti_ipinfo);
+ if (!b) return;
+
+ tcphdr = ebuf_ptr(b) + ebuf_length(b);
+
+ /*
+ * We're going to send something, so we can clear the flag.
+ * Also clear the delay-ack flag since everything's an ack.
+ */
+
+ tcb->tcb_flags &= ~(TCB_FLG_SENDMSG | TCB_FLG_DLYACK);
+
+ /*
+ * Build the TCP header
+ */
+
+ /* The flags are the current flags + the header length */
+ if (tcb->tcb_txflags & TCPFLG_SYN) {
+ flags = tcb->tcb_txflags | (TCPHDRFLG(TCP_HDR_LENGTH + 4));
+ hdrlen = TCP_HDR_LENGTH + 4;
+ }
+ else {
+ flags = tcb->tcb_txflags | (TCPHDRFLG(TCP_HDR_LENGTH));
+ hdrlen = TCP_HDR_LENGTH;
+ }
+
+
+#ifdef _TCP_DEBUG_
+ if (_tcp_dumpflags) _tcp_dumppktstate("TX_CTL",flags,
+ tcb->tcb_sendnext,
+ tcb->tcb_rcvack,0);
+#endif
+
+ /*
+ * The (receive) window is whatever it takes to fill the buffer.
+ */
+
+ window = tmb_remlen(&(tcb->tcb_rxbuf));
+ if (window > 65000) window = 65000;
+
+ /*
+ * Fill in the fields according to the RFC.
+ */
+
+ tcb->tcb_rcvack = tcb->tcb_rcvnext; /* update last tx ack */
+
+ ebuf_append_u16_be(b,tcb->tcb_lclport); /* Local and remote ports */
+ ebuf_append_u16_be(b,tcb->tcb_peerport);
+ ebuf_append_u32_be(b,tcb->tcb_sendnext); /* sequence and ack numbers */
+ ebuf_append_u32_be(b,tcb->tcb_rcvack);
+ ebuf_append_u16_be(b,flags); /* Flags */
+ ebuf_append_u16_be(b,window); /* Window size */
+ cksumptr = ebuf_ptr(b) + ebuf_length(b);
+ ebuf_append_u16_be(b,0); /* dummy checksum for calculation */
+ ebuf_append_u16_be(b,0); /* Urgent Pointer (not used) */
+
+ /*
+ * Append TCP options on SYN packet
+ */
+
+ if (flags & TCPFLG_SYN) {
+ ebuf_append_u16_be(b,TCP_MAX_SEG_OPT);
+ ebuf_append_u16_be(b,TCP_MAX_SEG_SIZE);
+ }
+
+ tcplen = 0; /* don't transmit data here */
+
+ /*
+ * SYN and FIN packets consume a sequence number, so
+ * increment the "sendnext" variable. If we need to retransmit
+ * these segments, we'll wind "sendnext" back to "sendunack"
+ *
+ * XXX: Can you send a SYN and FIN at the same time?
+ */
+
+ if (flags & (TCPFLG_SYN | TCPFLG_FIN)) tcb->tcb_sendnext++;
+
+ /*
+ * Build the pseudoheader, which is part of the checksum calculation
+ */
+
+ _ip_getaddr(ti->ti_ipinfo,&pseudoheader[0]);
+ memcpy(&pseudoheader[4],tcb->tcb_peeraddr,IP_ADDR_LEN);
+ pseudoheader[8] = 0;
+ pseudoheader[9] = IPPROTO_TCP;
+ pseudoheader[10] = ((tcplen+hdrlen) >> 8) & 0xFF;
+ pseudoheader[11] = ((tcplen+hdrlen) & 0xFF);
+
+ /*
+ * Checksum the packet and insert the checksum into the header
+ */
+
+ cksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader));
+ cksum = ip_chksum(cksum,tcphdr,tcplen + hdrlen);
+ cksum = ~cksum;
+ cksumptr[0] = (cksum >> 8) & 0xFF;
+ cksumptr[1] = (cksum & 0xFF);
+
+ /*
+ * Transmit the packet. The layer below us will free it.
+ */
+
+ _ip_send(ti->ti_ipinfo,b,tcb->tcb_peeraddr,IPPROTO_TCP);
+}
+
+/* *********************************************************************
+ * _tcp_sendreset(ti,dstipaddr,ack,srcport,dstport)
+ *
+ * Transmit "protocol messages" on the tcb. This is used for
+ * sending SYN, FIN, ACK, and other control packets.
+ *
+ * Input parameters:
+ * ti - tcp infomration
+ * tcb - tcb we're interested in
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_sendreset(tcp_info_t *ti,uint8_t *dstipaddr,uint32_t ack,
+ uint16_t srcport,uint16_t dstport)
+{
+ tcb_t tcb; /* fake TCB so we can use _tcp_protosend */
+
+ memset(&tcb,0,sizeof(tcb));
+ memcpy(tcb.tcb_peeraddr,dstipaddr,IP_ADDR_LEN);
+ tcb.tcb_peerport = dstport;
+ tcb.tcb_lclport = srcport;
+ tcb.tcb_txflags = TCPFLG_RST|TCPFLG_ACK;
+ tcb.tcb_rcvnext = ack;
+
+ _tcp_protosend(ti,&tcb);
+}
+
+
+/* *********************************************************************
+ * _tcp_sendctlmsg(ti,tcb,flags,timeout)
+ *
+ * Set up for and transmit a control message. This is usually
+ * called on a state transition where we need to send a control
+ * message like a SYN or FIN, with a timeout. We reset the
+ * retry counter, set the retransmit timer, and fire off the message
+ * right here.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * tcb - the tcb for this TCP session
+ * flags - packet flags (TCPFLG_xxx)
+ * timeout - timeout value , in ticks
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_sendctlmsg(tcp_info_t *ti,tcb_t *tcb,uint16_t flags,int timeout)
+{
+ tcb->tcb_txflags = flags;
+ tcb->tcb_retrycnt = 0;
+
+ if (timeout >= 0) {
+ if (timeout) {
+ TIMER_SET(tcb->tcb_timer_retx,timeout);
+ }
+ else {
+ TIMER_CLEAR(tcb->tcb_timer_retx);
+ }
+ }
+
+ _tcp_protosend(ti,tcb);
+}
+
+
+/* *********************************************************************
+ * _tcp_find_lclport(ti,port)
+ *
+ * Find the specified local port - mostly to see if it is
+ * already in use.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * port - local port
+ *
+ * Return value:
+ * tcb owning this port, or NULL if none found
+ ********************************************************************* */
+static tcb_t *_tcp_find_lclport(tcp_info_t *ti,uint16_t port)
+{
+ tcb_t *tcb = NULL;
+ queue_t *qb;
+
+ for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
+ tcb = (tcb_t *) qb;
+
+ if (tcb->tcb_lclport == port) return tcb;
+
+ }
+
+ return NULL;
+
+}
+
+/* *********************************************************************
+ * _tcp_find_tcb(ti,srcport,dstport,saddr)
+ *
+ * Locate the TCB in the active TCBs. This is used to match
+ * an inbound TCP packet to a TCB.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * srcport,dstport - source and dest ports from TCP header
+ * saddr - source IP address of sending host
+ *
+ * Return value:
+ * tcb pointer or NULL if no TCB was found
+ ********************************************************************* */
+
+static tcb_t *_tcp_find_tcb(tcp_info_t *ti,uint16_t srcport,uint16_t dstport,uint8_t *saddr)
+{
+ tcb_t *tcb = NULL;
+ queue_t *qb;
+
+ for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
+ tcb = (tcb_t *) qb;
+
+ /* Try active TCBs */
+ if ((tcb->tcb_peerport != 0) &&
+ (tcb->tcb_lclport == dstport) &&
+ (tcb->tcb_peerport == srcport) &&
+ (memcmp(saddr,tcb->tcb_peeraddr,IP_ADDR_LEN) == 0)) break;
+ }
+
+ /* Found it on our active list. */
+ if (qb != &(ti->ti_tcblist)) return tcb;
+
+ /* no dice, try listening ports */
+ for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
+ tcb = (tcb_t *) qb;
+
+ /* Try active TCBs */
+ if ((tcb->tcb_peerport == 0) &&
+ (tcb->tcb_lclport == dstport)) break;
+ }
+
+ /* Found it on our passive list. */
+ if (qb != &(ti->ti_tcblist)) return tcb;
+
+ return NULL;
+}
+
+/* *********************************************************************
+ * _tcp_procack(ti,tcb,ack,flags)
+ *
+ * Process a received acknowledgement.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * tcb - tcb for this tcb session
+ * ack - acknum from received packet
+ * flags - flags from received packet
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_procack(tcp_info_t *ti,tcb_t *tcb,uint32_t ack,uint16_t flags)
+{
+ int ackamt;
+ int unacklen;
+
+ /* This is the number of unacknowledged bytes we have */
+ unacklen = tmb_curlen(&(tcb->tcb_txbuf));
+
+ switch (tcb->tcb_state) {
+
+ case TCPSTATE_ESTABLISHED:
+ /*
+ * The ack is valid if it's in the range of
+ * unacknowledged data we're holding onto.
+ *
+ * sendunack < ack <= (sendunack+datalen)
+ *
+ * Do the first comparison as "<=" instead of just "<"
+ * so we can catch duplicate acks.
+ */
+
+ if (!(TCPSEQ_LEQ(tcb->tcb_sendunack,ack) &&
+ TCPSEQ_LEQ(ack,(tcb->tcb_sendunack+unacklen)))) {
+ DEBUGMSG(("Ack is out of range: %u\n",ack));
+ return;
+ }
+
+ /*
+ * Compute the # of bytes spanned by this ack
+ */
+
+ ackamt = TCPSEQ_DIFF(ack,tcb->tcb_sendunack);
+
+ /*
+ * If we actually acked something, adjust the tx buffer
+ * to remove the bytes covered by the ack, then update
+ * the 'next' sequence number so we'll start there next
+ * time.
+ */
+
+ if (ackamt > 0) {
+ tmb_adjust(&tcb->tcb_txbuf,ackamt);
+ tcb->tcb_txflags = TCPFLG_ACK;
+ tcb->tcb_sendunack = ack;
+ tcb->tcb_dup_ackcnt = 0; /* not a duplicate */
+ }
+ else {
+ tcb->tcb_dup_ackcnt++;
+ //DEBUGMSG(("Duplicate ack received\n"));
+ /*
+ * Duplicate ack received
+ * XXX This is where we'd be doing stuff for
+ * XXX slow-start, fast retransmit, etc.
+ */
+ }
+
+ /*
+ * If we're all caught up, we can cancel the
+ * retransmit timer. Otherwise, try to do
+ * some output on the interface. This will
+ * reset the retransmit timer if we did anything.
+ */
+
+ if (tmb_curlen(&(tcb->tcb_txbuf)) != 0) {
+ tcb->tcb_flags |= TCB_FLG_OUTPUT;
+ }
+ else {
+ TIMER_CLEAR(tcb->tcb_timer_retx);
+ }
+
+ break;
+
+ case TCPSTATE_FINWAIT_1:
+ ackamt = TCPSEQ_DIFF(ack,tcb->tcb_sendunack);
+ if (ackamt == 1) {
+ tcb->tcb_sendunack = ack;
+ if (flags & TCPFLG_FIN) {
+ _tcp_setstate(tcb,TCPSTATE_TIME_WAIT);
+ _tcp_canceltimers(tcb);
+ _tcp_preparectlmsg(tcb,TCPFLG_ACK);
+ TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER);
+ }
+ else {
+ _tcp_setstate(tcb,TCPSTATE_FINWAIT_2);
+ }
+ }
+ break;
+
+ }
+}
+
+/* *********************************************************************
+ * _tcp_procdata(ti,tcb,seqnum,flags,buf)
+ *
+ * Process data in a received TCP packet - we'll put the
+ * data into the receive ring buffer, process the seqnum
+ * field, and prepare to send an ack.
+ *
+ * Input parameters:
+ * ti - tcp information
+ * tcb - tcb describing TCP session
+ * seqnum,flags - from the header of the received TCP packet
+ * buf - ebuf contianing data
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _tcp_procdata(tcp_info_t *ti,tcb_t *tcb,uint32_t seqnum,
+ uint16_t flags,ebuf_t *buf)
+{
+ int datalen;
+ uint8_t *bp;
+ int rxwin,rwin;
+ uint32_t endseqnum;
+ uint32_t endrxwindow;
+ int reallen;
+
+ /*
+ * Figure out how much we're going to take. This should not
+ * exceed our buffer size because we advertised a window
+ * only big enough to fill our buffer.
+ */
+
+ bp = ebuf_ptr(buf); /* pointer to TCP data */
+ datalen = ebuf_remlen(buf); /* Size of TCP data */
+
+ /*
+ * If there's no data in the buffer, we can skip the data-related
+ * stuff and check for a possible FIN.
+ */
+
+ if (datalen != 0) {
+
+ /*
+ * Figure out if the data fits within the window. We don't deal
+ * with out-of-order segments, so the test is relatively
+ * simple: The received segment must contain (or match)
+ * the sequence number from "rcvnext" to the end of the receive
+ * window.
+ *
+ * Therefore: seqnum <= rcvnext < seqnum+datalen
+ */
+
+ rxwin = tmb_remlen(&(tcb->tcb_rxbuf)); /* receive window size */
+ endseqnum = (seqnum + datalen); /* seq # of end of segment */
+ endrxwindow = tcb->tcb_rcvack + rxwin; /* end of receive window */
+
+ /*
+ * The segment might include data outside the receive window
+ * (it's not supposed to, but it can). Crop the 'endseqnum'
+ * value at the rx window if necessary. Keep the earlier seqnum.
+ */
+//
+// XXX This is just plain broken - "endrxwindow" is the wrong thing to test.
+// if (TCPSEQ_LT(endrxwindow,endseqnum)) {
+// endseqnum = endrxwindow;
+// }
+
+ /*
+ * Test to see if the data is in sequence.
+ */
+
+ rwin = (TCPSEQ_LEQ(seqnum,tcb->tcb_rcvnext) &&
+ TCPSEQ_LT(tcb->tcb_rcvnext,endseqnum));
+
+ if (!rwin) {
+ DEBUGMSG(("Dropping out-of-order packet %u %u %u\n",seqnum,
+ tcb->tcb_rcvnext,endseqnum));
+ return;
+ }
+
+ /*
+ * The actual amount of new data is the distance from
+ * the "rcvnext" pointer to the end sequence number.
+ * typically this will be the entire packet, but we
+ * handle the case of receiving a partial duplicate segment.
+ * Do this by shortening the data length we're going to
+ * copy and adjusting the buffer pointer to point past the
+ * duplicate data. Normally this won't do anything.
+ */
+
+ reallen = endseqnum - tcb->tcb_rcvnext;
+ bp += (tcb->tcb_rcvnext - seqnum);
+
+ if (reallen != datalen) {
+ DEBUGMSG(("newdata(%d) does not match real length(%d)\n",reallen,datalen));
+ }
+
+ if (reallen > 0) {
+
+ /*
+ * Copy the data into the receive buffer. In the
+ * unlikely event that it doesn't fit, update the
+ * length so we'll only ack what we took.
+ */
+
+ reallen = tmb_copyin(&(tcb->tcb_rxbuf),bp,reallen,TRUE);
+
+ tcb->tcb_rcvnext += reallen;
+
+ /*
+ * Set the delayed-ack flag. If it's already set,
+ * then we've already received some data without acking
+ * it, so send the ack now, to encourage us to
+ * ack every other segment at least.
+ */
+
+ if (tcb->tcb_flags & TCB_FLG_DLYACK) {
+ _tcp_preparectlmsg(tcb,TCPFLG_ACK);
+ }
+ else {
+ tcb->tcb_flags |= TCB_FLG_DLYACK;
+ }
+ }
+ }
+
+ /*
+ * Handle the case of data in a FIN packet.
+ */
+
+ if (flags & TCPFLG_FIN) {
+
+ tcb->tcb_rcvnext++; /* Consume the FIN */
+
+ DEBUGMSG(("FIN rcvd in %d ack %u\n",tcb->tcb_state,tcb->tcb_rcvnext));
+
+ switch (tcb->tcb_state) {
+ case TCPSTATE_ESTABLISHED:
+
+ /*
+ * If a FIN is received in the ESTABLISHED state,
+ * go to CLOSE_WAIT.
+ */
+
+ tcb->tcb_flags &= ~TCB_FLG_DLYACK;
+ _tcp_setstate(tcb,TCPSTATE_CLOSE_WAIT);
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,-1);
+ break;
+
+ case TCPSTATE_FINWAIT_1:
+
+ /*
+ * Two choices: Either we got a FIN or a FIN ACK.
+ * In either case, send an ack. The difference
+ * is what state we end up in.
+ */
+
+ if (flags & TCPFLG_ACK) {
+ /* Received: FIN ACK - go directly to TIME_WAIT */
+ _tcp_canceltimers(tcb);
+ _tcp_preparectlmsg(tcb,TCPFLG_ACK);
+ _tcp_setstate(tcb,TCPSTATE_TIME_WAIT);
+#if defined(CONFIG_MIPS_BRCM)
+ TIMER_SET(tcb->tcb_timer_2msl,TCP_SEND_TIMER);
+#else
+ TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER);
+#endif
+ }
+ else {
+ /* Received: FIN - simultaneous close, go to CLOSING */
+ _tcp_setstate(tcb,TCPSTATE_CLOSING);
+ _tcp_preparectlmsg(tcb,TCPFLG_ACK);
+ }
+ break;
+
+ case TCPSTATE_FINWAIT_2:
+
+ /*
+ * Received a FIN in FINWAIT_2 - just transmit
+ * an ack and go to TIME_WAIT.
+ */
+
+ _tcp_canceltimers(tcb);
+ _tcp_preparectlmsg(tcb,TCPFLG_ACK);
+ _tcp_setstate(tcb,TCPSTATE_TIME_WAIT);
+ TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER);
+ break;
+ }
+ }
+
+}
+
+/* *********************************************************************
+ * _tcp_rx_callback(ref,buf,destaddr,srcaddr)
+ *
+ * The IP layer calls this routine when a TCP packet is received.
+ * We dispatch the packet to appropriate handlers from here.
+ *
+ * Input parameters:
+ * ref - our tcp information (held by the ip stack for us)
+ * buf - the ebuf that we received
+ * destaddr,srcaddr - destination and source IP addresses
+ *
+ * Return value:
+ * ETH_DROP or ETH_KEEP, depending if we keep the packet or not
+ ********************************************************************* */
+
+static int _tcp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr)
+{
+ uint8_t pseudoheader[12];
+ int tcplen;
+ uint16_t calccksum;
+ uint16_t origcksum;
+ uint8_t *tcphdr;
+ uint16_t srcport;
+ uint16_t dstport;
+ uint32_t seqnum;
+ uint32_t acknum;
+ uint16_t window;
+ uint16_t flags;
+ tcb_t *tcb;
+ tcp_info_t *ti = (tcp_info_t *) ref;
+
+ /*
+ * get a pointer to the TCP header
+ */
+
+ tcplen = ebuf_length(buf);
+ tcphdr = ebuf_ptr(buf);
+
+ /*
+ * construct the pseudoheader for the cksum calculation
+ */
+
+ memcpy(&pseudoheader[0],srcaddr,IP_ADDR_LEN);
+ memcpy(&pseudoheader[4],destaddr,IP_ADDR_LEN);
+ pseudoheader[8] = 0;
+ pseudoheader[9] = IPPROTO_TCP;
+ pseudoheader[10] = (tcplen >> 8) & 0xFF;
+ pseudoheader[11] = (tcplen & 0xFF);
+
+ origcksum = ((uint16_t) tcphdr[16] << 8) | (uint16_t) tcphdr[17];
+ tcphdr[16] = tcphdr[17] = 0;
+
+ calccksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader));
+ calccksum = ip_chksum(calccksum,tcphdr,tcplen);
+ calccksum = ~calccksum;
+
+ if (calccksum != origcksum) {
+ return ETH_DROP;
+ }
+
+ /* Read the other TCP header fields from the packet */
+
+ ebuf_get_u16_be(buf,srcport);
+ ebuf_get_u16_be(buf,dstport);
+ ebuf_get_u32_be(buf,seqnum);
+ ebuf_get_u32_be(buf,acknum);
+ ebuf_get_u16_be(buf,flags);
+ ebuf_get_u16_be(buf,window);
+ ebuf_skip(buf,4); /* skip checksum and urgent pointer */
+
+ /* Skip options in header */
+ if (TCPHDRSIZE(flags) < TCP_HDR_LENGTH) {
+ return ETH_DROP;
+ }
+ ebuf_skip(buf,(TCPHDRSIZE(flags) - TCP_HDR_LENGTH));
+
+ /*
+ * Okay, start looking for a matching TCB. If no matching TCB,
+ * send a RST.
+ * XXX Extra credit: rate-limit the RSTs.
+ */
+
+ tcb = _tcp_find_tcb(ti,srcport,dstport,srcaddr);
+ if (!tcb) {
+ DEBUGMSG(("Invalid TCB from %I, srcport=%u dstport=%u\n",srcaddr,srcport,dstport));
+ _tcp_sendreset(ti,srcaddr,seqnum+1,dstport,srcport);
+ return ETH_DROP; /* drop packet if no matching port */
+ }
+
+ /*
+ * Any activity on a TCB is enough to reset the keepalive timer
+ */
+
+ if (TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_RESETKEEPALIVE)) {
+ TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER);
+ }
+
+ /*
+ * Some debugging
+ */
+
+#ifdef _TCP_DEBUG_
+ if (_tcp_dumpflags) _tcp_dumppktstate("Received",flags,
+ acknum,seqnum,ebuf_length(buf));
+#endif
+
+ /*
+ * If someone tries to reset us, just kill off the port.
+ * (except: if we were in SYN_RECEIVED, go back to LISTEN)
+ */
+
+ if (flags & TCPFLG_RST) {
+ if (tcb->tcb_state == TCPSTATE_SYN_RECEIVED) {
+ _tcp_setstate(tcb,TCPSTATE_LISTEN);
+ }
+ else {
+ _tcp_closetcb(ti,tcb);
+ }
+ return ETH_DROP;
+ }
+
+ /*
+ * Remember the window we got.
+ */
+
+ tcb->tcb_sendwindow = window;
+
+ /*
+ * What we do here depends on the current connection state
+ * Most of this is just from the connection state diagram we've
+ * all see way too often.
+ */
+
+ switch ( tcb->tcb_state ) {
+
+ case TCPSTATE_LISTEN:
+ if (flags & TCPFLG_SYN) {
+ tcb->tcb_rcvnext = seqnum + 1;
+ tcb->tcb_peerport = srcport;
+ memcpy(tcb->tcb_peeraddr,srcaddr,IP_ADDR_LEN);
+ TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER);
+ _tcp_setstate(tcb,TCPSTATE_SYN_RECEIVED);
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_SYN | TCPFLG_ACK,TCP_RETX_TIMER);
+ }
+ return ETH_DROP; /* we ignore everything else */
+ break;
+
+ case TCPSTATE_SYN_SENT:
+
+ /*
+ * The only packets we pay attention to in SYN_SENT
+ * are packets with SYN flags.
+ */
+ if (flags & TCPFLG_SYN) {
+
+ /*
+ * Two choices: Either we got a SYN ACK (normal)
+ * or just a SYN (simultaneous open, rare)
+ */
+
+ if ((flags & TCPFLG_ACK) &&
+ (acknum == (tcb->tcb_sendunack + 1))) {
+ /*
+ * If we received a SYN ACK and the acknum
+ * matches our SYN's seqnum + 1, we want
+ * to transition from SYN_SENT to ESTABLISHED.
+ */
+ TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER);
+ _tcp_setstate(tcb,TCPSTATE_ESTABLISHED);
+ tcb->tcb_sendunack = acknum;
+ tcb->tcb_sendnext = tcb->tcb_sendunack;
+ tcb->tcb_rcvnext = seqnum + 1;
+ /*
+ * Send an ack, but don't bother with the timer.
+ * If the remote does not get our ack, it will
+ * retransmit the SYN ACK and we'll ack it from
+ * the "ESTABLISHED" state.
+ * Actually, is that really true?
+ */
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,0);
+ }
+ else {
+ DEBUGMSG(("Simultaneous open: SYN received in SYN_SENT state\n"));
+ tcb->tcb_rcvnext++; /* consume the SYN */
+ _tcp_setstate(tcb,TCPSTATE_SYN_RECEIVED);
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_SYN|TCPFLG_ACK,TCP_RETX_TIMER);
+ }
+ }
+
+ return ETH_DROP;
+ break;
+
+ case TCPSTATE_SYN_RECEIVED:
+ /*
+ * If we've received a SYN and someone sends us a SYN,
+ * and the sequence numbers don't match,
+ * send back a SYN ACK. (this doesn't sound right,
+ * does it? It's sort of what we do from LISTEN)
+ */
+
+ if (flags & TCPFLG_SYN) {
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_SYN | TCPFLG_ACK,TCP_RETX_TIMER);
+ }
+
+ /*
+ * If we got an ack and the acknum is correct,
+ * switch the state to 'ESTABLISHED' and cancel
+ * the timer. We're ready to rock.
+ */
+
+ if ((flags & TCPFLG_ACK) &&
+ (acknum == (tcb->tcb_sendunack + 1))) {
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,0);
+ tcb->tcb_sendunack = acknum;
+ tcb->tcb_sendnext = tcb->tcb_sendunack;
+ TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER);
+ _tcp_setstate(tcb,TCPSTATE_ESTABLISHED);
+ }
+
+ return ETH_DROP;
+ break;
+
+ case TCPSTATE_ESTABLISHED:
+ case TCPSTATE_FINWAIT_1:
+ case TCPSTATE_FINWAIT_2:
+
+ /*
+ * ESTABLISHED, FINWAIT_1, and FINWAIT_2 can all
+ * carry data. Process the data here. If the
+ * segment also contains a FIN, these routines
+ * will handle that.
+ */
+
+ if (flags & TCPFLG_ACK) {
+ _tcp_procack(ti,tcb,acknum,flags);
+ }
+ _tcp_procdata(ti,tcb,seqnum,flags,buf);
+ break;
+
+ case TCPSTATE_CLOSING:
+ if (acknum == (tcb->tcb_sendunack + 1)) {
+ _tcp_setstate(tcb,TCPSTATE_TIME_WAIT);
+ _tcp_canceltimers(tcb);
+ TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER);
+ }
+ break;
+
+ case TCPSTATE_LAST_ACK:
+ if (acknum == (tcb->tcb_sendunack + 1)) {
+ /* Ack matches, just close the TCB here. */
+ _tcp_closetcb(ti,tcb);
+ /* and free it. */
+ _tcp_freetcb(ti,tcb);
+ }
+ else {
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_FIN,TCP_RETX_TIMER);
+ }
+ break;
+
+ case TCPSTATE_TIME_WAIT:
+ if (!(flags & TCPFLG_RST)) {
+ tcb->tcb_txflags = TCPFLG_ACK;
+ TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER);
+ _tcp_protosend(ti,tcb);
+ }
+ break;
+ }
+
+ /*
+ * If we're expected to transmit something, do it now.
+ */
+
+ if (tcb->tcb_flags & TCB_FLG_OUTPUT) {
+ _tcp_output(ti,tcb);
+ tcb->tcb_flags &= ~(TCB_FLG_OUTPUT | TCB_FLG_SENDMSG);
+ }
+
+ if (tcb->tcb_flags & TCB_FLG_SENDMSG) {
+ _tcp_protosend(ti,tcb);
+ }
+
+ /* We always make a copy of the data, so drop the packet. */
+ return ETH_DROP;
+}
+
+/* *********************************************************************
+ * _tcp_fasttimo(ti)
+ *
+ * Handle "fast timeout" for active TCP sockets.
+ *
+ * Input parameters:
+ * ti - tcp_info structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void _tcp_fasttimo(tcp_info_t *ti)
+{
+ tcb_t *tcb;
+ queue_t *qb;
+
+ /*
+ * First, reset the timer so we'll end up here
+ * again in another 200ms
+ */
+
+ TIMER_SET(ti->ti_fasttimer,TCP_FAST_TIMER); /* 200ms */
+
+ /*
+ * Now, walk down the list of TCBs and handle
+ * all the timers.
+ */
+
+ for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
+ tcb = (tcb_t *) qb;
+ if (tcb->tcb_flags & TCB_FLG_DLYACK) {
+ tcb->tcb_flags &= ~TCB_FLG_DLYACK;
+ _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,-1);
+ }
+ }
+
+ /*
+ * While we're here, increment TCP's initial sequence number.
+ * BSD suggests 128000 every second, so we'll add 25600 every 200ms.
+ */
+
+ ti->ti_iss += 25600;
+
+}
+
+
+/* *********************************************************************
+ * _tcp_poll(arg)
+ *
+ * CFE calls this routine periodically to allow us to check
+ * and update timers, etc.
+ *
+ * Input parameters:
+ * arg - our tcp information (held by the timer module for us)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _tcp_poll(void *arg)
+{
+ tcb_t *tcb;
+ queue_t *qb;
+ tcp_info_t *ti = (tcp_info_t *) arg;
+
+ /*
+ * Handle the "fast" timer. We do this every 200ms
+ */
+
+ if (TIMER_EXPIRED(ti->ti_fasttimer)) {
+ _tcp_fasttimo(ti);
+ /* timer will be reset by the _tcp_fasttimo routine */
+ }
+
+ /*
+ * Check the TCBs for the "slow" timers.
+ */
+
+ for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
+ tcb = (tcb_t *) qb;
+
+ /*
+ * Check the retransmit timer. This is used during connection
+ * attempts to retransmit control messages, or also during
+ * regular data transfer to retransmit messages that are not
+ * acknowledged.
+ *
+ * XXX use the computed round-trip timer here
+ */
+
+ if (TIMER_EXPIRED(tcb->tcb_timer_retx)) {
+ TIMER_CLEAR(tcb->tcb_timer_retx); /* unless it is reset */
+
+ DEBUGMSG(("Retransmit timer expired, retrycnt=%d\n",tcb->tcb_retrycnt));
+
+ switch (tcb->tcb_state) {
+ case TCPSTATE_ESTABLISHED:
+ /*
+ * wind the send seqnum back to the last unacknowledged data,
+ * and send it out again.
+ */
+ TIMER_SET(tcb->tcb_timer_retx,TCP_RETX_TIMER);
+ tcb->tcb_retrycnt++;
+ tcb->tcb_sendnext = tcb->tcb_sendunack;
+ _tcp_output(ti,tcb);
+ break;
+
+ case TCPSTATE_SYN_SENT:
+ TIMER_SET(tcb->tcb_timer_retx,(TCP_RETX_TIMER << tcb->tcb_retrycnt));
+ tcb->tcb_retrycnt++;
+ tcb->tcb_sendnext = tcb->tcb_sendunack;
+ _tcp_protosend(ti,tcb);
+ break;
+
+ }
+ }
+
+ /*
+ * Check the keepalive timer. This is used during connection
+ * attempts to time out the connection, and _can_ be used for
+ * keepalives during established sessions.
+ *
+ * Our TCP does not bother with keepalive messages.
+ */
+
+ if (TIMER_EXPIRED(tcb->tcb_timer_keep)) {
+ TIMER_CLEAR(tcb->tcb_timer_keep); /* unless it is reset */
+ DEBUGMSG(("Keepalive timer expired in state %d\n",tcb->tcb_state));
+ if (TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_CONNINPROGRESS)) {
+ DEBUGMSG(("Canceling pending connection\n"));
+ _tcp_aborttcb(ti,tcb);
+ }
+ }
+
+ /*
+ * Check the 2MSL timer. This is used in the TIME_WAIT state
+ * to return the tcb to the free list after the time wait
+ * period elapses.
+ */
+
+ if (TIMER_EXPIRED(tcb->tcb_timer_2msl)) {
+ TIMER_CLEAR(tcb->tcb_timer_2msl); /* will not be reset */
+ DEBUGMSG(("2MSL timer expired in state %d\n",tcb->tcb_state));
+ if (tcb->tcb_state == TCPSTATE_TIME_WAIT) {
+ DEBUGMSG(("Freeing TCB\n"));
+ _tcp_closetcb(ti,tcb);
+ _tcp_freetcb(ti,tcb);
+ }
+ }
+
+ }
+
+}
+
+
diff --git a/cfe/cfe/net/net_tcp.h b/cfe/cfe/net/net_tcp.h
new file mode 100755
index 0000000..fa772e6
--- /dev/null
+++ b/cfe/cfe/net/net_tcp.h
@@ -0,0 +1,83 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * TCP Protocol Definitions File: net_tcp.h
+ *
+ * This file contains TCP protocol-specific definitions
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+/* *********************************************************************
+ * TCP Flags - keep in sync with net_api.h
+ ********************************************************************* */
+
+#define TCPFLG_NODELAY 1 /* disable nagle */
+#define TCPFLG_NBIO 2 /* Non-blocking I/O */
+
+#define TCPSTATUS_NOTCONN 0
+#define TCPSTATUS_CONNECTING 1
+#define TCPSTATUS_CONNECTED 2
+
+/* *********************************************************************
+ * TCP API
+ ********************************************************************* */
+
+typedef struct tcp_info_s tcp_info_t;
+
+tcp_info_t *_tcp_init(ip_info_t *ipi,void *ref);
+void _tcp_uninit(tcp_info_t *info);
+
+int _tcp_socket(tcp_info_t *info);
+int _tcp_connect(tcp_info_t *ti,int s,uint8_t *dest,uint16_t port);
+int _tcp_close(tcp_info_t *ti,int s);
+int _tcp_send(tcp_info_t *ti,int s,uint8_t *buf,int len);
+int _tcp_recv(tcp_info_t *ti,int s,uint8_t *buf,int len);
+int _tcp_bind(tcp_info_t *ti,int s,uint16_t port);
+int _tcp_peeraddr(tcp_info_t *ti,int s,uint8_t *addr,uint16_t *port);
+int _tcp_listen(tcp_info_t *ti,int s,uint16_t port);
+int _tcp_status(tcp_info_t *ti,int s,unsigned int *connflag,int *rxready,int *rxeof);
+int _tcp_debug(tcp_info_t *ti,int s,int arg);
+int _tcp_setflags(tcp_info_t *ti,int s,unsigned int flags);
+int _tcp_getflags(tcp_info_t *ti,int s,unsigned int *flags);
+
+void _tcp_poll(void *arg);
+
+
diff --git a/cfe/cfe/net/net_tcp_internal.h b/cfe/cfe/net/net_tcp_internal.h
new file mode 100755
index 0000000..1e3fc6d
--- /dev/null
+++ b/cfe/cfe/net/net_tcp_internal.h
@@ -0,0 +1,244 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * TCP Protocol Internal Definitions File: net_tcp_internal.h
+ *
+ * This file contains the structures and constants needed to
+ * maintain TCP connections.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+/* *********************************************************************
+ * TCP Constants
+ ********************************************************************* */
+
+
+#define TCP_MAX_PORTS 8
+#define TCP_MAX_TCBS 16
+#if defined(CONFIG_MIPS_BRCM)
+#define TCP_BUF_SIZE (20 * 1024)
+#else
+#define TCP_BUF_SIZE 65536
+#endif
+
+#define TCP_MAX_SEG_SIZE 1400
+
+#define TCP_CONNECT_TIMER (30*CFE_HZ)
+#define TCP_RETX_TIMER (1*CFE_HZ)
+#define TCP_TIMEWAIT_TIMER (30*CFE_HZ)
+#define TCP_SEND_TIMER (CFE_HZ)
+
+#define TCP_FAST_TIMER (CFE_HZ/5) /* 200ms */
+#define TCP_KEEPALIVE_TIMER (CFE_HZ*60) /* one minute */
+
+
+/* *********************************************************************
+ * TCP Protocol
+ ********************************************************************* */
+
+#define TCPFLG_FIN 0x0001
+#define TCPFLG_SYN 0x0002
+#define TCPFLG_RST 0x0004
+#define TCPFLG_PSH 0x0008
+#define TCPFLG_ACK 0x0010
+#define TCPFLG_URG 0x0020
+#define TCPHDRSIZE(flg) (((flg) >> 12)*4)
+#define TCPHDRFLG(size) (((size)/4)<<12)
+
+#define TCP_HDR_LENGTH 20
+
+#define TCP_MAX_SEG_OPT 0x0204
+
+/* *********************************************************************
+ * TCP State machine
+ ********************************************************************* */
+
+/*
+ * TCB states, see RFC
+ */
+
+#define TCPSTATE_CLOSED 0
+#define TCPSTATE_LISTEN 1
+#define TCPSTATE_SYN_SENT 2
+#define TCPSTATE_SYN_RECEIVED 3
+#define TCPSTATE_ESTABLISHED 4
+#define TCPSTATE_CLOSE_WAIT 5
+#define TCPSTATE_FINWAIT_1 6
+#define TCPSTATE_FINWAIT_2 7
+#define TCPSTATE_CLOSING 8
+#define TCPSTATE_LAST_ACK 9
+#define TCPSTATE_TIME_WAIT 10
+
+/*
+ * Masks for TCP states - we use these so we can make
+ * bit vectors of states for easy tests.
+ */
+
+#define M_TCPSTATE_CLOSED (1 << TCPSTATE_CLOSED)
+#define M_TCPSTATE_LISTEN (1 << TCPSTATE_LISTEN)
+#define M_TCPSTATE_SYN_SENT (1 << TCPSTATE_SYN_SENT)
+#define M_TCPSTATE_SYN_RECEIVED (1 << TCPSTATE_SYN_RECEIVED)
+#define M_TCPSTATE_ESTABLISHED (1 << TCPSTATE_ESTABLISHED)
+#define M_TCPSTATE_CLOSE_WAIT (1 << TCPSTATE_CLOSE_WAIT)
+#define M_TCPSTATE_FINWAIT_1 (1 << TCPSTATE_FINWAIT_1)
+#define M_TCPSTATE_FINWAIT_2 (1 << TCPSTATE_FINWAIT_2)
+#define M_TCPSTATE_CLOSING (1 << TCPSTATE_CLOSING)
+#define M_TCPSTATE_LAST_ACK (1 << TCPSTATE_LAST_ACK)
+#define M_TCPSTATE_TIME_WAIT (1 << TCPSTATE_TIME_WAIT)
+#define M_TCPSTATE_CLOSED (1 << TCPSTATE_CLOSED)
+
+/*
+ * This macro returns true if a given state is in a
+ * set of states (defined below)
+ */
+
+#define TCPSTATE_IN_SET(state,set) ((1 << (state)) & (set))
+
+/*
+ * Intresting groups of TCP states
+ */
+
+/* ABORTSTATES - tcp_abort will send a RST if our TCB is one of these. */
+#define M_TCPSTATE_ABORTSTATES \
+ M_TCPSTATE_SYN_SENT | M_TCPSTATE_SYN_RECEIVED | M_TCPSTATE_ESTABLISHED | \
+ M_TCPSTATE_FINWAIT_1 | M_TCPSTATE_FINWAIT_2 | M_TCPSTATE_CLOSING | \
+ M_TCPSTATE_LAST_ACK | M_TCPSTATE_CLOSE_WAIT
+
+/* SEND_OK - tcp_send will send data if our TCB is one of these */
+#define M_TCPSTATE_SEND_OK \
+ M_TCPSTATE_ESTABLISHED | M_TCPSTATE_CLOSE_WAIT
+
+/* RECV_OK - tcp_recv will pass up data if our TCB is in one of these */
+#define M_TCPSTATE_RECV_OK \
+ M_TCPSTATE_ESTABLISHED | M_TCPSTATE_CLOSE_WAIT
+
+/* PEERADDR_OK - tcp_peeraddr will return a value if TCB is in one of these */
+#define M_TCPSTATE_PEERADDR_OK \
+ M_TCPSTATE_SYN_SENT | M_TCPSTATE_SYN_RECEIVED | M_TCPSTATE_ESTABLISHED | \
+ M_TCPSTATE_FINWAIT_1 | M_TCPSTATE_FINWAIT_2 | M_TCPSTATE_CLOSING | \
+ M_TCPSTATE_LAST_ACK | M_TCPSTATE_CLOSE_WAIT
+
+/* RESETKEEPALIVE - reset keepalive timer in these states */
+#define M_TCPSTATE_RESETKEEPALIVE \
+ M_TCPSTATE_ESTABLISHED | M_TCPSTATE_CLOSE_WAIT | M_TCPSTATE_FINWAIT_1 | \
+ M_TCPSTATE_FINWAIT_2 | M_TCPSTATE_CLOSING | M_TCPSTATE_LAST_ACK
+
+#define CONNINPROGRESS - connection is in progress in these states */
+#define M_TCPSTATE_CONNINPROGRESS \
+ M_TCPSTATE_LISTEN | M_TCPSTATE_SYN_SENT | M_TCPSTATE_SYN_RECEIVED
+
+
+/*
+ * TCP flags for the control block
+ */
+
+#define TCB_FLG_OUTPUT 1 /* need to call tcp_output */
+#define TCB_FLG_SENDMSG 2
+#define TCB_FLG_DLYACK 4 /* delayed ack is pending */
+
+/* *********************************************************************
+ * TCP Control Block
+ ********************************************************************* */
+
+typedef struct tcb_s {
+ queue_t tcb_qb; /* next/previous in list */
+ int tcb_socknum; /* socket number, index into table */
+
+ int tcb_state; /* current connection state */
+
+ uint8_t tcb_peeraddr[IP_ADDR_LEN]; /* Peer's IP Address */
+ uint16_t tcb_peerport; /* Peer's port address */
+ uint16_t tcb_lclport; /* My port address */
+
+ uint16_t tcb_txflags; /* packet flags for next tx packet */
+
+ cfe_timer_t tcb_timer_2msl; /* 2MSL timer, used in TIME_WAIT */
+ cfe_timer_t tcb_timer_keep; /* Timer for keepalives and connections */
+ cfe_timer_t tcb_timer_retx; /* send retransmission timer */
+ cfe_timer_t tcb_timer_pers; /* Persist timer */
+
+ int tcb_retrycnt; /* Retry counter */
+
+ int tcb_mtu; /* MTU if underlying link */
+ unsigned int tcb_flags; /* Misc protocol flags */
+ unsigned int tcb_sockflags; /* flags set by user api */
+
+ /*
+ * Buffers
+ */
+
+ tcpmodbuf_t tcb_txbuf; /* Transmit buffer */
+ tcpmodbuf_t tcb_rxbuf; /* Receive buffer */
+
+ /*
+ * Send sequence variables
+ */
+
+ uint32_t tcb_sendunack; /* oldest unacknowledged seqnum */
+ uint32_t tcb_sendnext; /* Next seqnum to send */
+ uint32_t tcb_sendwindow; /* Last advertised send window */
+
+ /*
+ * Receive sequence variables
+ */
+
+ uint32_t tcb_rcvnext; /* next in-order receive seq num */
+ uint32_t tcb_rcvack; /* last transmitted acknowledgement */
+
+ /*
+ * Window management variables
+ */
+ int tcb_dup_ackcnt; /* Duplicate ack counter */
+
+} tcb_t;
+
+/* *********************************************************************
+ * Macros to muck with sequence numbers
+ ********************************************************************* */
+
+#define TCPSEQ_LT(a,b) ((int)((a)-(b)) < 0)
+#define TCPSEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
+#define TCPSEQ_GT(a,b) ((int)((a)-(b)) > 0)
+#define TCPSEQ_GEQ(a,b) ((int)((a)-(b)) >= 0)
+
+#define TCPSEQ_DIFF(a,b) ((int)((a)-(b)))
+
diff --git a/cfe/cfe/net/net_tcpbuf.c b/cfe/cfe/net/net_tcpbuf.c
new file mode 100644
index 0000000..08e690b
--- /dev/null
+++ b/cfe/cfe/net/net_tcpbuf.c
@@ -0,0 +1,298 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * TCP Protocol File: net_tcp.c
+ *
+ * This file contains a very simple TCP.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_error.h"
+
+#include "net_tcpbuf.h"
+
+
+
+/* *********************************************************************
+ * tmb_init(buf)
+ *
+ * Initialize a modulo buffer's pointers to the "empty" state
+ *
+ * Input parameters:
+ * buf - modulo buffer structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void tmb_init(tcpmodbuf_t *buf)
+{
+ buf->tmb_addptr = 0;
+ buf->tmb_remptr = 0;
+ buf->tmb_len = 0;
+}
+
+/* *********************************************************************
+ * tmb_adjust(buf,amt)
+ *
+ * Move the "remove" pointer ahead by 'amt' without retrieving the
+ * data.
+ *
+ * Input parameters:
+ * buf - modulo buffer structure
+ * amt - number of bytes to move
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+
+void tmb_adjust(tcpmodbuf_t *buf,int amt)
+{
+ /* XXX should we check for moving to far? */
+ buf->tmb_len -= amt;
+ buf->tmb_remptr = (buf->tmb_remptr + amt) % buf->tmb_bufsize;
+}
+
+/* *********************************************************************
+ * tmb_alloc(buf,size)
+ *
+ * Allocate memory for the modulo buffer.
+ *
+ * Input parameters:
+ * buf - modulo buffer structure
+ * size - size of data in modulo buffer
+ *
+ * Return value:
+ * 0 if ok
+ * -1 if error
+ ********************************************************************* */
+
+int tmb_alloc(tcpmodbuf_t *buf,int size)
+{
+ buf->tmb_buf = KMALLOC(size,0);
+ if (!buf->tmb_buf) return -1;
+ buf->tmb_bufsize = size;
+
+ tmb_init(buf);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * tmb_free(buf)
+ *
+ * Free memory associated with the modulo buffer
+ *
+ * Input parameters:
+ * buf - modulo buffer
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void tmb_free(tcpmodbuf_t *buf)
+{
+ if (buf->tmb_buf) KFREE(buf->tmb_buf);
+ buf->tmb_buf = NULL;
+}
+
+
+/* *********************************************************************
+ * tmb_copyin(tmb,buf,len,update)
+ *
+ * Copy data into the modulo buffer at the 'add' pointer
+ *
+ * Input parameters:
+ * tmb - modulo buffer structure
+ * buf,len - buffer and length of buffer to copy in
+ * update - true to advance 'add' pointer (usually true for copyin)
+ *
+ * Return value:
+ * number of bytes actually added to the buffer
+ ********************************************************************* */
+
+int tmb_copyin(tcpmodbuf_t *tmb,uint8_t *buf,int len,int update)
+{
+ int maxlen;
+ int l;
+ int newptr;
+ int retlen;
+
+ if (len == 0) return 0;
+
+ /* Set 'maxlen' to the max # of bytes we will send now */
+ maxlen = tmb->tmb_bufsize - tmb->tmb_len;
+ if (maxlen > len) maxlen = len;
+
+ retlen = maxlen; /* we'll return this later. */
+
+ /* Copy the bytes into the buffer and deal with buffer wrap */
+ l = tmb->tmb_bufsize - tmb->tmb_addptr;
+ if (l > maxlen) l = maxlen;
+
+ memcpy(tmb->tmb_buf + tmb->tmb_addptr,buf,l);
+ maxlen -= l;
+ buf += l;
+
+ if (maxlen) {
+ memcpy(tmb->tmb_buf,buf,maxlen);
+ newptr = maxlen;
+ }
+ else {
+ newptr = tmb->tmb_addptr + l;
+ }
+
+ if (update) {
+ tmb->tmb_len += retlen; /* this many more in the buffer */
+ tmb->tmb_addptr = newptr;
+ }
+
+ return retlen;
+}
+
+/* *********************************************************************
+ * tmb_copyout(tmb,buf,len,update)
+ *
+ * Copy data out of the modulo buffer from the 'remove' pointer
+ *
+ * Input parameters:
+ * tmb - modulo buffer structure
+ * buf,len - buffer and length of buffer to copy out
+ * update - true to advance 'remove' pointer
+ *
+ * Return value:
+ * number of bytes actually removed from the buffer
+ ********************************************************************* */
+
+int tmb_copyout(tcpmodbuf_t *tmb,uint8_t *buf,int len,int update)
+{
+ int maxlen;
+ int l;
+ int newptr;
+ int retlen;
+
+ /* Compute how many bytes to return */
+ maxlen = tmb->tmb_len;
+ if (maxlen > len) maxlen = len;
+
+ retlen = maxlen;
+
+ l = tmb->tmb_bufsize - tmb->tmb_remptr;
+ if (l > maxlen) l = maxlen;
+
+ memcpy(buf,tmb->tmb_buf + tmb->tmb_remptr,l);
+ buf += l;
+ maxlen -= l;
+
+ if (maxlen) {
+ memcpy(buf,tmb->tmb_buf,maxlen);
+ newptr = maxlen;
+ }
+ else {
+ newptr = tmb->tmb_remptr + l;
+ }
+
+ if (update) {
+ tmb->tmb_len -= retlen;
+ tmb->tmb_remptr = newptr;
+ }
+
+ return retlen;
+}
+
+/* *********************************************************************
+ * tmb_copyout2(tmb,buf,offset,len)
+ *
+ * Copy data out of the modulo buffer from a specific offset from
+ * the remove pointer. This is done without updating the
+ * remove pointer - we use this to dig data out when segmenting
+ * packets for transmission.
+ *
+ * Input parameters:
+ * tmb - modulo buffer structure
+ * buf,len - buffer and length of buffer to copy out
+ * offset - offset from remove pointer to start
+ *
+ * Return value:
+ * number of bytes actually copied out of the buffer
+ ********************************************************************* */
+
+int tmb_copyout2(tcpmodbuf_t *tmb,uint8_t *buf,int offset,int len)
+{
+ int maxlen;
+ int l;
+ int retlen;
+ int remptr;
+
+ /* Compute how many bytes to return */
+ maxlen = tmb->tmb_len - offset;
+
+ /* if offset is beyond length, get out now. */
+ if (maxlen <= 0) return 0;
+
+ /* otherwise choose min(max_can_copy,max_to_copy) */
+ if (maxlen > len) maxlen = len;
+ retlen = maxlen;
+
+ /* Adjust remove pointer for offset */
+ remptr = (tmb->tmb_remptr + offset) % tmb->tmb_bufsize;
+
+ l = tmb->tmb_bufsize - remptr;
+ if (l > maxlen) l = maxlen;
+
+ memcpy(buf,tmb->tmb_buf + remptr,l);
+ buf += l;
+ maxlen -= l;
+
+ if (maxlen) {
+ memcpy(buf,tmb->tmb_buf,maxlen);
+ }
+
+ return retlen;
+}
+
diff --git a/cfe/cfe/net/net_tcpbuf.h b/cfe/cfe/net/net_tcpbuf.h
new file mode 100644
index 0000000..0c251e3
--- /dev/null
+++ b/cfe/cfe/net/net_tcpbuf.h
@@ -0,0 +1,83 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * TCP Protocol Definitions File: net_tcp.h
+ *
+ * This file contains TCP protocol-specific definitions
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define tmb_remlen(tmb) ((tmb)->tmb_bufsize - (tmb)->tmb_len)
+#define tmb_curlen(tmb) ((tmb)->tmb_len)
+
+
+/* *********************************************************************
+ * Modulo Buffer
+ ********************************************************************* */
+
+typedef struct tcpmodbuf_s {
+ uint8_t *tmb_buf; /* Buffer */
+ int tmb_bufsize; /* size of buffer */
+ int tmb_addptr; /* current "add" pointer */
+ int tmb_remptr; /* current "remove" pointer */
+ int tmb_len; /* amount of data in the buffer */
+} tcpmodbuf_t;
+
+
+/* *********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+void tmb_init(tcpmodbuf_t *buf);
+void tmb_adjust(tcpmodbuf_t *buf,int amt);
+int tmb_alloc(tcpmodbuf_t *buf,int size);
+void tmb_free(tcpmodbuf_t *buf);
+int tmb_copyin(tcpmodbuf_t *tmb,uint8_t *buf,int len,int update);
+int tmb_copyout(tcpmodbuf_t *tmb,uint8_t *buf,int len,int update);
+int tmb_copyout2(tcpmodbuf_t *tmb,uint8_t *buf,int offset,int len);
+
+
+
+
+
diff --git a/cfe/cfe/net/net_tftp.c b/cfe/cfe/net/net_tftp.c
new file mode 100644
index 0000000..1c3e799
--- /dev/null
+++ b/cfe/cfe/net/net_tftp.c
@@ -0,0 +1,921 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * TFTP Client File: net_tftp.c
+ *
+ * This module contains a TFTP client.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_error.h"
+#include "cfe_fileops.h"
+
+/* Foxconn add start by Cliff Wang, 03/23/2010 */
+#include "cfe_console.h"
+/* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "cfe.h"
+
+#include "cfe_loader.h"
+
+#include "net_api.h"
+
+
+
+/* *********************************************************************
+ * TFTP protocol
+ ********************************************************************* */
+
+#define UDP_PROTO_TFTP 69
+
+#define TFTP_BLOCKSIZE 512
+
+#define TFTP_OP_RRQ 1
+#define TFTP_OP_WRQ 2
+#define TFTP_OP_DATA 3
+#define TFTP_OP_ACK 4
+#define TFTP_OP_ERROR 5
+
+#define TFTP_ERR_DISKFULL 3
+
+#define TFTP_MAX_RETRIES 8
+
+#define TFTP_RRQ_TIMEOUT 1 /* seconds */
+#define TFTP_RECV_TIMEOUT 1 /* seconds */
+
+/* *********************************************************************
+ * TFTP context
+ ********************************************************************* */
+
+typedef struct tftp_fsctx_s {
+ int dummy;
+} tftp_fsctx_t;
+
+typedef struct tftp_info_s {
+ int tftp_socket;
+ uint8_t tftp_data[TFTP_BLOCKSIZE];
+ int tftp_blklen;
+ int tftp_blkoffset;
+ int tftp_fileoffset;
+ uint16_t tftp_blknum;
+ uint8_t tftp_ipaddr[IP_ADDR_LEN];
+ int tftp_lastblock;
+ int tftp_error;
+ int tftp_filemode;
+ char *tftp_filename;
+} tftp_info_t;
+
+/* *********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+static int tftp_fileop_init(void **fsctx,void *devicename);
+static int tftp_fileop_open(void **ref,void *fsctx,char *filename,int mode);
+static int tftp_fileop_read(void *ref,uint8_t *buf,int len);
+static int tftp_fileop_write(void *ref,uint8_t *buf,int len);
+static int tftp_fileop_seek(void *ref,int offset,int how);
+static void tftp_fileop_close(void *ref);
+static void tftp_fileop_uninit(void *fsctx);
+
+/* Foxconn add start by Cliff Wang, 03/23/2010 */
+int tftp_max_retries = TFTP_MAX_RETRIES;
+int tftp_rrq_timeout = TFTP_RRQ_TIMEOUT;
+int tftp_recv_timeout = TFTP_RECV_TIMEOUT;
+/* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+/* *********************************************************************
+ * TFTP fileio dispatch table
+ ********************************************************************* */
+
+const fileio_dispatch_t tftp_fileops = {
+ "tftp",
+ LOADFLG_NOBB | FSYS_TYPE_NETWORK,
+ tftp_fileop_init,
+ tftp_fileop_open,
+ tftp_fileop_read,
+ tftp_fileop_write,
+ tftp_fileop_seek,
+ tftp_fileop_close,
+ tftp_fileop_uninit
+};
+
+
+/* *********************************************************************
+ * _tftp_open(info,hostname,filename,mode)
+ *
+ * Open a file on a remote host, using the TFTP protocol.
+ *
+ * Input parameters:
+ * info - TFTP information
+ * hostname - host name or IP address of remote host
+ * filename - name of file on remote system
+ * mode - file open mode, read or write
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int _tftp_open(tftp_info_t *info,char *hostname,char *filename,int mode)
+{
+ ebuf_t *buf = NULL;
+ const char *datamode = "octet";
+ uint16_t type,error,block;
+ int res;
+ int retries;
+
+ /*
+ * Look up the remote host's IP address
+ */
+
+ res = dns_lookup(hostname,info->tftp_ipaddr);
+ if (res < 0) return res;
+
+ /*
+ * Open a UDP socket to the TFTP server
+ */
+
+ info->tftp_socket = udp_socket(UDP_PROTO_TFTP);
+ info->tftp_lastblock = 0;
+ info->tftp_error = 0;
+ info->tftp_filemode = mode;
+
+ /*
+ * Try to send the RRQ packet to open the file
+ */
+
+ for (retries = 0; retries < TFTP_MAX_RETRIES; retries++) {
+
+ buf = udp_alloc();
+ if (!buf) break;
+
+ if (info->tftp_filemode == FILE_MODE_READ) {
+ ebuf_append_u16_be(buf,TFTP_OP_RRQ); /* read file */
+ }
+ else {
+ ebuf_append_u16_be(buf,TFTP_OP_WRQ); /* write file */
+ }
+ ebuf_append_bytes(buf,filename,strlen(filename)+1);
+ ebuf_append_bytes(buf,datamode,strlen(datamode)+1);
+
+ udp_send(info->tftp_socket,buf,info->tftp_ipaddr);
+
+ buf = udp_recv_with_timeout(info->tftp_socket,TFTP_RRQ_TIMEOUT);
+ if (buf) break;
+ }
+
+ /*
+ * If we got no response, bail now.
+ */
+
+ if (!buf) {
+ udp_close(info->tftp_socket);
+ info->tftp_socket = -1;
+ return CFE_ERR_TIMEOUT;
+ }
+
+ /*
+ * Otherwise, process the response.
+ */
+
+ ebuf_get_u16_be(buf,type);
+
+ switch (type) {
+ case TFTP_OP_ACK:
+ /*
+ * Acks are what we get back on a WRQ command,
+ * but are otherwise unexpected.
+ */
+ if (info->tftp_filemode == FILE_MODE_WRITE) {
+ udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
+ info->tftp_blknum = 1;
+ info->tftp_blklen = 0;
+ udp_free(buf);
+ return 0;
+ break;
+ }
+ /* fall through */
+ case TFTP_OP_RRQ:
+ case TFTP_OP_WRQ:
+ default:
+ /*
+ * we aren't expecting any of these messages
+ */
+ udp_free(buf);
+ udp_close(info->tftp_socket);
+ info->tftp_socket = -1;
+ return CFE_ERR_PROTOCOLERR;
+
+ case TFTP_OP_ERROR:
+ /*
+ * Process the error return (XXX: remove xprintf here)
+ */
+ ebuf_get_u16_be(buf,error);
+ xprintf("TFTP error %d: %s\n",error,ebuf_ptr(buf));
+ udp_free(buf);
+ udp_close(info->tftp_socket);
+ info->tftp_socket = -1;
+ return CFE_ERR_PROTOCOLERR;
+
+ case TFTP_OP_DATA:
+ /*
+ * Yay, we've got data! Store the first block.
+ */
+ ebuf_get_u16_be(buf,block);
+ udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
+ info->tftp_blknum = block;
+ info->tftp_blklen = ebuf_length(buf);
+ ebuf_get_bytes(buf,info->tftp_data,ebuf_length(buf));
+ udp_free(buf);
+ if (info->tftp_blklen < TFTP_BLOCKSIZE) {
+ info->tftp_lastblock = 1; /* EOF */
+ }
+ return 0;
+ break;
+
+ }
+}
+
+
+/* *********************************************************************
+ * _tftp_readmore(info)
+ *
+ * Read the next block of the file. We do this by acking the
+ * previous block. Once that block is acked, the TFTP server
+ * should send the next block to us.
+ *
+ * Input parameters:
+ * info - TFTP information
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int _tftp_readmore(tftp_info_t *info)
+{
+ ebuf_t *buf;
+ uint16_t cmd,block;
+ int retries;
+
+ /*
+ * If we've already read the last block, there is no more
+ */
+
+ if (info->tftp_lastblock) return 1;
+ if (info->tftp_error) return CFE_ERR_TIMEOUT;
+
+ /*
+ * Otherwise, ack the current block so another one will come
+ */
+
+ for (retries = 0; retries < TFTP_MAX_RETRIES; retries++) {
+
+ buf = udp_alloc();
+ if (!buf) return -1;
+
+ /*
+ * Send the ack
+ */
+
+ ebuf_append_u16_be(buf,TFTP_OP_ACK);
+ ebuf_append_u16_be(buf,info->tftp_blknum);
+ udp_send(info->tftp_socket,buf,info->tftp_ipaddr);
+
+ /*
+ * Wait for some response, retransmitting as necessary
+ */
+
+ /* Foxconn add start by Cliff Wang, 03/23/2010 */
+ buf = udp_recv_with_timeout(info->tftp_socket,tftp_recv_timeout);
+ // buf = udp_recv_with_timeout(info->tftp_socket,TFTP_RECV_TIMEOUT);
+ /* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+ if (buf == NULL) continue;
+
+ /*
+ * Got a response, make sure it's right
+ */
+
+ ebuf_get_u16_be(buf,cmd);
+ if (cmd != TFTP_OP_DATA) {
+ udp_free(buf);
+ continue;
+ }
+
+ ebuf_get_u16_be(buf,block);
+ if (block != (info->tftp_blknum+1)) {
+ udp_free(buf);
+ continue;
+ }
+
+ /*
+ * It's the correct response. Copy the user data
+ */
+
+ info->tftp_blknum = block;
+ info->tftp_blklen = ebuf_length(buf);
+ ebuf_get_bytes(buf,info->tftp_data,ebuf_length(buf));
+ udp_free(buf);
+ break;
+ }
+
+ /*
+ * If the block is less than 512 bytes long, it's the EOF block.
+ */
+
+ if (retries == TFTP_MAX_RETRIES) {
+ info->tftp_error = 1;
+ return CFE_ERR_TIMEOUT;
+ }
+
+ if (info->tftp_blklen < TFTP_BLOCKSIZE) {
+ info->tftp_lastblock = 1; /* EOF */
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _tftp_writemore(info)
+ *
+ * Write the next block of the file, sending the data from our
+ * holding buffer. Note that the holding buffer must be full
+ * or else we consider this to be an EOF.
+ *
+ * Input parameters:
+ * info - TFTP information
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int _tftp_writemore(tftp_info_t *info)
+{
+ ebuf_t *buf;
+ uint16_t cmd,block,error;
+ int retries;
+
+ /*
+ * If we've already written the last block, there is no more
+ */
+
+ if (info->tftp_lastblock) return 1;
+ if (info->tftp_error) return CFE_ERR_TIMEOUT;
+
+ /*
+ * Otherwise, send a block
+ */
+
+ for (retries = 0; retries < TFTP_MAX_RETRIES; retries++) {
+
+ buf = udp_alloc();
+ if (!buf) return -1;
+
+ /*
+ * Send the data
+ */
+
+ ebuf_append_u16_be(buf,TFTP_OP_DATA);
+ ebuf_append_u16_be(buf,info->tftp_blknum);
+ ebuf_append_bytes(buf,info->tftp_data,info->tftp_blklen);
+ udp_send(info->tftp_socket,buf,info->tftp_ipaddr);
+
+ /*
+ * Wait for some response, retransmitting as necessary
+ */
+
+ /* Foxconn add start by Cliff Wang, 03/23/2010 */
+ buf = udp_recv_with_timeout(info->tftp_socket, tftp_recv_timeout);
+ // buf = udp_recv_with_timeout(info->tftp_socket,TFTP_RECV_TIMEOUT);
+ /* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+ if (buf == NULL) continue;
+
+ /*
+ * Got a response, make sure it's right
+ */
+
+ ebuf_get_u16_be(buf,cmd);
+
+ if (cmd == TFTP_OP_ERROR) {
+ /*
+ * Process the error return (XXX: remove xprintf here)
+ */
+ ebuf_get_u16_be(buf,error);
+ xprintf("TFTP write error %d: %s\n",error,ebuf_ptr(buf));
+ info->tftp_error = 1;
+ info->tftp_lastblock = 1;
+ udp_free(buf);
+ return CFE_ERR_IOERR;
+ }
+
+ if (cmd != TFTP_OP_ACK) {
+ udp_free(buf);
+ continue;
+ }
+
+ ebuf_get_u16_be(buf,block);
+ if (block != (info->tftp_blknum)) {
+ udp_free(buf);
+ continue;
+ }
+
+ /*
+ * It's the correct response. Update the block #
+ */
+
+ info->tftp_blknum++;
+ if (info->tftp_blklen != TFTP_BLOCKSIZE) info->tftp_lastblock = 1;
+ udp_free(buf);
+ break;
+ }
+
+ /*
+ * If we had some failure, mark the stream with an error
+ */
+
+ if (retries == TFTP_MAX_RETRIES) {
+ info->tftp_error = 1;
+ return CFE_ERR_TIMEOUT;
+ }
+
+ return 0;
+}
+
+/* Foxconn add start by Cliff Wang, 03/23/2010 */
+static int _tftpd_open(tftp_info_t *info,char *hostname,char *filename,int mode)
+{
+ ebuf_t *buf = NULL;
+ uint16_t type;
+ int res;
+ int retries;
+ char ch = 0;
+
+ /*
+ * * Open a UDP socket
+ * */
+
+ info->tftp_socket = udp_socket(UDP_PROTO_TFTP);
+ info->tftp_lastblock = 0;
+ info->tftp_error = 0;
+ info->tftp_filemode = mode;
+
+ /*
+ * * Listen for requests
+ * */
+
+ res = udp_bind(info->tftp_socket,UDP_PROTO_TFTP);
+ if (res < 0) return res;
+
+ res = CFE_ERR_TIMEOUT;
+
+ for (retries = 0; retries < tftp_max_retries; retries++) {
+ while (console_status()) {
+ console_read(&ch,1);
+ if (ch == 3) break;
+ }
+
+ if (ch == 3) {
+ res = CFE_ERR_INTR;
+ break;
+ }
+
+ buf = udp_recv_with_timeout(info->tftp_socket,tftp_recv_timeout);
+ if (buf == NULL) continue;
+
+ /*
+ * * Process the request
+ * */
+
+ ebuf_get_u16_be(buf,type);
+
+ switch (type) {
+ case TFTP_OP_RRQ:
+ udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
+ memcpy(info->tftp_ipaddr,buf->eb_usrptr,IP_ADDR_LEN);
+ info->tftp_blknum = 1;
+ info->tftp_blklen = 0;
+ res = 0;
+ break;
+
+ case TFTP_OP_WRQ:
+ udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
+ memcpy(info->tftp_ipaddr,buf->eb_usrptr,IP_ADDR_LEN);
+ info->tftp_blknum = 0;
+ res = _tftp_readmore(info);
+ break;
+
+ default:
+ /*
+ * aren't expecting any of these messages
+ * */
+ res = CFE_ERR_PROTOCOLERR;
+ break;
+ }
+
+ udp_free(buf);
+ break;
+ }
+
+ if (res) {
+ udp_close(info->tftp_socket);
+ info->tftp_socket = -1;
+ }
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * _tftp_close(info)
+ *
+ * Close a TFTP file. There are two cases for what we do
+ * here. If we're closing the file mid-stream, send an error
+ * packet to tell the host we're getting out early. Otherwise,
+ * just ack the final packet and the connection will close
+ * gracefully.
+ *
+ * Input parameters:
+ * info - TFTP info
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int _tftp_close(tftp_info_t *info)
+{
+ ebuf_t *buf;
+ const char *emsg = "transfer cancelled"; /* some error message */
+
+ if (info->tftp_socket == -1) return 0;
+
+ if (info->tftp_filemode == FILE_MODE_READ) {
+ buf = udp_alloc();
+ if (buf) {
+ /* If we're on the EOF packet, just send an ack */
+ if (info->tftp_lastblock) {
+ ebuf_append_u16_be(buf,TFTP_OP_ACK);
+ ebuf_append_u16_be(buf,info->tftp_blknum);
+ }
+ else {
+ ebuf_append_u16_be(buf,TFTP_OP_ERROR);
+ ebuf_append_u16_be(buf,TFTP_ERR_DISKFULL);
+ ebuf_append_bytes(buf,emsg,strlen(emsg)+1);
+ }
+ udp_send(info->tftp_socket,buf,info->tftp_ipaddr);
+ }
+ }
+ else {
+ /* Just flush out the remaining write data, if any */
+ _tftp_writemore(info);
+ }
+
+ udp_close(info->tftp_socket);
+ info->tftp_socket = -1;
+ return 0;
+}
+
+
+
+/* *********************************************************************
+ * tftp_fileop_init(fsctx,device)
+ *
+ * Create a file system device context for the TFTP service
+ *
+ * Input parameters:
+ * fsctx - location to place context information
+ * device - underlying device (unused)
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int tftp_fileop_init(void **fsctx,void *dev)
+{
+ void *ref;
+
+ ref = KMALLOC(sizeof(tftp_fsctx_t),0);
+
+ if (!ref) return CFE_ERR_NOMEM;
+ *fsctx = ref;
+ return 0;
+}
+
+/* *********************************************************************
+ * tftp_fileop_open(ref,fsctx,filename,mode)
+ *
+ * This is the filesystem entry point for opening a TFTP file.
+ * Allocate a tftp_info structure, open the TFTP file, and
+ * return a handle.
+ *
+ * Input parameters:
+ * ref - location to place reference data (the TFTP structure)
+ * fsctx - filesystem context
+ * filename - name of remote file to open
+ * mode - FILE_MODE_READ or FILE_MODE_WRITE
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int tftp_fileop_open(void **ref,void *fsctx,char *filename,int mode)
+{
+ tftp_info_t *info;
+ char *host;
+ char *file;
+ int res;
+
+ if ((mode != FILE_MODE_READ) && (mode != FILE_MODE_WRITE)) {
+ /* must be either read or write, not both */
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ /* Allocate the tftp info structure */
+
+ info = KMALLOC(sizeof(tftp_info_t),0);
+ if (!info) {
+ return CFE_ERR_NOMEM;
+ }
+
+
+ info->tftp_filename = lib_strdup(filename);
+ if (!info->tftp_filename) {
+ KFREE(info);
+ return CFE_ERR_NOMEM;
+ }
+
+ lib_chop_filename(info->tftp_filename,&host,&file);
+
+ /* Open the file */
+ /* Foxconn add start by Cliff Wang, 03/23/2010 */
+ if (!*host && !*file) {
+ /* TFTP server if hostname and filename are not specified */
+ res = _tftpd_open(info,host,file,mode);
+ } else {
+ res = _tftp_open(info,host,file,mode);
+ }
+ /* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+ if (res == 0) {
+ info->tftp_blkoffset = 0;
+ info->tftp_fileoffset = 0;
+ *ref = info;
+ }
+ else {
+ KFREE(info->tftp_filename);
+ KFREE(info);
+ *ref = NULL;
+ }
+ return res;
+}
+
+/* *********************************************************************
+ * tftp_fileop_read(ref,buf,len)
+ *
+ * Read some bytes from the remote TFTP file. Do this by copying
+ * data from the block buffer, and reading more data from the
+ * remote file as necessary.
+ *
+ * Input parameters:
+ * ref - tftp_info structure
+ * buf - destination buffer address (NULL to read data and
+ * not copy it anywhere)
+ * len - number of bytes to read
+ *
+ * Return value:
+ * number of bytes read, 0 for EOF, <0 if an error occured.
+ ********************************************************************* */
+
+static int tftp_fileop_read(void *ref,uint8_t *buf,int len)
+{
+ tftp_info_t *info = (tftp_info_t *) ref;
+ int copied = 0;
+ int amtcopy;
+ int res;
+
+ if (info->tftp_error) return CFE_ERR_IOERR;
+ if (info->tftp_filemode == FILE_MODE_WRITE) return CFE_ERR_UNSUPPORTED;
+
+ while (len) {
+
+ if (info->tftp_blkoffset >= info->tftp_blklen) break;
+ amtcopy = len;
+
+ if (amtcopy > (info->tftp_blklen-info->tftp_blkoffset)) {
+ amtcopy = (info->tftp_blklen-info->tftp_blkoffset);
+ }
+
+ if (buf) {
+ memcpy(buf,&(info->tftp_data[info->tftp_blkoffset]),amtcopy);
+ buf += amtcopy;
+ }
+
+ info->tftp_blkoffset += amtcopy;
+ len -= amtcopy;
+ info->tftp_fileoffset += amtcopy;
+ copied += amtcopy;
+
+ if (info->tftp_blkoffset >= info->tftp_blklen) {
+ res = _tftp_readmore(info);
+ if (res != 0) break;
+ info->tftp_blkoffset = 0;
+ }
+ }
+
+ return copied;
+}
+
+/* *********************************************************************
+ * tftp_fileop_write(ref,buf,len)
+ *
+ * Write some bytes to the remote TFTP file. Do this by copying
+ * data to the block buffer, and writing data to the
+ * remote file as necessary.
+ *
+ * Input parameters:
+ * ref - tftp_info structure
+ * buf - source buffer address
+ * len - number of bytes to write
+ *
+ * Return value:
+ * number of bytes written, 0 for EOF, <0 if an error occured.
+ ********************************************************************* */
+
+static int tftp_fileop_write(void *ref,uint8_t *buf,int len)
+{
+ tftp_info_t *info = (tftp_info_t *) ref;
+ int copied = 0;
+ int amtcopy;
+ int res;
+
+ if (info->tftp_error) return CFE_ERR_IOERR;
+ if (info->tftp_filemode == FILE_MODE_READ) return CFE_ERR_UNSUPPORTED;
+
+ while (len) {
+
+ amtcopy = len;
+ if (amtcopy > (TFTP_BLOCKSIZE - info->tftp_blklen)) {
+ amtcopy = (TFTP_BLOCKSIZE - info->tftp_blklen);
+ }
+
+ memcpy(&(info->tftp_data[info->tftp_blklen]),buf,amtcopy);
+ buf += amtcopy;
+
+ info->tftp_blklen += amtcopy;
+ len -= amtcopy;
+ info->tftp_fileoffset += amtcopy;
+ copied += amtcopy;
+
+ if (info->tftp_blklen == TFTP_BLOCKSIZE) {
+ res = _tftp_writemore(info);
+ if (res != 0) {
+ break;
+ }
+ info->tftp_blklen = 0;
+ }
+ }
+
+ return copied;
+}
+
+/* *********************************************************************
+ * tftp_fileop_seek(ref,offset,how)
+ *
+ * Seek within a TFTP file. Note that you can only seek *forward*,
+ * as TFTP doesn't really let you go backwards. (I suppose you
+ * could reopen the file, but thus far nobody needs to go
+ * backwards). You can only seek in a file in read mode.
+ *
+ * Input parameters:
+ * ref - our tftp information
+ * offset - distance to move
+ * how - how to move, (FILE_SEEK_*)
+ *
+ * Return value:
+ * new offset, or <0 if an error occured.
+ ********************************************************************* */
+
+static int tftp_fileop_seek(void *ref,int offset,int how)
+{
+ tftp_info_t *info = (tftp_info_t *) ref;
+ int delta;
+ int startloc;
+ int res;
+
+ if (info->tftp_filemode == FILE_MODE_WRITE) return CFE_ERR_UNSUPPORTED;
+
+ switch (how) {
+ case FILE_SEEK_BEGINNING:
+ startloc = info->tftp_fileoffset;
+ break;
+ case FILE_SEEK_CURRENT:
+ startloc = 0;
+ break;
+ default:
+ startloc = 0;
+ break;
+ }
+
+ delta = offset - startloc;
+ if (delta < 0) {
+ xprintf("Warning: negative seek on tftp file attempted\n");
+ return CFE_ERR_UNSUPPORTED;
+ }
+ res = tftp_fileop_read(ref,NULL,delta);
+ if (res < 0) return res;
+
+ return info->tftp_fileoffset;
+}
+
+
+/* *********************************************************************
+ * tftp_fileop_close(ref)
+ *
+ * Close the TFTP file.
+ *
+ * Input parameters:
+ * ref - our TFTP info
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void tftp_fileop_close(void *ref)
+{
+ tftp_info_t *info = (tftp_info_t *) ref;
+
+ _tftp_close(info);
+
+ KFREE(info->tftp_filename);
+ KFREE(info);
+}
+
+
+/* *********************************************************************
+ * tftp_fileop_uninit(fsctx)
+ *
+ * Uninitialize the filesystem context, freeing allocated
+ * resources.
+ *
+ * Input parameters:
+ * fsctx - our context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void tftp_fileop_uninit(void *fsctx)
+{
+ KFREE(fsctx);
+}
diff --git a/cfe/cfe/net/net_udp.c b/cfe/cfe/net/net_udp.c
new file mode 100644
index 0000000..968081a
--- /dev/null
+++ b/cfe/cfe/net/net_udp.c
@@ -0,0 +1,637 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * User Datagram Protocol File: net_udp.c
+ *
+ * This module implements the User Datagram Protocol (RFCxxxx)
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_timer.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "net_ip.h"
+
+#include "cfe_error.h"
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define UDP_HDR_LENGTH 8
+#define UDP_PORTBASE 1024
+#define UDP_MAX_PORTS 4
+
+/* *********************************************************************
+ * Types
+ ********************************************************************* */
+
+typedef struct udp_port_s udp_port_t;
+
+/*
+ * UDP port structure - describes an open UDP port.
+ */
+
+struct udp_port_s {
+ uint16_t up_destport; /* destination port number */
+ uint16_t up_srcport; /* source port number */
+ queue_t up_rxqueue; /* queue of received packets */
+ int up_maxqueue; /* max # of elements on rx queue */
+ int up_inuse; /* nonzero if port is in use */
+};
+
+
+/*
+ * UDP stack information - describes the entire UDP layer.
+ */
+
+struct udp_info_s {
+ uint16_t ui_portbase;
+ void *ui_ref;
+ ip_info_t *ui_ipinfo;
+ udp_port_t ui_ports[UDP_MAX_PORTS];
+};
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+static int _udp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr);
+
+
+/* *********************************************************************
+ * udp_find_port(info,port)
+ *
+ * Locate an open port. Scan the list of ports looking for one
+ * that is both open and has a matching source port number.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * port - source port # we're looking for
+ *
+ * Return value:
+ * udp_port_t pointer or NULL if no port was found
+ ********************************************************************* */
+
+static udp_port_t *_udp_find_port(udp_info_t *info,uint16_t port)
+{
+ int idx;
+ udp_port_t *udp = info->ui_ports;
+
+ for (idx = 0; idx < UDP_MAX_PORTS; idx++) {
+ if (udp->up_inuse && (udp->up_srcport == port)) {
+ return udp;
+ }
+ udp++;
+ }
+
+ return NULL;
+}
+
+/* *********************************************************************
+ * _udp_socket(info,port)
+ *
+ * Open a UDP socket. This is an internal function used by
+ * the network API layer.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * port - port number to open
+ *
+ * Return value:
+ * port number (0 based) or an error code (<0) if an error
+ * occured.
+ ********************************************************************* */
+
+int _udp_socket(udp_info_t *info,uint16_t port)
+{
+ extern int32_t _getticks(void); /* return value of CP0 COUNT */
+ int idx;
+ udp_port_t *udp;
+ uint16_t srcport = UDP_PORTBASE + (_getticks() & 0xFFF);
+
+ while (_udp_find_port(info,srcport)) { /* should always exit */
+ srcport++;
+ if (srcport > (UDP_PORTBASE+4096)) srcport = UDP_PORTBASE;
+ }
+
+ udp = info->ui_ports;
+
+ for (idx = 0; idx < UDP_MAX_PORTS; idx++) {
+ if (!udp->up_inuse) break;
+ udp++;
+ }
+
+ if (idx == UDP_MAX_PORTS) return CFE_ERR_NOHANDLES;
+
+ udp->up_destport = port;
+ udp->up_srcport = srcport;
+ udp->up_maxqueue = 2;
+ udp->up_inuse = TRUE;
+ q_init(&(udp->up_rxqueue));
+
+ return idx;
+}
+
+
+/* *********************************************************************
+ * _udp_close(info,s)
+ *
+ * Internal function to close an open UDP port. This routine is
+ * called by the high-level network API.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket handle (returned from _udp_open)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _udp_close(udp_info_t *info,int s)
+{
+ udp_port_t *udp = &(info->ui_ports[s]);
+ ebuf_t *buf;
+
+ while ((buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue)))) {
+ _ip_free(info->ui_ipinfo,buf);
+ }
+
+ udp->up_srcport = 0;
+ udp->up_destport = 0;
+ udp->up_maxqueue = 0;
+ udp->up_inuse = FALSE;
+}
+
+/* *********************************************************************
+ * _udp_send(info,s,buf,dest)
+ *
+ * Transmit a UDP datagram. Note that we never send fragmented
+ * datagrams, so all datagrams must be less than the MTU.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket handle (returned from _udp_open)
+ * buf - an ebuf to send
+ * dest - destination IP address
+ *
+ * Return value:
+ * 0 if packet was sent
+ * else error code
+ ********************************************************************* */
+
+int _udp_send(udp_info_t *info,int s,ebuf_t *buf,uint8_t *dest)
+{
+ udp_port_t *udp = &(info->ui_ports[s]);
+ uint8_t *udphdr;
+ int udplen;
+ uint8_t pseudoheader[12];
+ uint16_t cksum;
+
+ /*
+ * Calculate the length of the IP datagram (includes UDP header)
+ */
+
+ udplen = ebuf_length(buf) + UDP_HDR_LENGTH;
+
+ /*
+ * Build the pseudoheader, which is part of the checksum calculation
+ */
+
+ _ip_getaddr(info->ui_ipinfo,&pseudoheader[0]);
+ memcpy(&pseudoheader[4],dest,IP_ADDR_LEN);
+ pseudoheader[8] = 0;
+ pseudoheader[9] = IPPROTO_UDP;
+ pseudoheader[10] = (udplen >> 8) & 0xFF;
+ pseudoheader[11] = (udplen & 0xFF);
+
+ /*
+ * Back up and build the actual UDP header in the packet
+ */
+
+ ebuf_seek(buf,-UDP_HDR_LENGTH);
+ udphdr = ebuf_ptr(buf);
+
+ ebuf_put_u16_be(buf,udp->up_srcport);
+ ebuf_put_u16_be(buf,udp->up_destport);
+ ebuf_put_u16_be(buf,udplen);
+ ebuf_put_u16_be(buf,0);
+
+ ebuf_prepend(buf,UDP_HDR_LENGTH);
+
+ /*
+ * Checksum the packet and insert the checksum into the header
+ */
+
+ cksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader));
+ cksum = ip_chksum(cksum,udphdr,udplen);
+ cksum = ~cksum;
+ if (cksum == 0) cksum = 0xFFFF;
+ udphdr[6] = (cksum >> 8) & 0xFF;
+ udphdr[7] = (cksum & 0xFF);
+
+ /*
+ * Off it goes!
+ */
+
+ _ip_send(info->ui_ipinfo,buf,dest,IPPROTO_UDP);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _udp_bind(info,s,port)
+ *
+ * Bind a UDP socket to a particular port number. Basically,
+ * all this means is we set the "source" port number.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket (from _udp_open)
+ * port - port number to assign to the UDP socket
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int _udp_bind(udp_info_t *info,int s,uint16_t port)
+{
+ udp_port_t *udp = &(info->ui_ports[s]);
+
+ if (_udp_find_port(info,port)) return CFE_ERR_ALREADYBOUND;
+
+ udp->up_srcport = port;
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * _udp_connect(info,s,port)
+ *
+ * "connect" a UDP socket to a particular port number. Basically,
+ * this just sets the "destination" port number. It is used for
+ * protocols like TFTP where the destination port number changes
+ * after the port is open.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket (from _udp_open)
+ * port - port number to assign to the UDP socket
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _udp_connect(udp_info_t *info,int s,uint16_t port)
+{
+ udp_port_t *udp = &(info->ui_ports[s]);
+
+ udp->up_destport = port;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _udp_rx_callback(ref,buf,destaddr,srcaddr)
+ *
+ * Receive callback routine from the IP layer. When an IP
+ * packet of protocol type "UDP" is received, this routine gets
+ * called.
+ *
+ * Input parameters:
+ * ref - reference data (pointer to our UDP stack info)
+ * buf - the ebuf, currently pointing at the UDP header
+ * destaddr - the destination IP address (usually our IP address)
+ * srcaddr - the source IP address
+ *
+ * Return value:
+ * ETH_KEEP to keep (not deallocate) the packet
+ * ETH_DROP to deallocate the packet.
+ ********************************************************************* */
+
+static int _udp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr)
+{
+ uint8_t pseudoheader[12];
+ int udplen;
+ uint16_t calccksum;
+ uint16_t origcksum;
+ uint8_t *udphdr;
+ uint16_t srcport;
+ uint16_t dstport;
+ uint16_t udplen2;
+ udp_port_t *udp;
+ udp_info_t *info = (udp_info_t *) ref;
+
+
+
+ /*
+ * get a pointer to the UDP header
+ */
+
+ udplen = ebuf_length(buf);
+ udphdr = ebuf_ptr(buf);
+
+ /*
+ * see if we are checking checksums (cksum field != 0)
+ */
+
+ if ((udphdr[6] | udphdr[7]) != 0) {
+
+ /*
+ * construct the pseudoheader for the cksum calculation
+ */
+
+ memcpy(&pseudoheader[0],srcaddr,IP_ADDR_LEN);
+ memcpy(&pseudoheader[4],destaddr,IP_ADDR_LEN);
+ pseudoheader[8] = 0;
+ pseudoheader[9] = IPPROTO_UDP;
+ pseudoheader[10] = (udplen >> 8) & 0xFF;
+ pseudoheader[11] = (udplen & 0xFF);
+
+ origcksum = ((uint16_t) udphdr[6] << 8) | (uint16_t) udphdr[7];
+ udphdr[6] = udphdr[7] = 0;
+
+ calccksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader));
+ calccksum = ip_chksum(calccksum,udphdr,udplen);
+ if (calccksum != 0xffff) {
+ calccksum = ~calccksum;
+ }
+
+ if (calccksum != origcksum) {
+ return ETH_DROP;
+ }
+ }
+
+ /* Read the other UDP header fields from the packet */
+
+ ebuf_get_u16_be(buf,srcport);
+ ebuf_get_u16_be(buf,dstport);
+ ebuf_get_u16_be(buf,udplen2);
+ ebuf_skip(buf,2);
+
+ /*
+ * It's no good if the lengths don't match. The length
+ * reported by IP should be the length in the UDP header + 8
+ */
+
+ if (udplen2 != (uint16_t) udplen) {
+ return ETH_DROP;
+ }
+
+ /*
+ * Okay, start looking for a matching port
+ */
+
+ udp = _udp_find_port(info,dstport);
+ if (!udp) {
+ return ETH_DROP; /* drop packet if no matching port */
+ /* XXX should send ICMP message here */
+ }
+
+ buf->eb_usrdata = (int) srcport;
+ buf->eb_usrptr = srcaddr;
+
+ /*
+ * Drop packet if queue is full
+ */
+
+ if (q_count(&(udp->up_rxqueue)) >= udp->up_maxqueue) {
+ return ETH_DROP;
+ }
+
+ /*
+ * Add to receive queue
+ */
+
+ ebuf_setlength(buf,udplen2-UDP_HDR_LENGTH);
+ q_enqueue(&(udp->up_rxqueue),(queue_t *) buf);
+
+ return ETH_KEEP;
+}
+
+
+/* *********************************************************************
+ * _udp_recv(info,s)
+ *
+ * Receive a packet from the specified UDP socket.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket handle (from _udp_open)
+ *
+ * Return value:
+ * an ebuf, or NULL if no packets have been received.
+ ********************************************************************* */
+
+ebuf_t *_udp_recv(udp_info_t *info,int s)
+{
+ ebuf_t *buf;
+ udp_port_t *udp = &(info->ui_ports[s]);
+
+ buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue));
+
+ return buf;
+}
+
+
+/* *********************************************************************
+ * _udp_init(ipi,ref)
+ *
+ * Initialize the UDP module. This routine registers our
+ * protocol with the IP layer.
+ *
+ * Input parameters:
+ * ipi - IP information (including our IP address, etc.)
+ * ref - reference data, stored in our UDP stack structure
+ *
+ * Return value:
+ * udp_info_t (allocated) or NULL if something went wrong.
+ ********************************************************************* */
+
+udp_info_t *_udp_init(ip_info_t *ipi,void *ref)
+{
+ udp_info_t *info;
+ udp_port_t *udp;
+ int idx;
+
+ /*
+ * Allocate some memory for our structure
+ */
+
+ info = KMALLOC(sizeof(udp_info_t),0);
+
+ if (info == NULL) return NULL;
+
+ memset(info,0,sizeof(udp_info_t));
+
+ /*
+ * Fill in the fields.
+ */
+
+ info->ui_ref = ref;
+ info->ui_ipinfo = ipi;
+ udp = info->ui_ports;
+ for (idx = 0; idx < UDP_MAX_PORTS; idx++) {
+ udp->up_inuse = FALSE;
+ q_init(&(udp->up_rxqueue));
+ udp++;
+ }
+
+ /*
+ * Register our protocol with IP
+ */
+
+ _ip_register(ipi,IPPROTO_UDP,_udp_rx_callback,info);
+
+ return info;
+}
+
+
+/* *********************************************************************
+ * _udp_uninit(info)
+ *
+ * Uninitialize the UDP module, deregistering ourselves from the
+ * IP layer.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _udp_uninit(udp_info_t *info)
+{
+ int idx;
+ udp_port_t *udp;
+ ebuf_t *buf;
+
+ /*
+ * Unregister from IP
+ */
+
+ _ip_deregister(info->ui_ipinfo,IPPROTO_UDP);
+
+ /*
+ * Free up any packets that were waiting
+ */
+
+ udp = info->ui_ports;
+ for (idx = 0; idx < UDP_MAX_PORTS; idx++) {
+ if (udp->up_inuse) {
+ while ((buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue)))) {
+ _ip_free(info->ui_ipinfo,buf);
+ }
+ }
+ udp++;
+ }
+
+ /*
+ * Free the stack info
+ */
+
+ KFREE(info);
+}
+
+/* *********************************************************************
+ * _udp_alloc(info)
+ *
+ * Allocate a buffer for use with UDP. This routine obtains an
+ * ebuf and adjusts its header to include room for the UDP
+ * header.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ *
+ * Return value:
+ * ebuf, or NULL if there are none left
+ ********************************************************************* */
+
+ebuf_t *_udp_alloc(udp_info_t *info)
+{
+ ebuf_t *buf;
+
+ /*
+ * Get an ebuf
+ */
+
+ buf = _ip_alloc(info->ui_ipinfo);
+
+ if (!buf) return NULL;
+
+ /*
+ * make room for the udp header
+ */
+
+ ebuf_seek(buf,UDP_HDR_LENGTH);
+ ebuf_setlength(buf,0);
+
+ return buf;
+}
+
+/* *********************************************************************
+ * _udp_free(info,buf)
+ *
+ * Return an ebuf to the pool.
+ *
+ * Input parameters:
+ * info - UDP stack info
+ * buf - an ebuf
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _udp_free(udp_info_t *info,ebuf_t *buf)
+{
+ _ip_free(info->ui_ipinfo,buf);
+}