summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuriyan Ramasami <suriyan.r@gmail.com>2013-10-07 14:53:40 +0400
committerMauro Ribeiro <git@mdrjr.net>2013-10-07 14:53:40 +0400
commita9b472caa6a3427a8f02bac71315a65aee2b0935 (patch)
treef591293c9453b1fc0d7f1b7f47021f57c0730bac
parente724b5b73d44f89e3259dbd35a4bd308ace56472 (diff)
downloadu-boot-a9b472caa6a3427a8f02bac71315a65aee2b0935.tar.xz
[PATCH 1/1] USB Ether Net port
-rw-r--r--Makefile1
-rw-r--r--arch/arm/cpu/armv7/s5p-common/timer.c18
-rw-r--r--common/cmd_elf.c2
-rw-r--r--common/cmd_net.c6
-rw-r--r--common/cmd_nvedit.c15
-rw-r--r--drivers/usb/eth/Makefile33
-rw-r--r--drivers/usb/eth/asix.c702
-rw-r--r--drivers/usb/eth/smsc95xx.c883
-rw-r--r--drivers/usb/eth/usb_ether.c149
-rw-r--r--include/common.h39
-rw-r--r--include/configs/smdk4412.h16
-rw-r--r--include/ide.h4
-rw-r--r--include/linux/ethtool.h725
-rw-r--r--include/linux/mdio.h284
-rw-r--r--include/net.h473
-rw-r--r--include/phy.h229
-rw-r--r--include/usb_ether.h62
-rw-r--r--lib/display_options.c14
-rw-r--r--lib/net_utils.c20
-rw-r--r--net/Makefile24
-rw-r--r--net/arp.c236
-rw-r--r--net/arp.h30
-rw-r--r--net/bootp.c569
-rw-r--r--net/bootp.h60
-rw-r--r--net/cdp.c366
-rw-r--r--net/cdp.h21
-rw-r--r--net/dns.c34
-rw-r--r--net/dns.h5
-rw-r--r--net/eth.c368
-rw-r--r--net/link_local.c345
-rw-r--r--net/link_local.h24
-rw-r--r--net/net.c1609
-rw-r--r--net/net_rand.h43
-rw-r--r--net/nfs.c386
-rw-r--r--net/nfs.h7
-rw-r--r--net/ping.c115
-rw-r--r--net/ping.h31
-rw-r--r--net/rarp.c116
-rw-r--r--net/rarp.h29
-rw-r--r--net/sntp.c40
-rw-r--r--net/sntp.h7
-rw-r--r--net/tftp.c688
-rw-r--r--net/tftp.h11
43 files changed, 6558 insertions, 2281 deletions
diff --git a/Makefile b/Makefile
index 07e75c4c47..5fb3d1f564 100644
--- a/Makefile
+++ b/Makefile
@@ -240,6 +240,7 @@ LIBS += drivers/serial/libserial.o
LIBS += drivers/twserial/libtws.o
LIBS += drivers/usb/gadget/libusb_gadget.o
LIBS += drivers/usb/host/libusb_host.o
+LIBS += drivers/usb/eth/libusb_eth.o
LIBS += drivers/usb/musb/libusb_musb.o
LIBS += drivers/usb/phy/libusb_phy.o
LIBS += drivers/video/libvideo.o
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c
index 2be12bb789..5f5852f40a 100644
--- a/arch/arm/cpu/armv7/s5p-common/timer.c
+++ b/arch/arm/cpu/armv7/s5p-common/timer.c
@@ -107,11 +107,23 @@ void reset_timer(void)
reset_timer_masked();
}
-unsigned long get_timer(unsigned long base)
+unsigned long get_timer_org(unsigned long base)
{
return get_timer_masked() - base;
}
+/*
+ * Suriyan - we are trying to make this function more like a milli second
+ * timer - this is required as most, if not all functions call get_timer
+ * assuming it increments every milli second. If not it create issues with
+ * USB code - EHCI timed out on TD.
+ */
+unsigned long get_timer(unsigned long base)
+{
+ base *= 1000;
+ return (get_timer_masked() - base)/1000;
+}
+
void set_timer(unsigned long t)
{
timestamp = t;
@@ -143,7 +155,7 @@ void __udelay(unsigned long usec)
}
/* get current timestamp */
- tmp = get_timer(0);
+ tmp = get_timer_org(0);
/* if setting this fordward will roll time stamp */
/* reset "advancing" timestamp to 0, set lastdec value */
@@ -188,7 +200,7 @@ unsigned long get_timer_masked(void)
*/
unsigned long long get_ticks(void)
{
- return get_timer(0);
+ return get_timer_org(0);
}
/*
diff --git a/common/cmd_elf.c b/common/cmd_elf.c
index bf3261256f..a2c05128ce 100644
--- a/common/cmd_elf.c
+++ b/common/cmd_elf.c
@@ -133,7 +133,7 @@ int do_bootvx (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/* Check to see if we need to tftp the image ourselves before starting */
if ((argc == 2) && (strcmp (argv[1], "tftp") == 0)) {
- if (NetLoop (TFTP) <= 0)
+ if (NetLoop (TFTPGET) <= 0)
return 1;
printf ("Automatic boot of VxWorks image at address 0x%08lx ... \n",
addr);
diff --git a/common/cmd_net.c b/common/cmd_net.c
index c358859dd8..8b109e4a40 100644
--- a/common/cmd_net.c
+++ b/common/cmd_net.c
@@ -34,7 +34,7 @@ DECLARE_GLOBAL_DATA_PTR;
extern int do_bootm (cmd_tbl_t *, int, int, char * const []);
-static int netboot_common (proto_t, cmd_tbl_t *, int , char * const []);
+static int netboot_common (enum proto_t, cmd_tbl_t *, int , char * const []);
int do_bootp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
@@ -49,7 +49,7 @@ U_BOOT_CMD(
int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- return netboot_common (TFTP, cmdtp, argc, argv);
+ return netboot_common (TFTPGET, cmdtp, argc, argv);
}
U_BOOT_CMD(
@@ -157,7 +157,7 @@ static void netboot_update_env (void)
}
static int
-netboot_common (proto_t proto, cmd_tbl_t *cmdtp, int argc, char * const argv[])
+netboot_common (enum proto_t proto, cmd_tbl_t *cmdtp, int argc, char * const argv[])
{
char *s;
char *end;
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 1b6c2dd56a..9e123e3776 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -351,6 +351,21 @@ int do_env_set (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
/*
+ * Set an environment variable to an value in hex
+ *
+ * @param varname Environment variable to set
+ * @param value Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+int setenv_hex(const char *varname, ulong value)
+{
+ char str[17];
+
+ sprintf(str, "%lx", value);
+ return setenv(varname, str);
+}
+
+/*
* Prompt for environment variable
*/
#if defined(CONFIG_CMD_ASKENV)
diff --git a/drivers/usb/eth/Makefile b/drivers/usb/eth/Makefile
new file mode 100644
index 0000000000..04a8b58c89
--- /dev/null
+++ b/drivers/usb/eth/Makefile
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2011 The Chromium OS Authors.
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libusb_eth.o
+
+# new USB host ethernet layer dependencies
+COBJS-$(CONFIG_USB_HOST_ETHER) += usb_ether.o
+ifdef CONFIG_USB_ETHER_ASIX
+COBJS-y += asix.o
+endif
+COBJS-$(CONFIG_USB_ETHER_SMSC95XX) += smsc95xx.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c
new file mode 100644
index 0000000000..659533a8d4
--- /dev/null
+++ b/drivers/usb/eth/asix.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+#include <malloc.h>
+
+
+/* ASIX AX8817X based USB 2.0 Ethernet Devices */
+
+#define AX_CMD_SET_SW_MII 0x06
+#define AX_CMD_READ_MII_REG 0x07
+#define AX_CMD_WRITE_MII_REG 0x08
+#define AX_CMD_SET_HW_MII 0x0a
+#define AX_CMD_READ_EEPROM 0x0b
+#define AX_CMD_READ_RX_CTL 0x0f
+#define AX_CMD_WRITE_RX_CTL 0x10
+#define AX_CMD_WRITE_IPG0 0x12
+#define AX_CMD_READ_NODE_ID 0x13
+#define AX_CMD_WRITE_NODE_ID 0x14
+#define AX_CMD_READ_PHY_ID 0x19
+#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
+#define AX_CMD_WRITE_GPIOS 0x1f
+#define AX_CMD_SW_RESET 0x20
+#define AX_CMD_SW_PHY_SELECT 0x22
+
+#define AX_SWRESET_CLEAR 0x00
+#define AX_SWRESET_PRTE 0x04
+#define AX_SWRESET_PRL 0x08
+#define AX_SWRESET_IPRL 0x20
+#define AX_SWRESET_IPPD 0x40
+
+#define AX88772_IPG0_DEFAULT 0x15
+#define AX88772_IPG1_DEFAULT 0x0c
+#define AX88772_IPG2_DEFAULT 0x12
+
+/* AX88772 & AX88178 Medium Mode Register */
+#define AX_MEDIUM_PF 0x0080
+#define AX_MEDIUM_JFE 0x0040
+#define AX_MEDIUM_TFC 0x0020
+#define AX_MEDIUM_RFC 0x0010
+#define AX_MEDIUM_ENCK 0x0008
+#define AX_MEDIUM_AC 0x0004
+#define AX_MEDIUM_FD 0x0002
+#define AX_MEDIUM_GM 0x0001
+#define AX_MEDIUM_SM 0x1000
+#define AX_MEDIUM_SBP 0x0800
+#define AX_MEDIUM_PS 0x0200
+#define AX_MEDIUM_RE 0x0100
+
+#define AX88178_MEDIUM_DEFAULT \
+ (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
+ AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
+ AX_MEDIUM_RE)
+
+#define AX88772_MEDIUM_DEFAULT \
+ (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
+ AX_MEDIUM_TFC | AX_MEDIUM_PS | \
+ AX_MEDIUM_AC | AX_MEDIUM_RE)
+
+/* AX88772 & AX88178 RX_CTL values */
+#define AX_RX_CTL_SO 0x0080
+#define AX_RX_CTL_AB 0x0008
+
+#define AX_DEFAULT_RX_CTL \
+ (AX_RX_CTL_SO | AX_RX_CTL_AB)
+
+/* GPIO 2 toggles */
+#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */
+#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */
+#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
+
+/* local defines */
+#define ASIX_BASE_NAME "asx"
+#define USB_CTRL_SET_TIMEOUT 5000
+#define USB_CTRL_GET_TIMEOUT 5000
+#define USB_BULK_SEND_TIMEOUT 5000
+#define USB_BULK_RECV_TIMEOUT 5000
+
+#define AX_RX_URB_SIZE 2048
+#define PHY_CONNECT_TIMEOUT 5000
+
+/* asix_flags defines */
+#define FLAG_NONE 0
+#define FLAG_TYPE_AX88172 (1U << 0)
+#define FLAG_TYPE_AX88772 (1U << 1)
+#define FLAG_TYPE_AX88772B (1U << 2)
+#define FLAG_EEPROM_MAC (1U << 3) /* initial mac address in eeprom */
+
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+
+/* driver private */
+struct asix_private {
+ int flags;
+};
+
+/*
+ * Asix infrastructure commands
+ */
+static int asix_write_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ int len;
+
+ debug("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x "
+ "size=%d\n", cmd, value, index, size);
+
+ len = usb_control_msg(
+ dev->pusb_dev,
+ usb_sndctrlpipe(dev->pusb_dev, 0),
+ cmd,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ data,
+ size,
+ USB_CTRL_SET_TIMEOUT);
+
+ return len == size ? 0 : -1;
+}
+
+static int asix_read_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ int len;
+
+ debug("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+ cmd, value, index, size);
+
+ len = usb_control_msg(
+ dev->pusb_dev,
+ usb_rcvctrlpipe(dev->pusb_dev, 0),
+ cmd,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ data,
+ size,
+ USB_CTRL_GET_TIMEOUT);
+ return len == size ? 0 : -1;
+}
+
+static inline int asix_set_sw_mii(struct ueth_data *dev)
+{
+ int ret;
+
+ ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
+ if (ret < 0)
+ debug("Failed to enable software MII access\n");
+ return ret;
+}
+
+static inline int asix_set_hw_mii(struct ueth_data *dev)
+{
+ int ret;
+
+ ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
+ if (ret < 0)
+ debug("Failed to enable hardware MII access\n");
+ return ret;
+}
+
+static int asix_mdio_read(struct ueth_data *dev, int phy_id, int loc)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(__le16, res, 1);
+
+ asix_set_sw_mii(dev);
+ asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, res);
+ asix_set_hw_mii(dev);
+
+ debug("asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+ phy_id, loc, le16_to_cpu(*res));
+
+ return le16_to_cpu(*res);
+}
+
+static void
+asix_mdio_write(struct ueth_data *dev, int phy_id, int loc, int val)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(__le16, res, 1);
+ *res = cpu_to_le16(val);
+
+ debug("asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+ phy_id, loc, val);
+ asix_set_sw_mii(dev);
+ asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, res);
+ asix_set_hw_mii(dev);
+}
+
+/*
+ * Asix "high level" commands
+ */
+static int asix_sw_reset(struct ueth_data *dev, u8 flags)
+{
+ int ret;
+
+ ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
+ if (ret < 0)
+ debug("Failed to send software reset: %02x\n", ret);
+ else
+ udelay(150 * 1000);
+
+ return ret;
+}
+
+static inline int asix_get_phy_addr(struct ueth_data *dev)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(u8, buf, 2);
+
+ int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
+
+ debug("asix_get_phy_addr()\n");
+
+ if (ret < 0) {
+ debug("Error reading PHYID register: %02x\n", ret);
+ goto out;
+ }
+ debug("asix_get_phy_addr() returning 0x%02x%02x\n", buf[0], buf[1]);
+ ret = buf[1];
+
+out:
+ return ret;
+}
+
+static int asix_write_medium_mode(struct ueth_data *dev, u16 mode)
+{
+ int ret;
+
+ debug("asix_write_medium_mode() - mode = 0x%04x\n", mode);
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode,
+ 0, 0, NULL);
+ if (ret < 0) {
+ debug("Failed to write Medium Mode mode to 0x%04x: %02x\n",
+ mode, ret);
+ }
+ return ret;
+}
+
+static u16 asix_read_rx_ctl(struct ueth_data *dev)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(__le16, v, 1);
+
+ int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, v);
+
+ if (ret < 0)
+ debug("Error reading RX_CTL register: %02x\n", ret);
+ else
+ ret = le16_to_cpu(*v);
+ return ret;
+}
+
+static int asix_write_rx_ctl(struct ueth_data *dev, u16 mode)
+{
+ int ret;
+
+ debug("asix_write_rx_ctl() - mode = 0x%04x\n", mode);
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
+ if (ret < 0) {
+ debug("Failed to write RX_CTL mode to 0x%04x: %02x\n",
+ mode, ret);
+ }
+ return ret;
+}
+
+static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep)
+{
+ int ret;
+
+ debug("asix_write_gpio() - value = 0x%04x\n", value);
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
+ if (ret < 0) {
+ debug("Failed to write GPIO value 0x%04x: %02x\n",
+ value, ret);
+ }
+ if (sleep)
+ udelay(sleep * 1000);
+
+ return ret;
+}
+
+static int asix_write_hwaddr(struct eth_device *eth)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ int ret;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
+
+ memcpy(buf, eth->enetaddr, ETH_ALEN);
+
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf);
+ if (ret < 0)
+ debug("Failed to set MAC address: %02x\n", ret);
+
+ return ret;
+}
+
+/*
+ * mii commands
+ */
+
+/*
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ *
+ * Returns 0 on success, negative on error.
+ */
+static int mii_nway_restart(struct ueth_data *dev)
+{
+ int bmcr;
+ int r = -1;
+
+ /* if autoneg is off, it's an error */
+ bmcr = asix_mdio_read(dev, dev->phy_id, MII_BMCR);
+
+ if (bmcr & BMCR_ANENABLE) {
+ bmcr |= BMCR_ANRESTART;
+ asix_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr);
+ r = 0;
+ }
+
+ return r;
+}
+
+static int asix_read_mac(struct eth_device *eth)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ struct asix_private *priv = (struct asix_private *)dev->dev_priv;
+ int i;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
+
+ if (priv->flags & FLAG_EEPROM_MAC) {
+ for (i = 0; i < (ETH_ALEN >> 1); i++) {
+ if (asix_read_cmd(dev, AX_CMD_READ_EEPROM,
+ 0x04 + i, 0, 2, buf) < 0) {
+ debug("Failed to read SROM address 04h.\n");
+ return -1;
+ }
+ memcpy((eth->enetaddr + i * 2), buf, 2);
+ }
+ } else {
+ if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)
+ < 0) {
+ debug("Failed to read MAC address.\n");
+ return -1;
+ }
+ memcpy(eth->enetaddr, buf, ETH_ALEN);
+ }
+
+ return 0;
+}
+
+static int asix_basic_reset(struct ueth_data *dev)
+{
+ int embd_phy;
+ u16 rx_ctl;
+
+ if (asix_write_gpio(dev,
+ AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5) < 0)
+ return -1;
+
+ /* 0x10 is the phy id of the embedded 10/100 ethernet phy */
+ embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
+ if (asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+ embd_phy, 0, 0, NULL) < 0) {
+ debug("Select PHY #1 failed\n");
+ return -1;
+ }
+
+ if (asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL) < 0)
+ return -1;
+
+ if (asix_sw_reset(dev, AX_SWRESET_CLEAR) < 0)
+ return -1;
+
+ if (embd_phy) {
+ if (asix_sw_reset(dev, AX_SWRESET_IPRL) < 0)
+ return -1;
+ } else {
+ if (asix_sw_reset(dev, AX_SWRESET_PRTE) < 0)
+ return -1;
+ }
+
+ rx_ctl = asix_read_rx_ctl(dev);
+ debug("RX_CTL is 0x%04x after software reset\n", rx_ctl);
+ if (asix_write_rx_ctl(dev, 0x0000) < 0)
+ return -1;
+
+ rx_ctl = asix_read_rx_ctl(dev);
+ debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
+
+ dev->phy_id = asix_get_phy_addr(dev);
+ if (dev->phy_id < 0)
+ debug("Failed to read phy id\n");
+
+ asix_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET);
+ asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA);
+ mii_nway_restart(dev);
+
+ if (asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT) < 0)
+ return -1;
+
+ if (asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
+ AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
+ AX88772_IPG2_DEFAULT, 0, NULL) < 0) {
+ debug("Write IPG,IPG1,IPG2 failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Asix callbacks
+ */
+static int asix_init(struct eth_device *eth, bd_t *bd)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ int timeout = 0;
+#define TIMEOUT_RESOLUTION 50 /* ms */
+ int link_detected;
+
+ debug("** %s()\n", __func__);
+
+ if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0)
+ goto out_err;
+
+ do {
+ link_detected = asix_mdio_read(dev, dev->phy_id, MII_BMSR) &
+ BMSR_LSTATUS;
+ if (!link_detected) {
+ if (timeout == 0)
+ printf("Waiting for Ethernet connection... ");
+ udelay(TIMEOUT_RESOLUTION * 1000);
+ timeout += TIMEOUT_RESOLUTION;
+ }
+ } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+ if (link_detected) {
+ if (timeout != 0)
+ printf("done.\n");
+ } else {
+ printf("unable to connect.\n");
+ goto out_err;
+ }
+
+ return 0;
+out_err:
+ return -1;
+}
+
+static int asix_send(struct eth_device *eth, void *packet, int length)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ int err;
+ u32 packet_len;
+ int actual_len;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg,
+ PKTSIZE + sizeof(packet_len));
+
+ debug("** %s(), len %d\n", __func__, length);
+
+ packet_len = (((length) ^ 0x0000ffff) << 16) + (length);
+ cpu_to_le32s(&packet_len);
+
+ memcpy(msg, &packet_len, sizeof(packet_len));
+ memcpy(msg + sizeof(packet_len), (void *)packet, length);
+ if (length & 1)
+ length++;
+
+ err = usb_bulk_msg(dev->pusb_dev,
+ usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
+ (void *)msg,
+ length + sizeof(packet_len),
+ &actual_len,
+ USB_BULK_SEND_TIMEOUT);
+ debug("Tx: len = %u, actual = %u, err = %d\n",
+ length + sizeof(packet_len), actual_len, err);
+
+ return err;
+}
+
+static int asix_recv(struct eth_device *eth)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE);
+ unsigned char *buf_ptr;
+ int err;
+ int actual_len;
+ u32 packet_len;
+
+ debug("** %s()\n", __func__);
+
+ err = usb_bulk_msg(dev->pusb_dev,
+ usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+ (void *)recv_buf,
+ AX_RX_URB_SIZE,
+ &actual_len,
+ USB_BULK_RECV_TIMEOUT);
+ debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE,
+ actual_len, err);
+ if (err != 0) {
+ debug("Rx: failed to receive\n");
+ return -1;
+ }
+ if (actual_len > AX_RX_URB_SIZE) {
+ debug("Rx: received too many bytes %d\n", actual_len);
+ return -1;
+ }
+
+ buf_ptr = recv_buf;
+ while (actual_len > 0) {
+ /*
+ * 1st 4 bytes contain the length of the actual data as two
+ * complementary 16-bit words. Extract the length of the data.
+ */
+ if (actual_len < sizeof(packet_len)) {
+ debug("Rx: incomplete packet length\n");
+ return -1;
+ }
+ memcpy(&packet_len, buf_ptr, sizeof(packet_len));
+ le32_to_cpus(&packet_len);
+ if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
+ debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
+ packet_len, (~packet_len >> 16) & 0x7ff,
+ packet_len & 0x7ff);
+ return -1;
+ }
+ packet_len = packet_len & 0x7ff;
+ if (packet_len > actual_len - sizeof(packet_len)) {
+ debug("Rx: too large packet: %d\n", packet_len);
+ return -1;
+ }
+
+ /* Notify net stack */
+ NetReceive(buf_ptr + sizeof(packet_len), packet_len);
+
+ /* Adjust for next iteration. Packets are padded to 16-bits */
+ if (packet_len & 1)
+ packet_len++;
+ actual_len -= sizeof(packet_len) + packet_len;
+ buf_ptr += sizeof(packet_len) + packet_len;
+ }
+
+ return err;
+}
+
+static void asix_halt(struct eth_device *eth)
+{
+ debug("** %s()\n", __func__);
+}
+
+/*
+ * Asix probing functions
+ */
+void asix_eth_before_probe(void)
+{
+ curr_eth_dev = 0;
+}
+
+struct asix_dongle {
+ unsigned short vendor;
+ unsigned short product;
+ int flags;
+};
+
+static const struct asix_dongle const asix_dongles[] = {
+ { 0x05ac, 0x1402, FLAG_TYPE_AX88772 }, /* Apple USB Ethernet Adapter */
+ { 0x07d1, 0x3c05, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver B1 */
+ { 0x2001, 0x1a02, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver C1 */
+ /* Cables-to-Go USB Ethernet Adapter */
+ { 0x0b95, 0x772a, FLAG_TYPE_AX88772 },
+ { 0x0b95, 0x7720, FLAG_TYPE_AX88772 }, /* Trendnet TU2-ET100 V3.0R */
+ { 0x0b95, 0x1720, FLAG_TYPE_AX88172 }, /* SMC */
+ { 0x0db0, 0xa877, FLAG_TYPE_AX88772 }, /* MSI - ASIX 88772a */
+ { 0x13b1, 0x0018, FLAG_TYPE_AX88172 }, /* Linksys 200M v2.1 */
+ { 0x1557, 0x7720, FLAG_TYPE_AX88772 }, /* 0Q0 cable ethernet */
+ /* DLink DUB-E100 H/W Ver B1 Alternate */
+ { 0x2001, 0x3c05, FLAG_TYPE_AX88772 },
+ /* ASIX 88772B */
+ { 0x0b95, 0x772b, FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
+ { 0x0000, 0x0000, FLAG_NONE } /* END - Do not remove */
+};
+
+/* Probe to see if a new device is actually an asix device */
+int asix_eth_probe(struct usb_device *dev, unsigned int ifnum,
+ struct ueth_data *ss)
+{
+ struct usb_interface *iface;
+ struct usb_interface_descriptor *iface_desc;
+ int ep_in_found = 0, ep_out_found = 0;
+ int i;
+
+ /* let's examine the device now */
+ iface = &dev->config.if_desc[ifnum];
+ iface_desc = &dev->config.if_desc[ifnum].desc;
+
+ for (i = 0; asix_dongles[i].vendor != 0; i++) {
+ if (dev->descriptor.idVendor == asix_dongles[i].vendor &&
+ dev->descriptor.idProduct == asix_dongles[i].product)
+ /* Found a supported dongle */
+ break;
+ }
+
+ if (asix_dongles[i].vendor == 0)
+ return 0;
+
+ memset(ss, 0, sizeof(struct ueth_data));
+
+ /* At this point, we know we've got a live one */
+ debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+ /* Initialize the ueth_data structure with some useful info */
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+ ss->subclass = iface_desc->bInterfaceSubClass;
+ ss->protocol = iface_desc->bInterfaceProtocol;
+
+ /* alloc driver private */
+ ss->dev_priv = calloc(1, sizeof(struct asix_private));
+ if (!ss->dev_priv)
+ return 0;
+
+ ((struct asix_private *)ss->dev_priv)->flags = asix_dongles[i].flags;
+
+ /*
+ * We are expecting a minimum of 3 endpoints - in, out (bulk), and
+ * int. We will ignore any others.
+ */
+ for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+ /* is it an BULK endpoint? */
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ u8 ep_addr = iface->ep_desc[i].bEndpointAddress;
+ if (ep_addr & USB_DIR_IN) {
+ if (!ep_in_found) {
+ ss->ep_in = ep_addr &
+ USB_ENDPOINT_NUMBER_MASK;
+ ep_in_found = 1;
+ }
+ } else {
+ if (!ep_out_found) {
+ ss->ep_out = ep_addr &
+ USB_ENDPOINT_NUMBER_MASK;
+ ep_out_found = 1;
+ }
+ }
+ }
+
+ /* is it an interrupt endpoint? */
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+ ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ ss->irqinterval = iface->ep_desc[i].bInterval;
+ }
+ }
+ debug("Endpoints In %d Out %d Int %d\n",
+ ss->ep_in, ss->ep_out, ss->ep_int);
+
+ /* Do some basic sanity checks, and bail if we find a problem */
+ if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+ !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+ debug("Problems with device\n");
+ return 0;
+ }
+ dev->privptr = (void *)ss;
+ return 1;
+}
+
+int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+ struct eth_device *eth)
+{
+ struct asix_private *priv = (struct asix_private *)ss->dev_priv;
+
+ if (!eth) {
+ debug("%s: missing parameter.\n", __func__);
+ return 0;
+ }
+ sprintf(eth->name, "%s%d", ASIX_BASE_NAME, curr_eth_dev++);
+ eth->init = asix_init;
+ eth->send = asix_send;
+ eth->recv = asix_recv;
+ eth->halt = asix_halt;
+ if (!(priv->flags & FLAG_TYPE_AX88172))
+ eth->write_hwaddr = asix_write_hwaddr;
+ eth->priv = ss;
+
+ if (asix_basic_reset(ss))
+ return 0;
+
+ /* Get the MAC address */
+ if (asix_read_mac(eth))
+ return 0;
+ debug("MAC %pM\n", eth->enetaddr);
+
+ return 1;
+}
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
new file mode 100644
index 0000000000..15fd9a9f78
--- /dev/null
+++ b/drivers/usb/eth/smsc95xx.c
@@ -0,0 +1,883 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (C) 2009 NVIDIA, Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/unaligned.h>
+#include <common.h>
+#include <usb.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+#include <malloc.h>
+
+/* SMSC LAN95xx based USB 2.0 Ethernet Devices */
+
+/* Tx command words */
+#define TX_CMD_A_FIRST_SEG_ 0x00002000
+#define TX_CMD_A_LAST_SEG_ 0x00001000
+
+/* Rx status word */
+#define RX_STS_FL_ 0x3FFF0000 /* Frame Length */
+#define RX_STS_ES_ 0x00008000 /* Error Summary */
+
+/* SCSRs */
+#define ID_REV 0x00
+
+#define INT_STS 0x08
+
+#define TX_CFG 0x10
+#define TX_CFG_ON_ 0x00000004
+
+#define HW_CFG 0x14
+#define HW_CFG_BIR_ 0x00001000
+#define HW_CFG_RXDOFF_ 0x00000600
+#define HW_CFG_MEF_ 0x00000020
+#define HW_CFG_BCE_ 0x00000002
+#define HW_CFG_LRST_ 0x00000008
+
+#define PM_CTRL 0x20
+#define PM_CTL_PHY_RST_ 0x00000010
+
+#define AFC_CFG 0x2C
+
+/*
+ * Hi watermark = 15.5Kb (~10 mtu pkts)
+ * low watermark = 3k (~2 mtu pkts)
+ * backpressure duration = ~ 350us
+ * Apply FC on any frame.
+ */
+#define AFC_CFG_DEFAULT 0x00F830A1
+
+#define E2P_CMD 0x30
+#define E2P_CMD_BUSY_ 0x80000000
+#define E2P_CMD_READ_ 0x00000000
+#define E2P_CMD_TIMEOUT_ 0x00000400
+#define E2P_CMD_LOADED_ 0x00000200
+#define E2P_CMD_ADDR_ 0x000001FF
+
+#define E2P_DATA 0x34
+
+#define BURST_CAP 0x38
+
+#define INT_EP_CTL 0x68
+#define INT_EP_CTL_PHY_INT_ 0x00008000
+
+#define BULK_IN_DLY 0x6C
+
+/* MAC CSRs */
+#define MAC_CR 0x100
+#define MAC_CR_MCPAS_ 0x00080000
+#define MAC_CR_PRMS_ 0x00040000
+#define MAC_CR_HPFILT_ 0x00002000
+#define MAC_CR_TXEN_ 0x00000008
+#define MAC_CR_RXEN_ 0x00000004
+
+#define ADDRH 0x104
+
+#define ADDRL 0x108
+
+#define MII_ADDR 0x114
+#define MII_WRITE_ 0x02
+#define MII_BUSY_ 0x01
+#define MII_READ_ 0x00 /* ~of MII Write bit */
+
+#define MII_DATA 0x118
+
+#define FLOW 0x11C
+
+#define VLAN1 0x120
+
+#define COE_CR 0x130
+#define Tx_COE_EN_ 0x00010000
+#define Rx_COE_EN_ 0x00000001
+
+/* Vendor-specific PHY Definitions */
+#define PHY_INT_SRC 29
+
+#define PHY_INT_MASK 30
+#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040)
+#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010)
+#define PHY_INT_MASK_DEFAULT_ (PHY_INT_MASK_ANEG_COMP_ | \
+ PHY_INT_MASK_LINK_DOWN_)
+
+/* USB Vendor Requests */
+#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1
+
+/* Some extra defines */
+#define HS_USB_PKT_SIZE 512
+#define FS_USB_PKT_SIZE 64
+#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE)
+#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE)
+#define DEFAULT_BULK_IN_DELAY 0x00002000
+#define MAX_SINGLE_PACKET_SIZE 2048
+#define EEPROM_MAC_OFFSET 0x01
+#define SMSC95XX_INTERNAL_PHY_ID 1
+#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
+
+/* local defines */
+#define SMSC95XX_BASE_NAME "sms"
+#define USB_CTRL_SET_TIMEOUT 5000
+#define USB_CTRL_GET_TIMEOUT 5000
+#define USB_BULK_SEND_TIMEOUT 5000
+#define USB_BULK_RECV_TIMEOUT 5000
+
+#define AX_RX_URB_SIZE 2048
+#define PHY_CONNECT_TIMEOUT 5000
+
+#define TURBO_MODE
+
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+
+/* driver private */
+struct smsc95xx_private {
+ size_t rx_urb_size; /* maximum USB URB size */
+ u32 mac_cr; /* MAC control register value */
+ int have_hwaddr; /* 1 if we have a hardware MAC address */
+};
+
+/*
+ * Smsc95xx infrastructure commands
+ */
+static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data)
+{
+ int len;
+ ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
+
+ cpu_to_le32s(&data);
+ tmpbuf[0] = data;
+
+ len = usb_control_msg(dev->pusb_dev, usb_sndctrlpipe(dev->pusb_dev, 0),
+ USB_VENDOR_REQUEST_WRITE_REGISTER,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 00, index, tmpbuf, sizeof(data), USB_CTRL_SET_TIMEOUT);
+ if (len != sizeof(data)) {
+ debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d",
+ index, data, len);
+ return -1;
+ }
+ return 0;
+}
+
+static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data)
+{
+ int len;
+ ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
+
+ len = usb_control_msg(dev->pusb_dev, usb_rcvctrlpipe(dev->pusb_dev, 0),
+ USB_VENDOR_REQUEST_READ_REGISTER,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 00, index, tmpbuf, sizeof(data), USB_CTRL_GET_TIMEOUT);
+ *data = tmpbuf[0];
+ if (len != sizeof(data)) {
+ debug("smsc95xx_read_reg failed: index=%d, len=%d",
+ index, len);
+ return -1;
+ }
+
+ le32_to_cpus(data);
+ return 0;
+}
+
+/* Loop until the read is completed with timeout */
+static int smsc95xx_phy_wait_not_busy(struct ueth_data *dev)
+{
+ unsigned long start_time = get_timer(0);
+ u32 val;
+
+ do {
+ smsc95xx_read_reg(dev, MII_ADDR, &val);
+ if (!(val & MII_BUSY_))
+ return 0;
+ } while (get_timer(start_time) < 1 * 1000 * 1000);
+
+ return -1;
+}
+
+static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx)
+{
+ u32 val, addr;
+
+ /* confirm MII not busy */
+ if (smsc95xx_phy_wait_not_busy(dev)) {
+ debug("MII is busy in smsc95xx_mdio_read\n");
+ return -1;
+ }
+
+ /* set the address, index & direction (read from PHY) */
+ addr = (phy_id << 11) | (idx << 6) | MII_READ_;
+ smsc95xx_write_reg(dev, MII_ADDR, addr);
+
+ if (smsc95xx_phy_wait_not_busy(dev)) {
+ debug("Timed out reading MII reg %02X\n", idx);
+ return -1;
+ }
+
+ smsc95xx_read_reg(dev, MII_DATA, &val);
+
+ return (u16)(val & 0xFFFF);
+}
+
+static void smsc95xx_mdio_write(struct ueth_data *dev, int phy_id, int idx,
+ int regval)
+{
+ u32 val, addr;
+
+ /* confirm MII not busy */
+ if (smsc95xx_phy_wait_not_busy(dev)) {
+ debug("MII is busy in smsc95xx_mdio_write\n");
+ return;
+ }
+
+ val = regval;
+ smsc95xx_write_reg(dev, MII_DATA, val);
+
+ /* set the address, index & direction (write to PHY) */
+ addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
+ smsc95xx_write_reg(dev, MII_ADDR, addr);
+
+ if (smsc95xx_phy_wait_not_busy(dev))
+ debug("Timed out writing MII reg %02X\n", idx);
+}
+
+static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev)
+{
+ unsigned long start_time = get_timer(0);
+ u32 val;
+
+ do {
+ smsc95xx_read_reg(dev, E2P_CMD, &val);
+ if (!(val & E2P_CMD_BUSY_))
+ return 0;
+ udelay(40);
+ } while (get_timer(start_time) < 1 * 1000 * 1000);
+
+ debug("EEPROM is busy\n");
+ return -1;
+}
+
+static int smsc95xx_wait_eeprom(struct ueth_data *dev)
+{
+ unsigned long start_time = get_timer(0);
+ u32 val;
+
+ do {
+ smsc95xx_read_reg(dev, E2P_CMD, &val);
+ if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
+ break;
+ udelay(40);
+ } while (get_timer(start_time) < 1 * 1000 * 1000);
+
+ if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
+ debug("EEPROM read operation timeout\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length,
+ u8 *data)
+{
+ u32 val;
+ int i, ret;
+
+ ret = smsc95xx_eeprom_confirm_not_busy(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < length; i++) {
+ val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
+ smsc95xx_write_reg(dev, E2P_CMD, val);
+
+ ret = smsc95xx_wait_eeprom(dev);
+ if (ret < 0)
+ return ret;
+
+ smsc95xx_read_reg(dev, E2P_DATA, &val);
+ data[i] = val & 0xFF;
+ offset++;
+ }
+ return 0;
+}
+
+/*
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ *
+ * Returns 0 on success, negative on error.
+ */
+static int mii_nway_restart(struct ueth_data *dev)
+{
+ int bmcr;
+ int r = -1;
+
+ /* if autoneg is off, it's an error */
+ bmcr = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMCR);
+
+ if (bmcr & BMCR_ANENABLE) {
+ bmcr |= BMCR_ANRESTART;
+ smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr);
+ r = 0;
+ }
+ return r;
+}
+
+static int smsc95xx_phy_initialize(struct ueth_data *dev)
+{
+ smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET);
+ smsc95xx_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+
+ /* read to clear */
+ smsc95xx_mdio_read(dev, dev->phy_id, PHY_INT_SRC);
+
+ smsc95xx_mdio_write(dev, dev->phy_id, PHY_INT_MASK,
+ PHY_INT_MASK_DEFAULT_);
+ mii_nway_restart(dev);
+
+ debug("phy initialised succesfully\n");
+ return 0;
+}
+
+static int smsc95xx_init_mac_address(struct eth_device *eth,
+ struct ueth_data *dev)
+{
+ /* try reading mac address from EEPROM */
+ if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
+ eth->enetaddr) == 0) {
+ if (is_valid_ether_addr(eth->enetaddr)) {
+ /* eeprom values are valid so use them */
+ debug("MAC address read from EEPROM\n");
+ return 0;
+ }
+ }
+
+ /*
+ * No eeprom, or eeprom values are invalid. Generating a random MAC
+ * address is not safe. Just return an error.
+ */
+ return -1;
+}
+
+static int smsc95xx_write_hwaddr(struct eth_device *eth)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ struct smsc95xx_private *priv = dev->dev_priv;
+ u32 addr_lo = __get_unaligned_le32(&eth->enetaddr[0]);
+ u32 addr_hi = __get_unaligned_le16(&eth->enetaddr[4]);
+ int ret;
+
+ /* set hardware address */
+ debug("** %s()\n", __func__);
+ ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
+ if (ret < 0)
+ return ret;
+
+ ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
+ if (ret < 0)
+ return ret;
+
+ debug("MAC %pM\n", eth->enetaddr);
+ priv->have_hwaddr = 1;
+ return 0;
+}
+
+/* Enable or disable Tx & Rx checksum offload engines */
+static int smsc95xx_set_csums(struct ueth_data *dev,
+ int use_tx_csum, int use_rx_csum)
+{
+ u32 read_buf;
+ int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
+ if (ret < 0)
+ return ret;
+
+ if (use_tx_csum)
+ read_buf |= Tx_COE_EN_;
+ else
+ read_buf &= ~Tx_COE_EN_;
+
+ if (use_rx_csum)
+ read_buf |= Rx_COE_EN_;
+ else
+ read_buf &= ~Rx_COE_EN_;
+
+ ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
+ if (ret < 0)
+ return ret;
+
+ debug("COE_CR = 0x%08x\n", read_buf);
+ return 0;
+}
+
+static void smsc95xx_set_multicast(struct ueth_data *dev)
+{
+ struct smsc95xx_private *priv = dev->dev_priv;
+
+ /* No multicast in u-boot */
+ priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+}
+
+/* starts the TX path */
+static void smsc95xx_start_tx_path(struct ueth_data *dev)
+{
+ struct smsc95xx_private *priv = dev->dev_priv;
+ u32 reg_val;
+
+ /* Enable Tx at MAC */
+ priv->mac_cr |= MAC_CR_TXEN_;
+
+ smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr);
+
+ /* Enable Tx at SCSRs */
+ reg_val = TX_CFG_ON_;
+ smsc95xx_write_reg(dev, TX_CFG, reg_val);
+}
+
+/* Starts the Receive path */
+static void smsc95xx_start_rx_path(struct ueth_data *dev)
+{
+ struct smsc95xx_private *priv = dev->dev_priv;
+
+ priv->mac_cr |= MAC_CR_RXEN_;
+ smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr);
+}
+
+/*
+ * Smsc95xx callbacks
+ */
+static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
+{
+ int ret;
+ u32 write_buf;
+ u32 read_buf;
+ u32 burst_cap;
+ int timeout;
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ struct smsc95xx_private *priv =
+ (struct smsc95xx_private *)dev->dev_priv;
+#define TIMEOUT_RESOLUTION 50 /* ms */
+ int link_detected;
+
+ debug("** %s()\n", __func__);
+ dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */
+
+ write_buf = HW_CFG_LRST_;
+ ret = smsc95xx_write_reg(dev, HW_CFG, write_buf);
+ if (ret < 0)
+ return ret;
+
+ timeout = 0;
+ do {
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0)
+ return ret;
+ udelay(10 * 1000);
+ timeout++;
+ } while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
+
+ if (timeout >= 100) {
+ debug("timeout waiting for completion of Lite Reset\n");
+ return -1;
+ }
+
+ write_buf = PM_CTL_PHY_RST_;
+ ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf);
+ if (ret < 0)
+ return ret;
+
+ timeout = 0;
+ do {
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
+ if (ret < 0)
+ return ret;
+ udelay(10 * 1000);
+ timeout++;
+ } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
+ if (timeout >= 100) {
+ debug("timeout waiting for PHY Reset\n");
+ return -1;
+ }
+ if (!priv->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0)
+ priv->have_hwaddr = 1;
+ if (!priv->have_hwaddr) {
+ puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n");
+ return -1;
+ }
+ if (smsc95xx_write_hwaddr(eth) < 0)
+ return -1;
+
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0)
+ return ret;
+ debug("Read Value from HW_CFG : 0x%08x\n", read_buf);
+
+ read_buf |= HW_CFG_BIR_;
+ ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+ if (ret < 0)
+ return ret;
+
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0)
+ return ret;
+ debug("Read Value from HW_CFG after writing "
+ "HW_CFG_BIR_: 0x%08x\n", read_buf);
+
+#ifdef TURBO_MODE
+ if (dev->pusb_dev->speed == USB_SPEED_HIGH) {
+ burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
+ priv->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
+ } else {
+ burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
+ priv->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
+ }
+#else
+ burst_cap = 0;
+ priv->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
+#endif
+ debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size);
+
+ ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
+ if (ret < 0)
+ return ret;
+
+ ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
+ if (ret < 0)
+ return ret;
+ debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf);
+
+ read_buf = DEFAULT_BULK_IN_DELAY;
+ ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf);
+ if (ret < 0)
+ return ret;
+
+ ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
+ if (ret < 0)
+ return ret;
+ debug("Read Value from BULK_IN_DLY after writing: "
+ "0x%08x\n", read_buf);
+
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0)
+ return ret;
+ debug("Read Value from HW_CFG: 0x%08x\n", read_buf);
+
+#ifdef TURBO_MODE
+ read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_);
+#endif
+ read_buf &= ~HW_CFG_RXDOFF_;
+
+#define NET_IP_ALIGN 0
+ read_buf |= NET_IP_ALIGN << 9;
+
+ ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+ if (ret < 0)
+ return ret;
+
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0)
+ return ret;
+ debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
+
+ write_buf = 0xFFFFFFFF;
+ ret = smsc95xx_write_reg(dev, INT_STS, write_buf);
+ if (ret < 0)
+ return ret;
+
+ ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
+ if (ret < 0)
+ return ret;
+ debug("ID_REV = 0x%08x\n", read_buf);
+
+ /* Init Tx */
+ write_buf = 0;
+ ret = smsc95xx_write_reg(dev, FLOW, write_buf);
+ if (ret < 0)
+ return ret;
+
+ read_buf = AFC_CFG_DEFAULT;
+ ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf);
+ if (ret < 0)
+ return ret;
+
+ ret = smsc95xx_read_reg(dev, MAC_CR, &priv->mac_cr);
+ if (ret < 0)
+ return ret;
+
+ /* Init Rx. Set Vlan */
+ write_buf = (u32)ETH_P_8021Q;
+ ret = smsc95xx_write_reg(dev, VLAN1, write_buf);
+ if (ret < 0)
+ return ret;
+
+ /* Disable checksum offload engines */
+ ret = smsc95xx_set_csums(dev, 0, 0);
+ if (ret < 0) {
+ debug("Failed to set csum offload: %d\n", ret);
+ return ret;
+ }
+ smsc95xx_set_multicast(dev);
+
+ if (smsc95xx_phy_initialize(dev) < 0)
+ return -1;
+ ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
+ if (ret < 0)
+ return ret;
+
+ /* enable PHY interrupts */
+ read_buf |= INT_EP_CTL_PHY_INT_;
+
+ ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
+ if (ret < 0)
+ return ret;
+
+ smsc95xx_start_tx_path(dev);
+ smsc95xx_start_rx_path(dev);
+
+ timeout = 0;
+ do {
+ link_detected = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMSR)
+ & BMSR_LSTATUS;
+ if (!link_detected) {
+ if (timeout == 0)
+ printf("Waiting for Ethernet connection... ");
+ udelay(TIMEOUT_RESOLUTION * 1000);
+ timeout += TIMEOUT_RESOLUTION;
+ }
+ } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+ if (link_detected) {
+ if (timeout != 0)
+ printf("done.\n");
+ } else {
+ printf("unable to connect.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int smsc95xx_send(struct eth_device *eth, void* packet, int length)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ int err;
+ int actual_len;
+ u32 tx_cmd_a;
+ u32 tx_cmd_b;
+ ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg,
+ PKTSIZE + sizeof(tx_cmd_a) + sizeof(tx_cmd_b));
+
+ debug("** %s(), len %d, buf %#x\n", __func__, length, (int)msg);
+ if (length > PKTSIZE)
+ return -1;
+
+ tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+ tx_cmd_b = (u32)length;
+ cpu_to_le32s(&tx_cmd_a);
+ cpu_to_le32s(&tx_cmd_b);
+
+ /* prepend cmd_a and cmd_b */
+ memcpy(msg, &tx_cmd_a, sizeof(tx_cmd_a));
+ memcpy(msg + sizeof(tx_cmd_a), &tx_cmd_b, sizeof(tx_cmd_b));
+ memcpy(msg + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), (void *)packet,
+ length);
+ err = usb_bulk_msg(dev->pusb_dev,
+ usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
+ (void *)msg,
+ length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b),
+ &actual_len,
+ USB_BULK_SEND_TIMEOUT);
+ debug("Tx: len = %u, actual = %u, err = %d\n",
+ length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b),
+ actual_len, err);
+ return err;
+}
+
+static int smsc95xx_recv(struct eth_device *eth)
+{
+ struct ueth_data *dev = (struct ueth_data *)eth->priv;
+ DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE);
+ unsigned char *buf_ptr;
+ int err;
+ int actual_len;
+ u32 packet_len;
+ int cur_buf_align;
+
+ debug("** %s()\n", __func__);
+ err = usb_bulk_msg(dev->pusb_dev,
+ usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+ (void *)recv_buf,
+ AX_RX_URB_SIZE,
+ &actual_len,
+ USB_BULK_RECV_TIMEOUT);
+ debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE,
+ actual_len, err);
+ if (err != 0) {
+ debug("Rx: failed to receive\n");
+ return -1;
+ }
+ if (actual_len > AX_RX_URB_SIZE) {
+ debug("Rx: received too many bytes %d\n", actual_len);
+ return -1;
+ }
+
+ buf_ptr = recv_buf;
+ while (actual_len > 0) {
+ /*
+ * 1st 4 bytes contain the length of the actual data plus error
+ * info. Extract data length.
+ */
+ if (actual_len < sizeof(packet_len)) {
+ debug("Rx: incomplete packet length\n");
+ return -1;
+ }
+ memcpy(&packet_len, buf_ptr, sizeof(packet_len));
+ le32_to_cpus(&packet_len);
+ if (packet_len & RX_STS_ES_) {
+ debug("Rx: Error header=%#x", packet_len);
+ return -1;
+ }
+ packet_len = ((packet_len & RX_STS_FL_) >> 16);
+
+ if (packet_len > actual_len - sizeof(packet_len)) {
+ debug("Rx: too large packet: %d\n", packet_len);
+ return -1;
+ }
+
+ /* Notify net stack */
+ NetReceive(buf_ptr + sizeof(packet_len), packet_len - 4);
+
+ /* Adjust for next iteration */
+ actual_len -= sizeof(packet_len) + packet_len;
+ buf_ptr += sizeof(packet_len) + packet_len;
+ cur_buf_align = (int)buf_ptr - (int)recv_buf;
+
+ if (cur_buf_align & 0x03) {
+ int align = 4 - (cur_buf_align & 0x03);
+
+ actual_len -= align;
+ buf_ptr += align;
+ }
+ }
+ return err;
+}
+
+static void smsc95xx_halt(struct eth_device *eth)
+{
+ debug("** %s()\n", __func__);
+}
+
+/*
+ * SMSC probing functions
+ */
+void smsc95xx_eth_before_probe(void)
+{
+ curr_eth_dev = 0;
+}
+
+struct smsc95xx_dongle {
+ unsigned short vendor;
+ unsigned short product;
+};
+
+static const struct smsc95xx_dongle smsc95xx_dongles[] = {
+ { 0x0424, 0xec00 }, /* LAN9512/LAN9514 Ethernet */
+ { 0x0424, 0x9500 }, /* LAN9500 Ethernet */
+ { 0x0424, 0x9730 }, /* LAN9730 Ethernet (HSIC) */
+ { 0x0424, 0x9900 }, /* SMSC9500 USB Ethernet Device (SAL10) */
+ { 0x0000, 0x0000 } /* END - Do not remove */
+};
+
+/* Probe to see if a new device is actually an SMSC device */
+int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum,
+ struct ueth_data *ss)
+{
+ struct usb_interface *iface;
+ struct usb_interface_descriptor *iface_desc;
+ int i;
+
+ /* let's examine the device now */
+ iface = &dev->config.if_desc[ifnum];
+ iface_desc = &dev->config.if_desc[ifnum].desc;
+
+ for (i = 0; smsc95xx_dongles[i].vendor != 0; i++) {
+ if (dev->descriptor.idVendor == smsc95xx_dongles[i].vendor &&
+ dev->descriptor.idProduct == smsc95xx_dongles[i].product)
+ /* Found a supported dongle */
+ break;
+ }
+ if (smsc95xx_dongles[i].vendor == 0)
+ return 0;
+
+ /* At this point, we know we've got a live one */
+ debug("\n\nUSB Ethernet device detected\n");
+ memset(ss, '\0', sizeof(struct ueth_data));
+
+ /* Initialize the ueth_data structure with some useful info */
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+ ss->subclass = iface_desc->bInterfaceSubClass;
+ ss->protocol = iface_desc->bInterfaceProtocol;
+
+ /*
+ * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
+ * We will ignore any others.
+ */
+ for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+ /* is it an BULK endpoint? */
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
+ ss->ep_in =
+ iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ else
+ ss->ep_out =
+ iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ }
+
+ /* is it an interrupt endpoint? */
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+ ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ ss->irqinterval = iface->ep_desc[i].bInterval;
+ }
+ }
+ debug("Endpoints In %d Out %d Int %d\n",
+ ss->ep_in, ss->ep_out, ss->ep_int);
+
+ /* Do some basic sanity checks, and bail if we find a problem */
+ if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+ !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+ debug("Problems with device\n");
+ return 0;
+ }
+ dev->privptr = (void *)ss;
+
+ /* alloc driver private */
+ ss->dev_priv = calloc(1, sizeof(struct smsc95xx_private));
+ if (!ss->dev_priv)
+ return 0;
+
+ return 1;
+}
+
+int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+ struct eth_device *eth)
+{
+ debug("** %s()\n", __func__);
+ if (!eth) {
+ debug("%s: missing parameter.\n", __func__);
+ return 0;
+ }
+ sprintf(eth->name, "%s%d", SMSC95XX_BASE_NAME, curr_eth_dev++);
+ eth->init = smsc95xx_init;
+ eth->send = smsc95xx_send;
+ eth->recv = smsc95xx_recv;
+ eth->halt = smsc95xx_halt;
+ eth->write_hwaddr = smsc95xx_write_hwaddr;
+ eth->priv = ss;
+ return 1;
+}
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c
new file mode 100644
index 0000000000..2c4126be36
--- /dev/null
+++ b/drivers/usb/eth/usb_ether.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <usb.h>
+
+#include "usb_ether.h"
+
+typedef void (*usb_eth_before_probe)(void);
+typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum,
+ struct ueth_data *ss);
+typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss,
+ struct eth_device *dev_desc);
+
+struct usb_eth_prob_dev {
+ usb_eth_before_probe before_probe; /* optional */
+ usb_eth_probe probe;
+ usb_eth_get_info get_info;
+};
+
+/* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */
+static const struct usb_eth_prob_dev prob_dev[] = {
+#ifdef CONFIG_USB_ETHER_ASIX
+ {
+ .before_probe = asix_eth_before_probe,
+ .probe = asix_eth_probe,
+ .get_info = asix_eth_get_info,
+ },
+#endif
+#ifdef CONFIG_USB_ETHER_SMSC95XX
+ {
+ .before_probe = smsc95xx_eth_before_probe,
+ .probe = smsc95xx_eth_probe,
+ .get_info = smsc95xx_eth_get_info,
+ },
+#endif
+ { }, /* END */
+};
+
+static int usb_max_eth_dev; /* number of highest available usb eth device */
+static struct ueth_data usb_eth[USB_MAX_ETH_DEV];
+
+/*******************************************************************************
+ * tell if current ethernet device is a usb dongle
+ */
+int is_eth_dev_on_usb_host(void)
+{
+ int i;
+ struct eth_device *dev = eth_get_dev();
+
+ if (dev) {
+ for (i = 0; i < usb_max_eth_dev; i++)
+ if (&usb_eth[i].eth_dev == dev)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Given a USB device, ask each driver if it can support it, and attach it
+ * to the first driver that says 'yes'
+ */
+static void probe_valid_drivers(struct usb_device *dev)
+{
+ struct eth_device *eth;
+ int j;
+
+ for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) {
+ if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev]))
+ continue;
+ /*
+ * ok, it is a supported eth device. Get info and fill it in
+ */
+ eth = &usb_eth[usb_max_eth_dev].eth_dev;
+ if (prob_dev[j].get_info(dev,
+ &usb_eth[usb_max_eth_dev],
+ eth)) {
+ /* found proper driver */
+ /* register with networking stack */
+ usb_max_eth_dev++;
+
+ /*
+ * usb_max_eth_dev must be incremented prior to this
+ * call since eth_current_changed (internally called)
+ * relies on it
+ */
+ eth_register(eth);
+ if (eth_write_hwaddr(eth, "usbeth",
+ usb_max_eth_dev - 1))
+ puts("Warning: failed to set MAC address\n");
+ break;
+ }
+ }
+ }
+
+/*******************************************************************************
+ * scan the usb and reports device info
+ * to the user if mode = 1
+ * returns current device or -1 if no
+ */
+int usb_host_eth_scan(int mode)
+{
+ int i, old_async;
+ struct usb_device *dev;
+
+
+ if (mode == 1)
+ printf(" scanning usb for ethernet devices... ");
+
+ old_async = usb_disable_asynch(1); /* asynch transfer not allowed */
+
+ /* unregister a previously detected device */
+ for (i = 0; i < usb_max_eth_dev; i++)
+ eth_unregister(&usb_eth[i].eth_dev);
+
+ memset(usb_eth, 0, sizeof(usb_eth));
+
+ for (i = 0; prob_dev[i].probe; i++) {
+ if (prob_dev[i].before_probe)
+ prob_dev[i].before_probe();
+ }
+
+ usb_max_eth_dev = 0;
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ dev = usb_get_dev_index(i); /* get device */
+ debug("i=%d\n", i);
+ if (dev == NULL)
+ break; /* no more devices available */
+
+ /* find valid usb_ether driver for this device, if any */
+ probe_valid_drivers(dev);
+
+ /* check limit */
+ if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
+ printf("max USB Ethernet Device reached: %d stopping\n",
+ usb_max_eth_dev);
+ break;
+ }
+ } /* for */
+
+ usb_disable_asynch(old_async); /* restore asynch value */
+ printf("%d Ethernet Device(s) found\n", usb_max_eth_dev);
+ if (usb_max_eth_dev > 0)
+ return 0;
+ return -1;
+}
diff --git a/include/common.h b/include/common.h
index 55f3793208..cb80d83ec8 100644
--- a/include/common.h
+++ b/include/common.h
@@ -116,13 +116,40 @@ typedef volatile unsigned char vu_char;
#include <flash.h>
#include <image.h>
-#ifdef DEBUG
-#define debug(fmt,args...) printf (fmt ,##args)
-#define debugX(level,fmt,args...) if (DEBUG>=level) printf(fmt,##args);
+#ifdef DEBUG
+#define _DEBUG 1
#else
-#define debug(fmt,args...)
-#define debugX(level,fmt,args...)
-#endif /* DEBUG */
+#define _DEBUG 0
+#endif
+
+/*
+ * Output a debug text when condition "cond" is met. The "cond" should be
+ * computed by a preprocessor in the best case, allowing for the best
+ * optimization.
+ */
+#define debug_cond(cond, fmt, args...) \
+ do { \
+ if (cond) \
+ printf(fmt, ##args); \
+ } while (0)
+
+#define debug(fmt, args...) \
+ debug_cond(_DEBUG, fmt, ##args)
+
+/*
+ * An assertion is run-time check done in debug mode only. If DEBUG is not
+ * defined then it is skipped. If DEBUG is defined and the assertion fails,
+ * then it calls panic*( which may or may not reset/halt U-Boot (see
+ * CONFIG_PANIC_HANG), It is hoped that all failing assertions are found
+ * before release, and after release it is hoped that they don't matter. But
+ * in any case these failing assertions cannot be fixed with a reset (which
+ * may just do the same assertion again).
+ */
+void __assert_fail(const char *assertion, const char *file, unsigned line,
+ const char *function);
+#define assert(x) \
+ ({ if (!(x) && _DEBUG) \
+ __assert_fail(#x, __FILE__, __LINE__, __func__); })
#define error(fmt, args...) do { \
printf("ERROR: " fmt "\nat %s:%d/%s()\n", \
diff --git a/include/configs/smdk4412.h b/include/configs/smdk4412.h
index fe04dedd57..0cb606f1a6 100644
--- a/include/configs/smdk4412.h
+++ b/include/configs/smdk4412.h
@@ -468,12 +468,16 @@
/*
* Ethernet Contoller driver
*/
-#ifdef CONFIG_CMD_NET
-#define CONFIG_NET_MULTI
-#define CONFIG_SMC911X
-#define CONFIG_SMC911X_BASE 0x5000000
-#define CONFIG_SMC911X_16_BIT
-#endif /* CONFIG_CMD_NET */
+//#ifdef CONFIG_CMD_NET
+//#define CONFIG_NET_MULTI
+//#define CONFIG_SMC911X
+//#define CONFIG_SMC911X_BASE 0x5000000
+//#define CONFIG_SMC911X_16_BIT
+//#endif /* CONFIG_CMD_NET */
+
+#define CONFIG_CMD_NET
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_SMSC95XX
/* GPIO */
#define GPIO_BASE 0x11000000
diff --git a/include/ide.h b/include/ide.h
index 6a1b7ae844..0256a64973 100644
--- a/include/ide.h
+++ b/include/ide.h
@@ -42,8 +42,12 @@
#ifdef CONFIG_SYS_64BIT_LBA
typedef uint64_t lbaint_t;
+#define LBAF "%llx"
+#define LBAFU "%llu"
#else
typedef ulong lbaint_t;
+#define LBAF "%lx"
+#define LBAFU "%lu"
#endif
/*
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
new file mode 100644
index 0000000000..f6dbdb096d
--- /dev/null
+++ b/include/linux/ethtool.h
@@ -0,0 +1,725 @@
+/*
+ * ethtool.h: Defines for Linux ethtool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ * Copyright 2001 Jeff Garzik <jgarzik@pobox.com>
+ * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
+ * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
+ * christopher.leech@intel.com,
+ * scott.feldman@intel.com)
+ * Portions Copyright (C) Sun Microsystems 2008
+ */
+
+#ifndef _LINUX_ETHTOOL_H
+#define _LINUX_ETHTOOL_H
+
+#include <linux/types.h>
+
+/* This should work for both 32 and 64 bit userland. */
+struct ethtool_cmd {
+ __u32 cmd;
+ __u32 supported; /* Features this interface supports */
+ __u32 advertising; /* Features this interface advertises */
+ __u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */
+ __u8 duplex; /* Duplex, half or full */
+ __u8 port; /* Which connector port */
+ __u8 phy_address;
+ __u8 transceiver; /* Which transceiver to use */
+ __u8 autoneg; /* Enable or disable autonegotiation */
+ __u8 mdio_support;
+ __u32 maxtxpkt; /* Tx pkts before generating tx int */
+ __u32 maxrxpkt; /* Rx pkts before generating rx int */
+ __u16 speed_hi;
+ __u8 eth_tp_mdix;
+ __u8 reserved2;
+ __u32 lp_advertising; /* Features the link partner advertises */
+ __u32 reserved[2];
+};
+
+static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+ __u32 speed)
+{
+
+ ep->speed = (__u16)speed;
+ ep->speed_hi = (__u16)(speed >> 16);
+}
+
+static inline __u32 ethtool_cmd_speed(struct ethtool_cmd *ep)
+{
+ return (ep->speed_hi << 16) | ep->speed;
+}
+
+#define ETHTOOL_FWVERS_LEN 32
+#define ETHTOOL_BUSINFO_LEN 32
+/* these strings are set to whatever the driver author decides... */
+struct ethtool_drvinfo {
+ __u32 cmd;
+ char driver[32]; /* driver short name, "tulip", "eepro100" */
+ char version[32]; /* driver version string */
+ char fw_version[ETHTOOL_FWVERS_LEN]; /* firmware version string */
+ char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
+ /* For PCI devices, use pci_name(pci_dev). */
+ char reserved1[32];
+ char reserved2[12];
+ /*
+ * Some struct members below are filled in
+ * using ops->get_sset_count(). Obtaining
+ * this info from ethtool_drvinfo is now
+ * deprecated; Use ETHTOOL_GSSET_INFO
+ * instead.
+ */
+ __u32 n_priv_flags; /* number of flags valid in ETHTOOL_GPFLAGS */
+ __u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */
+ __u32 testinfo_len;
+ __u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
+ __u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
+};
+
+#define SOPASS_MAX 6
+/* wake-on-lan settings */
+struct ethtool_wolinfo {
+ __u32 cmd;
+ __u32 supported;
+ __u32 wolopts;
+ __u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */
+};
+
+/* for passing single values */
+struct ethtool_value {
+ __u32 cmd;
+ __u32 data;
+};
+
+/* for passing big chunks of data */
+struct ethtool_regs {
+ __u32 cmd;
+ __u32 version; /* driver-specific, indicates different chips/revs */
+ __u32 len; /* bytes */
+ __u8 data[0];
+};
+
+/* for passing EEPROM chunks */
+struct ethtool_eeprom {
+ __u32 cmd;
+ __u32 magic;
+ __u32 offset; /* in bytes */
+ __u32 len; /* in bytes */
+ __u8 data[0];
+};
+
+/* for configuring coalescing parameters of chip */
+struct ethtool_coalesce {
+ __u32 cmd; /* ETHTOOL_{G,S}COALESCE */
+
+ /* How many usecs to delay an RX interrupt after
+ * a packet arrives. If 0, only rx_max_coalesced_frames
+ * is used.
+ */
+ __u32 rx_coalesce_usecs;
+
+ /* How many packets to delay an RX interrupt after
+ * a packet arrives. If 0, only rx_coalesce_usecs is
+ * used. It is illegal to set both usecs and max frames
+ * to zero as this would cause RX interrupts to never be
+ * generated.
+ */
+ __u32 rx_max_coalesced_frames;
+
+ /* Same as above two parameters, except that these values
+ * apply while an IRQ is being serviced by the host. Not
+ * all cards support this feature and the values are ignored
+ * in that case.
+ */
+ __u32 rx_coalesce_usecs_irq;
+ __u32 rx_max_coalesced_frames_irq;
+
+ /* How many usecs to delay a TX interrupt after
+ * a packet is sent. If 0, only tx_max_coalesced_frames
+ * is used.
+ */
+ __u32 tx_coalesce_usecs;
+
+ /* How many packets to delay a TX interrupt after
+ * a packet is sent. If 0, only tx_coalesce_usecs is
+ * used. It is illegal to set both usecs and max frames
+ * to zero as this would cause TX interrupts to never be
+ * generated.
+ */
+ __u32 tx_max_coalesced_frames;
+
+ /* Same as above two parameters, except that these values
+ * apply while an IRQ is being serviced by the host. Not
+ * all cards support this feature and the values are ignored
+ * in that case.
+ */
+ __u32 tx_coalesce_usecs_irq;
+ __u32 tx_max_coalesced_frames_irq;
+
+ /* How many usecs to delay in-memory statistics
+ * block updates. Some drivers do not have an in-memory
+ * statistic block, and in such cases this value is ignored.
+ * This value must not be zero.
+ */
+ __u32 stats_block_coalesce_usecs;
+
+ /* Adaptive RX/TX coalescing is an algorithm implemented by
+ * some drivers to improve latency under low packet rates and
+ * improve throughput under high packet rates. Some drivers
+ * only implement one of RX or TX adaptive coalescing. Anything
+ * not implemented by the driver causes these values to be
+ * silently ignored.
+ */
+ __u32 use_adaptive_rx_coalesce;
+ __u32 use_adaptive_tx_coalesce;
+
+ /* When the packet rate (measured in packets per second)
+ * is below pkt_rate_low, the {rx,tx}_*_low parameters are
+ * used.
+ */
+ __u32 pkt_rate_low;
+ __u32 rx_coalesce_usecs_low;
+ __u32 rx_max_coalesced_frames_low;
+ __u32 tx_coalesce_usecs_low;
+ __u32 tx_max_coalesced_frames_low;
+
+ /* When the packet rate is below pkt_rate_high but above
+ * pkt_rate_low (both measured in packets per second) the
+ * normal {rx,tx}_* coalescing parameters are used.
+ */
+
+ /* When the packet rate is (measured in packets per second)
+ * is above pkt_rate_high, the {rx,tx}_*_high parameters are
+ * used.
+ */
+ __u32 pkt_rate_high;
+ __u32 rx_coalesce_usecs_high;
+ __u32 rx_max_coalesced_frames_high;
+ __u32 tx_coalesce_usecs_high;
+ __u32 tx_max_coalesced_frames_high;
+
+ /* How often to do adaptive coalescing packet rate sampling,
+ * measured in seconds. Must not be zero.
+ */
+ __u32 rate_sample_interval;
+};
+
+/* for configuring RX/TX ring parameters */
+struct ethtool_ringparam {
+ __u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */
+
+ /* Read only attributes. These indicate the maximum number
+ * of pending RX/TX ring entries the driver will allow the
+ * user to set.
+ */
+ __u32 rx_max_pending;
+ __u32 rx_mini_max_pending;
+ __u32 rx_jumbo_max_pending;
+ __u32 tx_max_pending;
+
+ /* Values changeable by the user. The valid values are
+ * in the range 1 to the "*_max_pending" counterpart above.
+ */
+ __u32 rx_pending;
+ __u32 rx_mini_pending;
+ __u32 rx_jumbo_pending;
+ __u32 tx_pending;
+};
+
+/* for configuring link flow control parameters */
+struct ethtool_pauseparam {
+ __u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */
+
+ /* If the link is being auto-negotiated (via ethtool_cmd.autoneg
+ * being true) the user may set 'autonet' here non-zero to have the
+ * pause parameters be auto-negotiated too. In such a case, the
+ * {rx,tx}_pause values below determine what capabilities are
+ * advertised.
+ *
+ * If 'autoneg' is zero or the link is not being auto-negotiated,
+ * then {rx,tx}_pause force the driver to use/not-use pause
+ * flow control.
+ */
+ __u32 autoneg;
+ __u32 rx_pause;
+ __u32 tx_pause;
+};
+
+#define ETH_GSTRING_LEN 32
+enum ethtool_stringset {
+ ETH_SS_TEST = 0,
+ ETH_SS_STATS,
+ ETH_SS_PRIV_FLAGS,
+ ETH_SS_NTUPLE_FILTERS,
+ ETH_SS_FEATURES,
+};
+
+/* for passing string sets for data tagging */
+struct ethtool_gstrings {
+ __u32 cmd; /* ETHTOOL_GSTRINGS */
+ __u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/
+ __u32 len; /* number of strings in the string set */
+ __u8 data[0];
+};
+
+struct ethtool_sset_info {
+ __u32 cmd; /* ETHTOOL_GSSET_INFO */
+ __u32 reserved;
+ __u64 sset_mask; /* input: each bit selects an sset to query */
+ /* output: each bit a returned sset */
+ __u32 data[0]; /* ETH_SS_xxx count, in order, based on bits
+ in sset_mask. One bit implies one
+ __u32, two bits implies two
+ __u32's, etc. */
+};
+
+enum ethtool_test_flags {
+ ETH_TEST_FL_OFFLINE = (1 << 0), /* online / offline */
+ ETH_TEST_FL_FAILED = (1 << 1), /* test passed / failed */
+};
+
+/* for requesting NIC test and getting results*/
+struct ethtool_test {
+ __u32 cmd; /* ETHTOOL_TEST */
+ __u32 flags; /* ETH_TEST_FL_xxx */
+ __u32 reserved;
+ __u32 len; /* result length, in number of u64 elements */
+ __u64 data[0];
+};
+
+/* for dumping NIC-specific statistics */
+struct ethtool_stats {
+ __u32 cmd; /* ETHTOOL_GSTATS */
+ __u32 n_stats; /* number of u64's being returned */
+ __u64 data[0];
+};
+
+struct ethtool_perm_addr {
+ __u32 cmd; /* ETHTOOL_GPERMADDR */
+ __u32 size;
+ __u8 data[0];
+};
+
+/* boolean flags controlling per-interface behavior characteristics.
+ * When reading, the flag indicates whether or not a certain behavior
+ * is enabled/present. When writing, the flag indicates whether
+ * or not the driver should turn on (set) or off (clear) a behavior.
+ *
+ * Some behaviors may read-only (unconditionally absent or present).
+ * If such is the case, return EINVAL in the set-flags operation if the
+ * flag differs from the read-only value.
+ */
+enum ethtool_flags {
+ ETH_FLAG_TXVLAN = (1 << 7), /* TX VLAN offload enabled */
+ ETH_FLAG_RXVLAN = (1 << 8), /* RX VLAN offload enabled */
+ ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */
+ ETH_FLAG_NTUPLE = (1 << 27), /* N-tuple filters enabled */
+ ETH_FLAG_RXHASH = (1 << 28),
+};
+
+/* The following structures are for supporting RX network flow
+ * classification and RX n-tuple configuration. Note, all multibyte
+ * fields, e.g., ip4src, ip4dst, psrc, pdst, spi, etc. are expected to
+ * be in network byte order.
+ */
+
+/**
+ * struct ethtool_tcpip4_spec - flow specification for TCP/IPv4 etc.
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @psrc: Source port
+ * @pdst: Destination port
+ * @tos: Type-of-service
+ *
+ * This can be used to specify a TCP/IPv4, UDP/IPv4 or SCTP/IPv4 flow.
+ */
+struct ethtool_tcpip4_spec {
+ __be32 ip4src;
+ __be32 ip4dst;
+ __be16 psrc;
+ __be16 pdst;
+ __u8 tos;
+};
+
+/**
+ * struct ethtool_ah_espip4_spec - flow specification for IPsec/IPv4
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @spi: Security parameters index
+ * @tos: Type-of-service
+ *
+ * This can be used to specify an IPsec transport or tunnel over IPv4.
+ */
+struct ethtool_ah_espip4_spec {
+ __be32 ip4src;
+ __be32 ip4dst;
+ __be32 spi;
+ __u8 tos;
+};
+
+#define ETH_RX_NFC_IP4 1
+
+/**
+ * struct ethtool_usrip4_spec - general flow specification for IPv4
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @l4_4_bytes: First 4 bytes of transport (layer 4) header
+ * @tos: Type-of-service
+ * @ip_ver: Value must be %ETH_RX_NFC_IP4; mask must be 0
+ * @proto: Transport protocol number; mask must be 0
+ */
+struct ethtool_usrip4_spec {
+ __be32 ip4src;
+ __be32 ip4dst;
+ __be32 l4_4_bytes;
+ __u8 tos;
+ __u8 ip_ver;
+ __u8 proto;
+};
+
+
+/**
+ * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection
+ * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR
+ * @size: On entry, the array size of the user buffer. On return from
+ * %ETHTOOL_GRXFHINDIR, the array size of the hardware indirection table.
+ * @ring_index: RX ring/queue index for each hash value
+ */
+struct ethtool_rxfh_indir {
+ __u32 cmd;
+ __u32 size;
+ __u32 ring_index[0];
+};
+
+#define ETHTOOL_FLASH_MAX_FILENAME 128
+enum ethtool_flash_op_type {
+ ETHTOOL_FLASH_ALL_REGIONS = 0,
+};
+
+/* for passing firmware flashing related parameters */
+struct ethtool_flash {
+ __u32 cmd;
+ __u32 region;
+ char data[ETHTOOL_FLASH_MAX_FILENAME];
+};
+
+/* for returning and changing feature sets */
+
+/**
+ * struct ethtool_get_features_block - block with state of 32 features
+ * @available: mask of changeable features
+ * @requested: mask of features requested to be enabled if possible
+ * @active: mask of currently enabled features
+ * @never_changed: mask of features not changeable for any device
+ */
+struct ethtool_get_features_block {
+ __u32 available;
+ __u32 requested;
+ __u32 active;
+ __u32 never_changed;
+};
+
+/**
+ * struct ethtool_gfeatures - command to get state of device's features
+ * @cmd: command number = %ETHTOOL_GFEATURES
+ * @size: in: number of elements in the features[] array;
+ * out: number of elements in features[] needed to hold all features
+ * @features: state of features
+ */
+struct ethtool_gfeatures {
+ __u32 cmd;
+ __u32 size;
+ struct ethtool_get_features_block features[0];
+};
+
+/**
+ * struct ethtool_set_features_block - block with request for 32 features
+ * @valid: mask of features to be changed
+ * @requested: values of features to be changed
+ */
+struct ethtool_set_features_block {
+ __u32 valid;
+ __u32 requested;
+};
+
+/**
+ * struct ethtool_sfeatures - command to request change in device's features
+ * @cmd: command number = %ETHTOOL_SFEATURES
+ * @size: array size of the features[] array
+ * @features: feature change masks
+ */
+struct ethtool_sfeatures {
+ __u32 cmd;
+ __u32 size;
+ struct ethtool_set_features_block features[0];
+};
+
+/*
+ * %ETHTOOL_SFEATURES changes features present in features[].valid to the
+ * values of corresponding bits in features[].requested. Bits in .requested
+ * not set in .valid or not changeable are ignored.
+ *
+ * Returns %EINVAL when .valid contains undefined or never-changable bits
+ * or size is not equal to required number of features words (32-bit blocks).
+ * Returns >= 0 if request was completed; bits set in the value mean:
+ * %ETHTOOL_F_UNSUPPORTED - there were bits set in .valid that are not
+ * changeable (not present in %ETHTOOL_GFEATURES' features[].available)
+ * those bits were ignored.
+ * %ETHTOOL_F_WISH - some or all changes requested were recorded but the
+ * resulting state of bits masked by .valid is not equal to .requested.
+ * Probably there are other device-specific constraints on some features
+ * in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered
+ * here as though ignored bits were cleared.
+ * %ETHTOOL_F_COMPAT - some or all changes requested were made by calling
+ * compatibility functions. Requested offload state cannot be properly
+ * managed by kernel.
+ *
+ * Meaning of bits in the masks are obtained by %ETHTOOL_GSSET_INFO (number of
+ * bits in the arrays - always multiple of 32) and %ETHTOOL_GSTRINGS commands
+ * for ETH_SS_FEATURES string set. First entry in the table corresponds to least
+ * significant bit in features[0] fields. Empty strings mark undefined features.
+ */
+enum ethtool_sfeatures_retval_bits {
+ ETHTOOL_F_UNSUPPORTED__BIT,
+ ETHTOOL_F_WISH__BIT,
+ ETHTOOL_F_COMPAT__BIT,
+};
+
+#define ETHTOOL_F_UNSUPPORTED (1 << ETHTOOL_F_UNSUPPORTED__BIT)
+#define ETHTOOL_F_WISH (1 << ETHTOOL_F_WISH__BIT)
+#define ETHTOOL_F_COMPAT (1 << ETHTOOL_F_COMPAT__BIT)
+
+/* CMDs currently supported */
+#define ETHTOOL_GSET 0x00000001 /* Get settings. */
+#define ETHTOOL_SSET 0x00000002 /* Set settings. */
+#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
+#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers. */
+#define ETHTOOL_GWOL 0x00000005 /* Get wake-on-lan options. */
+#define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options. */
+#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level. */
+#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation. */
+/* Get link status for host, i.e. whether the interface *and* the
+ * physical port (if there is one) are up (ethtool_value). */
+#define ETHTOOL_GLINK 0x0000000a
+#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data. */
+#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */
+#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config. */
+#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */
+#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters. */
+#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */
+#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters. */
+#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable
+ * (ethtool_value) */
+#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable
+ * (ethtool_value). */
+#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test. */
+#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */
+#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */
+#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */
+#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */
+#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */
+#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */
+#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */
+#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */
+#define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */
+#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */
+#define ETHTOOL_GFLAGS 0x00000025 /* Get flags bitmap(ethtool_value) */
+#define ETHTOOL_SFLAGS 0x00000026 /* Set flags bitmap(ethtool_value) */
+#define ETHTOOL_GPFLAGS 0x00000027 /* Get driver-private flags bitmap */
+#define ETHTOOL_SPFLAGS 0x00000028 /* Set driver-private flags bitmap */
+
+#define ETHTOOL_GRXFH 0x00000029 /* Get RX flow hash configuration */
+#define ETHTOOL_SRXFH 0x0000002a /* Set RX flow hash configuration */
+#define ETHTOOL_GGRO 0x0000002b /* Get GRO enable (ethtool_value) */
+#define ETHTOOL_SGRO 0x0000002c /* Set GRO enable (ethtool_value) */
+#define ETHTOOL_GRXRINGS 0x0000002d /* Get RX rings available for LB */
+#define ETHTOOL_GRXCLSRLCNT 0x0000002e /* Get RX class rule count */
+#define ETHTOOL_GRXCLSRULE 0x0000002f /* Get RX classification rule */
+#define ETHTOOL_GRXCLSRLALL 0x00000030 /* Get all RX classification rule */
+#define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */
+#define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */
+#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */
+#define ETHTOOL_RESET 0x00000034 /* Reset hardware */
+#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */
+#define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */
+#define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */
+#define ETHTOOL_GRXFHINDIR 0x00000038 /* Get RX flow hash indir'n table */
+#define ETHTOOL_SRXFHINDIR 0x00000039 /* Set RX flow hash indir'n table */
+
+#define ETHTOOL_GFEATURES 0x0000003a /* Get device offload settings */
+#define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */
+
+/* compatibility with older code */
+#define SPARC_ETH_GSET ETHTOOL_GSET
+#define SPARC_ETH_SSET ETHTOOL_SSET
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half (1 << 0)
+#define SUPPORTED_10baseT_Full (1 << 1)
+#define SUPPORTED_100baseT_Half (1 << 2)
+#define SUPPORTED_100baseT_Full (1 << 3)
+#define SUPPORTED_1000baseT_Half (1 << 4)
+#define SUPPORTED_1000baseT_Full (1 << 5)
+#define SUPPORTED_Autoneg (1 << 6)
+#define SUPPORTED_TP (1 << 7)
+#define SUPPORTED_AUI (1 << 8)
+#define SUPPORTED_MII (1 << 9)
+#define SUPPORTED_FIBRE (1 << 10)
+#define SUPPORTED_BNC (1 << 11)
+#define SUPPORTED_10000baseT_Full (1 << 12)
+#define SUPPORTED_Pause (1 << 13)
+#define SUPPORTED_Asym_Pause (1 << 14)
+#define SUPPORTED_2500baseX_Full (1 << 15)
+#define SUPPORTED_Backplane (1 << 16)
+#define SUPPORTED_1000baseKX_Full (1 << 17)
+#define SUPPORTED_10000baseKX4_Full (1 << 18)
+#define SUPPORTED_10000baseKR_Full (1 << 19)
+#define SUPPORTED_10000baseR_FEC (1 << 20)
+#define SUPPORTED_1000baseX_Half (1 << 21)
+#define SUPPORTED_1000baseX_Full (1 << 22)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half (1 << 0)
+#define ADVERTISED_10baseT_Full (1 << 1)
+#define ADVERTISED_100baseT_Half (1 << 2)
+#define ADVERTISED_100baseT_Full (1 << 3)
+#define ADVERTISED_1000baseT_Half (1 << 4)
+#define ADVERTISED_1000baseT_Full (1 << 5)
+#define ADVERTISED_Autoneg (1 << 6)
+#define ADVERTISED_TP (1 << 7)
+#define ADVERTISED_AUI (1 << 8)
+#define ADVERTISED_MII (1 << 9)
+#define ADVERTISED_FIBRE (1 << 10)
+#define ADVERTISED_BNC (1 << 11)
+#define ADVERTISED_10000baseT_Full (1 << 12)
+#define ADVERTISED_Pause (1 << 13)
+#define ADVERTISED_Asym_Pause (1 << 14)
+#define ADVERTISED_2500baseX_Full (1 << 15)
+#define ADVERTISED_Backplane (1 << 16)
+#define ADVERTISED_1000baseKX_Full (1 << 17)
+#define ADVERTISED_10000baseKX4_Full (1 << 18)
+#define ADVERTISED_10000baseKR_Full (1 << 19)
+#define ADVERTISED_10000baseR_FEC (1 << 20)
+#define ADVERTISED_1000baseX_Half (1 << 21)
+#define ADVERTISED_1000baseX_Full (1 << 22)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things. When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define SPEED_2500 2500
+#define SPEED_10000 10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF 0x00
+#define DUPLEX_FULL 0x01
+
+/* Which connector port. */
+#define PORT_TP 0x00
+#define PORT_AUI 0x01
+#define PORT_MII 0x02
+#define PORT_FIBRE 0x03
+#define PORT_BNC 0x04
+#define PORT_DA 0x05
+#define PORT_NONE 0xef
+#define PORT_OTHER 0xff
+
+/* Which transceiver to use. */
+#define XCVR_INTERNAL 0x00
+#define XCVR_EXTERNAL 0x01
+#define XCVR_DUMMY1 0x02
+#define XCVR_DUMMY2 0x03
+#define XCVR_DUMMY3 0x04
+
+/* Enable or disable autonegotiation. If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+/* Mode MDI or MDI-X */
+#define ETH_TP_MDI_INVALID 0x00
+#define ETH_TP_MDI 0x01
+#define ETH_TP_MDI_X 0x02
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY (1 << 0)
+#define WAKE_UCAST (1 << 1)
+#define WAKE_MCAST (1 << 2)
+#define WAKE_BCAST (1 << 3)
+#define WAKE_ARP (1 << 4)
+#define WAKE_MAGIC (1 << 5)
+#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
+
+/* L2-L4 network traffic flow types */
+#define TCP_V4_FLOW 0x01 /* hash or spec (tcp_ip4_spec) */
+#define UDP_V4_FLOW 0x02 /* hash or spec (udp_ip4_spec) */
+#define SCTP_V4_FLOW 0x03 /* hash or spec (sctp_ip4_spec) */
+#define AH_ESP_V4_FLOW 0x04 /* hash only */
+#define TCP_V6_FLOW 0x05 /* hash only */
+#define UDP_V6_FLOW 0x06 /* hash only */
+#define SCTP_V6_FLOW 0x07 /* hash only */
+#define AH_ESP_V6_FLOW 0x08 /* hash only */
+#define AH_V4_FLOW 0x09 /* hash or spec (ah_ip4_spec) */
+#define ESP_V4_FLOW 0x0a /* hash or spec (esp_ip4_spec) */
+#define AH_V6_FLOW 0x0b /* hash only */
+#define ESP_V6_FLOW 0x0c /* hash only */
+#define IP_USER_FLOW 0x0d /* spec only (usr_ip4_spec) */
+#define IPV4_FLOW 0x10 /* hash only */
+#define IPV6_FLOW 0x11 /* hash only */
+#define ETHER_FLOW 0x12 /* spec only (ether_spec) */
+
+/* L3-L4 network traffic flow hash options */
+#define RXH_L2DA (1 << 1)
+#define RXH_VLAN (1 << 2)
+#define RXH_L3_PROTO (1 << 3)
+#define RXH_IP_SRC (1 << 4)
+#define RXH_IP_DST (1 << 5)
+#define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */
+#define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */
+#define RXH_DISCARD (1 << 31)
+
+#define RX_CLS_FLOW_DISC 0xffffffffffffffffULL
+
+/* Reset flags */
+/* The reset() operation must clear the flags for the components which
+ * were actually reset. On successful return, the flags indicate the
+ * components which were not reset, either because they do not exist
+ * in the hardware or because they cannot be reset independently. The
+ * driver must never reset any components that were not requested.
+ */
+enum ethtool_reset_flags {
+ /* These flags represent components dedicated to the interface
+ * the command is addressed to. Shift any flag left by
+ * ETH_RESET_SHARED_SHIFT to reset a shared component of the
+ * same type.
+ */
+ ETH_RESET_MGMT = 1 << 0, /* Management processor */
+ ETH_RESET_IRQ = 1 << 1, /* Interrupt requester */
+ ETH_RESET_DMA = 1 << 2, /* DMA engine */
+ ETH_RESET_FILTER = 1 << 3, /* Filtering/flow direction */
+ ETH_RESET_OFFLOAD = 1 << 4, /* Protocol offload */
+ ETH_RESET_MAC = 1 << 5, /* Media access controller */
+ ETH_RESET_PHY = 1 << 6, /* Transceiver/PHY */
+ ETH_RESET_RAM = 1 << 7, /* RAM shared between
+ * multiple components */
+
+ ETH_RESET_DEDICATED = 0x0000ffff, /* All components dedicated to
+ * this interface */
+ ETH_RESET_ALL = 0xffffffff, /* All components used by this
+ * interface, even if shared */
+};
+#define ETH_RESET_SHARED_SHIFT 16
+
+#endif /* _LINUX_ETHTOOL_H */
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
new file mode 100644
index 0000000000..ea20608463
--- /dev/null
+++ b/include/linux/mdio.h
@@ -0,0 +1,284 @@
+/*
+ * linux/mdio.h: definitions for MDIO (clause 45) transceivers
+ * Copyright 2006-2009 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef __LINUX_MDIO_H__
+#define __LINUX_MDIO_H__
+
+#include <linux/mii.h>
+
+/* MDIO Manageable Devices (MMDs). */
+#define MDIO_MMD_PMAPMD 1 /* Physical Medium Attachment/
+ * Physical Medium Dependent */
+#define MDIO_MMD_WIS 2 /* WAN Interface Sublayer */
+#define MDIO_MMD_PCS 3 /* Physical Coding Sublayer */
+#define MDIO_MMD_PHYXS 4 /* PHY Extender Sublayer */
+#define MDIO_MMD_DTEXS 5 /* DTE Extender Sublayer */
+#define MDIO_MMD_TC 6 /* Transmission Convergence */
+#define MDIO_MMD_AN 7 /* Auto-Negotiation */
+#define MDIO_MMD_C22EXT 29 /* Clause 22 extension */
+#define MDIO_MMD_VEND1 30 /* Vendor specific 1 */
+#define MDIO_MMD_VEND2 31 /* Vendor specific 2 */
+
+/* Generic MDIO registers. */
+#define MDIO_CTRL1 MII_BMCR
+#define MDIO_STAT1 MII_BMSR
+#define MDIO_DEVID1 MII_PHYSID1
+#define MDIO_DEVID2 MII_PHYSID2
+#define MDIO_SPEED 4 /* Speed ability */
+#define MDIO_DEVS1 5 /* Devices in package */
+#define MDIO_DEVS2 6
+#define MDIO_CTRL2 7 /* 10G control 2 */
+#define MDIO_STAT2 8 /* 10G status 2 */
+#define MDIO_PMA_TXDIS 9 /* 10G PMA/PMD transmit disable */
+#define MDIO_PMA_RXDET 10 /* 10G PMA/PMD receive signal detect */
+#define MDIO_PMA_EXTABLE 11 /* 10G PMA/PMD extended ability */
+#define MDIO_PKGID1 14 /* Package identifier */
+#define MDIO_PKGID2 15
+#define MDIO_AN_ADVERTISE 16 /* AN advertising (base page) */
+#define MDIO_AN_LPA 19 /* AN LP abilities (base page) */
+#define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */
+
+/* Media-dependent registers. */
+#define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */
+#define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */
+#define MDIO_PMA_10GBT_SNR 133 /* 10GBASE-T SNR margin, lane A.
+ * Lanes B-D are numbered 134-136. */
+#define MDIO_PMA_10GBR_FECABLE 170 /* 10GBASE-R FEC ability */
+#define MDIO_PCS_10GBX_STAT1 24 /* 10GBASE-X PCS status 1 */
+#define MDIO_PCS_10GBRT_STAT1 32 /* 10GBASE-R/-T PCS status 1 */
+#define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */
+#define MDIO_AN_10GBT_CTRL 32 /* 10GBASE-T auto-negotiation control */
+#define MDIO_AN_10GBT_STAT 33 /* 10GBASE-T auto-negotiation status */
+#define MDIO_AN_EEE_ADV 60 /* EEE advertisement */
+
+/* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */
+#define MDIO_PMA_LASI_RXCTRL 0x9000 /* RX_ALARM control */
+#define MDIO_PMA_LASI_TXCTRL 0x9001 /* TX_ALARM control */
+#define MDIO_PMA_LASI_CTRL 0x9002 /* LASI control */
+#define MDIO_PMA_LASI_RXSTAT 0x9003 /* RX_ALARM status */
+#define MDIO_PMA_LASI_TXSTAT 0x9004 /* TX_ALARM status */
+#define MDIO_PMA_LASI_STAT 0x9005 /* LASI status */
+
+/* Control register 1. */
+/* Enable extended speed selection */
+#define MDIO_CTRL1_SPEEDSELEXT (BMCR_SPEED1000 | BMCR_SPEED100)
+/* All speed selection bits */
+#define MDIO_CTRL1_SPEEDSEL (MDIO_CTRL1_SPEEDSELEXT | 0x003c)
+#define MDIO_CTRL1_FULLDPLX BMCR_FULLDPLX
+#define MDIO_CTRL1_LPOWER BMCR_PDOWN
+#define MDIO_CTRL1_RESET BMCR_RESET
+#define MDIO_PMA_CTRL1_LOOPBACK 0x0001
+#define MDIO_PMA_CTRL1_SPEED1000 BMCR_SPEED1000
+#define MDIO_PMA_CTRL1_SPEED100 BMCR_SPEED100
+#define MDIO_PCS_CTRL1_LOOPBACK BMCR_LOOPBACK
+#define MDIO_PHYXS_CTRL1_LOOPBACK BMCR_LOOPBACK
+#define MDIO_AN_CTRL1_RESTART BMCR_ANRESTART
+#define MDIO_AN_CTRL1_ENABLE BMCR_ANENABLE
+#define MDIO_AN_CTRL1_XNP 0x2000 /* Enable extended next page */
+
+/* 10 Gb/s */
+#define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00)
+/* 10PASS-TS/2BASE-TL */
+#define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04)
+
+/* Status register 1. */
+#define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */
+#define MDIO_STAT1_LSTATUS BMSR_LSTATUS
+#define MDIO_STAT1_FAULT 0x0080 /* Fault */
+#define MDIO_AN_STAT1_LPABLE 0x0001 /* Link partner AN ability */
+#define MDIO_AN_STAT1_ABLE BMSR_ANEGCAPABLE
+#define MDIO_AN_STAT1_RFAULT BMSR_RFAULT
+#define MDIO_AN_STAT1_COMPLETE BMSR_ANEGCOMPLETE
+#define MDIO_AN_STAT1_PAGE 0x0040 /* Page received */
+#define MDIO_AN_STAT1_XNP 0x0080 /* Extended next page status */
+
+/* Speed register. */
+#define MDIO_SPEED_10G 0x0001 /* 10G capable */
+#define MDIO_PMA_SPEED_2B 0x0002 /* 2BASE-TL capable */
+#define MDIO_PMA_SPEED_10P 0x0004 /* 10PASS-TS capable */
+#define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */
+#define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */
+#define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */
+#define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */
+
+/* Device present registers. */
+#define MDIO_DEVS_PRESENT(devad) (1 << (devad))
+#define MDIO_DEVS_PMAPMD MDIO_DEVS_PRESENT(MDIO_MMD_PMAPMD)
+#define MDIO_DEVS_WIS MDIO_DEVS_PRESENT(MDIO_MMD_WIS)
+#define MDIO_DEVS_PCS MDIO_DEVS_PRESENT(MDIO_MMD_PCS)
+#define MDIO_DEVS_PHYXS MDIO_DEVS_PRESENT(MDIO_MMD_PHYXS)
+#define MDIO_DEVS_DTEXS MDIO_DEVS_PRESENT(MDIO_MMD_DTEXS)
+#define MDIO_DEVS_TC MDIO_DEVS_PRESENT(MDIO_MMD_TC)
+#define MDIO_DEVS_AN MDIO_DEVS_PRESENT(MDIO_MMD_AN)
+#define MDIO_DEVS_C22EXT MDIO_DEVS_PRESENT(MDIO_MMD_C22EXT)
+#define MDIO_DEVS_VEND1 MDIO_DEVS_PRESENT(MDIO_MMD_VEND1)
+#define MDIO_DEVS_VEND2 MDIO_DEVS_PRESENT(MDIO_MMD_VEND2)
+
+#define MDIO_DEVS_LINK (MDIO_DEVS_PMAPMD | \
+ MDIO_DEVS_WIS | \
+ MDIO_DEVS_PCS | \
+ MDIO_DEVS_PHYXS | \
+ MDIO_DEVS_DTEXS | \
+ MDIO_DEVS_AN)
+
+/* Control register 2. */
+#define MDIO_PMA_CTRL2_TYPE 0x000f /* PMA/PMD type selection */
+#define MDIO_PMA_CTRL2_10GBCX4 0x0000 /* 10GBASE-CX4 type */
+#define MDIO_PMA_CTRL2_10GBEW 0x0001 /* 10GBASE-EW type */
+#define MDIO_PMA_CTRL2_10GBLW 0x0002 /* 10GBASE-LW type */
+#define MDIO_PMA_CTRL2_10GBSW 0x0003 /* 10GBASE-SW type */
+#define MDIO_PMA_CTRL2_10GBLX4 0x0004 /* 10GBASE-LX4 type */
+#define MDIO_PMA_CTRL2_10GBER 0x0005 /* 10GBASE-ER type */
+#define MDIO_PMA_CTRL2_10GBLR 0x0006 /* 10GBASE-LR type */
+#define MDIO_PMA_CTRL2_10GBSR 0x0007 /* 10GBASE-SR type */
+#define MDIO_PMA_CTRL2_10GBLRM 0x0008 /* 10GBASE-LRM type */
+#define MDIO_PMA_CTRL2_10GBT 0x0009 /* 10GBASE-T type */
+#define MDIO_PMA_CTRL2_10GBKX4 0x000a /* 10GBASE-KX4 type */
+#define MDIO_PMA_CTRL2_10GBKR 0x000b /* 10GBASE-KR type */
+#define MDIO_PMA_CTRL2_1000BT 0x000c /* 1000BASE-T type */
+#define MDIO_PMA_CTRL2_1000BKX 0x000d /* 1000BASE-KX type */
+#define MDIO_PMA_CTRL2_100BTX 0x000e /* 100BASE-TX type */
+#define MDIO_PMA_CTRL2_10BT 0x000f /* 10BASE-T type */
+#define MDIO_PCS_CTRL2_TYPE 0x0003 /* PCS type selection */
+#define MDIO_PCS_CTRL2_10GBR 0x0000 /* 10GBASE-R type */
+#define MDIO_PCS_CTRL2_10GBX 0x0001 /* 10GBASE-X type */
+#define MDIO_PCS_CTRL2_10GBW 0x0002 /* 10GBASE-W type */
+#define MDIO_PCS_CTRL2_10GBT 0x0003 /* 10GBASE-T type */
+
+/* Status register 2. */
+#define MDIO_STAT2_RXFAULT 0x0400 /* Receive fault */
+#define MDIO_STAT2_TXFAULT 0x0800 /* Transmit fault */
+#define MDIO_STAT2_DEVPRST 0xc000 /* Device present */
+#define MDIO_STAT2_DEVPRST_VAL 0x8000 /* Device present value */
+#define MDIO_PMA_STAT2_LBABLE 0x0001 /* PMA loopback ability */
+#define MDIO_PMA_STAT2_10GBEW 0x0002 /* 10GBASE-EW ability */
+#define MDIO_PMA_STAT2_10GBLW 0x0004 /* 10GBASE-LW ability */
+#define MDIO_PMA_STAT2_10GBSW 0x0008 /* 10GBASE-SW ability */
+#define MDIO_PMA_STAT2_10GBLX4 0x0010 /* 10GBASE-LX4 ability */
+#define MDIO_PMA_STAT2_10GBER 0x0020 /* 10GBASE-ER ability */
+#define MDIO_PMA_STAT2_10GBLR 0x0040 /* 10GBASE-LR ability */
+#define MDIO_PMA_STAT2_10GBSR 0x0080 /* 10GBASE-SR ability */
+#define MDIO_PMD_STAT2_TXDISAB 0x0100 /* PMD TX disable ability */
+#define MDIO_PMA_STAT2_EXTABLE 0x0200 /* Extended abilities */
+#define MDIO_PMA_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */
+#define MDIO_PMA_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */
+#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R capable */
+#define MDIO_PCS_STAT2_10GBX 0x0002 /* 10GBASE-X capable */
+#define MDIO_PCS_STAT2_10GBW 0x0004 /* 10GBASE-W capable */
+#define MDIO_PCS_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */
+#define MDIO_PCS_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */
+
+/* Transmit disable register. */
+#define MDIO_PMD_TXDIS_GLOBAL 0x0001 /* Global PMD TX disable */
+#define MDIO_PMD_TXDIS_0 0x0002 /* PMD TX disable 0 */
+#define MDIO_PMD_TXDIS_1 0x0004 /* PMD TX disable 1 */
+#define MDIO_PMD_TXDIS_2 0x0008 /* PMD TX disable 2 */
+#define MDIO_PMD_TXDIS_3 0x0010 /* PMD TX disable 3 */
+
+/* Receive signal detect register. */
+#define MDIO_PMD_RXDET_GLOBAL 0x0001 /* Global PMD RX signal detect */
+#define MDIO_PMD_RXDET_0 0x0002 /* PMD RX signal detect 0 */
+#define MDIO_PMD_RXDET_1 0x0004 /* PMD RX signal detect 1 */
+#define MDIO_PMD_RXDET_2 0x0008 /* PMD RX signal detect 2 */
+#define MDIO_PMD_RXDET_3 0x0010 /* PMD RX signal detect 3 */
+
+/* Extended abilities register. */
+#define MDIO_PMA_EXTABLE_10GCX4 0x0001 /* 10GBASE-CX4 ability */
+#define MDIO_PMA_EXTABLE_10GBLRM 0x0002 /* 10GBASE-LRM ability */
+#define MDIO_PMA_EXTABLE_10GBT 0x0004 /* 10GBASE-T ability */
+#define MDIO_PMA_EXTABLE_10GBKX4 0x0008 /* 10GBASE-KX4 ability */
+#define MDIO_PMA_EXTABLE_10GBKR 0x0010 /* 10GBASE-KR ability */
+#define MDIO_PMA_EXTABLE_1000BT 0x0020 /* 1000BASE-T ability */
+#define MDIO_PMA_EXTABLE_1000BKX 0x0040 /* 1000BASE-KX ability */
+#define MDIO_PMA_EXTABLE_100BTX 0x0080 /* 100BASE-TX ability */
+#define MDIO_PMA_EXTABLE_10BT 0x0100 /* 10BASE-T ability */
+
+/* PHY XGXS lane state register. */
+#define MDIO_PHYXS_LNSTAT_SYNC0 0x0001
+#define MDIO_PHYXS_LNSTAT_SYNC1 0x0002
+#define MDIO_PHYXS_LNSTAT_SYNC2 0x0004
+#define MDIO_PHYXS_LNSTAT_SYNC3 0x0008
+#define MDIO_PHYXS_LNSTAT_ALIGN 0x1000
+
+/* PMA 10GBASE-T pair swap & polarity */
+#define MDIO_PMA_10GBT_SWAPPOL_ABNX 0x0001 /* Pair A/B uncrossed */
+#define MDIO_PMA_10GBT_SWAPPOL_CDNX 0x0002 /* Pair C/D uncrossed */
+#define MDIO_PMA_10GBT_SWAPPOL_AREV 0x0100 /* Pair A polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_BREV 0x0200 /* Pair B polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_CREV 0x0400 /* Pair C polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_DREV 0x0800 /* Pair D polarity reversed */
+
+/* PMA 10GBASE-T TX power register. */
+#define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */
+
+/* PMA 10GBASE-T SNR registers. */
+/* Value is SNR margin in dB, clamped to range [-127, 127], plus 0x8000. */
+#define MDIO_PMA_10GBT_SNR_BIAS 0x8000
+#define MDIO_PMA_10GBT_SNR_MAX 127
+
+/* PMA 10GBASE-R FEC ability register. */
+#define MDIO_PMA_10GBR_FECABLE_ABLE 0x0001 /* FEC ability */
+#define MDIO_PMA_10GBR_FECABLE_ERRABLE 0x0002 /* FEC error indic. ability */
+
+/* PCS 10GBASE-R/-T status register 1. */
+#define MDIO_PCS_10GBRT_STAT1_BLKLK 0x0001 /* Block lock attained */
+
+/* PCS 10GBASE-R/-T status register 2. */
+#define MDIO_PCS_10GBRT_STAT2_ERR 0x00ff
+#define MDIO_PCS_10GBRT_STAT2_BER 0x3f00
+
+/* AN 10GBASE-T control register. */
+#define MDIO_AN_10GBT_CTRL_ADV10G 0x1000 /* Advertise 10GBASE-T */
+
+/* AN 10GBASE-T status register. */
+#define MDIO_AN_10GBT_STAT_LPTRR 0x0200 /* LP training reset req. */
+#define MDIO_AN_10GBT_STAT_LPLTABLE 0x0400 /* LP loop timing ability */
+#define MDIO_AN_10GBT_STAT_LP10G 0x0800 /* LP is 10GBT capable */
+#define MDIO_AN_10GBT_STAT_REMOK 0x1000 /* Remote OK */
+#define MDIO_AN_10GBT_STAT_LOCOK 0x2000 /* Local OK */
+#define MDIO_AN_10GBT_STAT_MS 0x4000 /* Master/slave config */
+#define MDIO_AN_10GBT_STAT_MSFLT 0x8000 /* Master/slave config fault */
+
+/* AN EEE Advertisement register. */
+#define MDIO_AN_EEE_ADV_100TX 0x0002 /* Advertise 100TX EEE cap */
+#define MDIO_AN_EEE_ADV_1000T 0x0004 /* Advertise 1000T EEE cap */
+
+/* LASI RX_ALARM control/status registers. */
+#define MDIO_PMA_LASI_RX_PHYXSLFLT 0x0001 /* PHY XS RX local fault */
+#define MDIO_PMA_LASI_RX_PCSLFLT 0x0008 /* PCS RX local fault */
+#define MDIO_PMA_LASI_RX_PMALFLT 0x0010 /* PMA/PMD RX local fault */
+#define MDIO_PMA_LASI_RX_OPTICPOWERFLT 0x0020 /* RX optical power fault */
+#define MDIO_PMA_LASI_RX_WISLFLT 0x0200 /* WIS local fault */
+
+/* LASI TX_ALARM control/status registers. */
+#define MDIO_PMA_LASI_TX_PHYXSLFLT 0x0001 /* PHY XS TX local fault */
+#define MDIO_PMA_LASI_TX_PCSLFLT 0x0008 /* PCS TX local fault */
+#define MDIO_PMA_LASI_TX_PMALFLT 0x0010 /* PMA/PMD TX local fault */
+#define MDIO_PMA_LASI_TX_LASERPOWERFLT 0x0080 /* Laser output power fault */
+#define MDIO_PMA_LASI_TX_LASERTEMPFLT 0x0100 /* Laser temperature fault */
+#define MDIO_PMA_LASI_TX_LASERBICURRFLT 0x0200 /* Laser bias current fault */
+
+/* LASI control/status registers. */
+#define MDIO_PMA_LASI_LSALARM 0x0001 /* LS_ALARM enable/status */
+#define MDIO_PMA_LASI_TXALARM 0x0002 /* TX_ALARM enable/status */
+#define MDIO_PMA_LASI_RXALARM 0x0004 /* RX_ALARM enable/status */
+
+/* Mapping between MDIO PRTAD/DEVAD and mii_ioctl_data::phy_id */
+
+#define MDIO_PHY_ID_C45 0x8000
+#define MDIO_PHY_ID_PRTAD 0x03e0
+#define MDIO_PHY_ID_DEVAD 0x001f
+#define MDIO_PHY_ID_C45_MASK \
+ (MDIO_PHY_ID_C45 | MDIO_PHY_ID_PRTAD | MDIO_PHY_ID_DEVAD)
+
+#define MDIO_PRTAD_NONE (-1)
+#define MDIO_DEVAD_NONE (-1)
+#define MDIO_EMULATE_C22 4
+
+#endif /* __LINUX_MDIO_H__ */
diff --git a/include/net.h b/include/net.h
index a29dafc101..e07b643705 100644
--- a/include/net.h
+++ b/include/net.h
@@ -14,46 +14,15 @@
#if defined(CONFIG_8xx)
#include <commproc.h>
-# if !defined(CONFIG_NET_MULTI)
-# if defined(FEC_ENET) || defined(SCC_ENET)
-# define CONFIG_NET_MULTI
-# endif
-# endif
#endif /* CONFIG_8xx */
-#if defined(CONFIG_MPC5xxx)
-# if !defined(CONFIG_NET_MULTI)
-# if defined(CONFIG_MPC5xxx_FEC)
-# define CONFIG_NET_MULTI
-# endif
-# endif
-#endif /* CONFIG_MPC5xxx */
-
-#if !defined(CONFIG_NET_MULTI) && defined(CONFIG_CPM2)
-#include <config.h>
-#if defined(CONFIG_ETHER_ON_FCC)
-#if defined(CONFIG_ETHER_ON_SCC)
-#error "Ethernet not correctly defined"
-#endif /* CONFIG_ETHER_ON_SCC */
-#define CONFIG_NET_MULTI
-#if (CONFIG_ETHER_INDEX == 1)
-#define CONFIG_ETHER_ON_FCC1
-# define CONFIG_SYS_CMXFCR_MASK1 CONFIG_SYS_CMXFCR_MASK
-# define CONFIG_SYS_CMXFCR_VALUE1 CONFIG_SYS_CMXFCR_VALUE
-#elif (CONFIG_ETHER_INDEX == 2)
-#define CONFIG_ETHER_ON_FCC2
-# define CONFIG_SYS_CMXFCR_MASK2 CONFIG_SYS_CMXFCR_MASK
-# define CONFIG_SYS_CMXFCR_VALUE2 CONFIG_SYS_CMXFCR_VALUE
-#elif (CONFIG_ETHER_INDEX == 3)
-#define CONFIG_ETHER_ON_FCC3
-# define CONFIG_SYS_CMXFCR_MASK3 CONFIG_SYS_CMXFCR_MASK
-# define CONFIG_SYS_CMXFCR_VALUE3 CONFIG_SYS_CMXFCR_VALUE
-#endif /* CONFIG_ETHER_INDEX */
-#endif /* CONFIG_ETHER_ON_FCC */
-#endif /* !CONFIG_NET_MULTI && CONFIG_8260 */
-
+#include <asm/cache.h>
#include <asm/byteorder.h> /* for nton* / ntoh* stuff */
+#define DEBUG_LL_STATE 0 /* Link local state machine changes */
+#define DEBUG_DEV_PKT 0 /* Packets or info directed to the device */
+#define DEBUG_NET_PKT 0 /* Packets on info on the network at large */
+#define DEBUG_INT_STATE 0 /* Internal network state changes */
/*
* The number of receive packet buffers, and the required packet buffer
@@ -67,25 +36,42 @@
# define PKTBUFSRX 4
#endif
-#define PKTALIGN 32
+#define PKTALIGN ARCH_DMA_MINALIGN
-typedef ulong IPaddr_t;
+/* IPv4 addresses are always 32 bits in size */
+typedef __be32 IPaddr_t;
-/*
- * The current receive packet handler. Called with a pointer to the
- * application packet, and a protocol type (PORT_BOOTPC or PORT_TFTP).
- * All other packets are dealt with without calling the handler.
+/**
+ * An incoming packet handler.
+ * @param pkt pointer to the application packet
+ * @param dport destination UDP port
+ * @param sip source IP address
+ * @param sport source UDP port
+ * @param len packet length
*/
-typedef void rxhand_f(uchar *, unsigned, unsigned, unsigned);
+typedef void rxhand_f(uchar *pkt, unsigned dport,
+ IPaddr_t sip, unsigned sport,
+ unsigned len);
+
+/**
+ * An incoming ICMP packet handler.
+ * @param type ICMP type
+ * @param code ICMP code
+ * @param dport destination UDP port
+ * @param sip source IP address
+ * @param sport source UDP port
+ * @param pkt pointer to the ICMP packet data
+ * @param len packet length
+ */
+typedef void rxhand_icmp_f(unsigned type, unsigned code, unsigned dport,
+ IPaddr_t sip, unsigned sport, uchar *pkt, unsigned len);
/*
* A timeout handler. Called after time interval has expired.
*/
typedef void thand_f(void);
-#define NAMESIZE 16
-
enum eth_state_t {
ETH_STATE_INIT,
ETH_STATE_PASSIVE,
@@ -93,52 +79,114 @@ enum eth_state_t {
};
struct eth_device {
- char name[NAMESIZE];
+ char name[16];
unsigned char enetaddr[6];
int iobase;
int state;
- int (*init) (struct eth_device*, bd_t*);
- int (*send) (struct eth_device*, volatile void* packet, int length);
- int (*recv) (struct eth_device*);
- void (*halt) (struct eth_device*);
+ int (*init) (struct eth_device *, bd_t *);
+ int (*send) (struct eth_device *, void *packet, int length);
+ int (*recv) (struct eth_device *);
+ void (*halt) (struct eth_device *);
#ifdef CONFIG_MCAST_TFTP
- int (*mcast) (struct eth_device*, u32 ip, u8 set);
+ int (*mcast) (struct eth_device *, u32 ip, u8 set);
#endif
- int (*write_hwaddr) (struct eth_device*);
+ int (*write_hwaddr) (struct eth_device *);
struct eth_device *next;
+ int index;
void *priv;
};
extern int eth_initialize(bd_t *bis); /* Initialize network subsystem */
extern int eth_register(struct eth_device* dev);/* Register network device */
+extern int eth_unregister(struct eth_device *dev);/* Remove network device */
extern void eth_try_another(int first_restart); /* Change the device */
-#ifdef CONFIG_NET_MULTI
extern void eth_set_current(void); /* set nterface to ethcur var */
-#endif
-extern struct eth_device *eth_get_dev(void); /* get the current device MAC */
+
+/* get the current device MAC */
+extern struct eth_device *eth_current;
+
+static inline __attribute__((always_inline))
+struct eth_device *eth_get_dev(void)
+{
+ return eth_current;
+}
extern struct eth_device *eth_get_dev_by_name(const char *devname);
extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
-extern int eth_get_dev_index (void); /* get the device index */
+extern int eth_get_dev_index(void); /* get the device index */
extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
extern int eth_getenv_enetaddr(char *name, uchar *enetaddr);
extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
-extern int eth_getenv_enetaddr_by_index(int index, uchar *enetaddr);
+
+/*
+ * Get the hardware address for an ethernet interface .
+ * Args:
+ * base_name - base name for device (normally "eth")
+ * index - device index number (0 for first)
+ * enetaddr - returns 6 byte hardware address
+ * Returns:
+ * Return true if the address is valid.
+ */
+extern int eth_getenv_enetaddr_by_index(const char *base_name, int index,
+ uchar *enetaddr);
+
+#ifdef CONFIG_RANDOM_MACADDR
+/*
+ * The u-boot policy does not allow hardcoded ethernet addresses. Under the
+ * following circumstances a random generated address is allowed:
+ * - in emergency cases, where you need a working network connection to set
+ * the ethernet address.
+ * Eg. you want a rescue boot and don't have a serial port to access the
+ * CLI to set environment variables.
+ *
+ * In these cases, we generate a random locally administered ethernet address.
+ *
+ * Args:
+ * enetaddr - returns 6 byte hardware address
+ */
+extern void eth_random_enetaddr(uchar *enetaddr);
+#endif
extern int usb_eth_initialize(bd_t *bi);
extern int eth_init(bd_t *bis); /* Initialize the device */
-extern int eth_send(volatile void *packet, int length); /* Send a packet */
+extern int eth_send(void *packet, int length); /* Send a packet */
#ifdef CONFIG_API
-extern int eth_receive(volatile void *packet, int length); /* Receive a packet*/
+extern int eth_receive(void *packet, int length); /* Receive a packet*/
+extern void (*push_packet)(void *packet, int length);
#endif
extern int eth_rx(void); /* Check for received packets */
extern void eth_halt(void); /* stop SCC */
extern char *eth_get_name(void); /* get name of current device */
+/* Set active state */
+static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis)
+{
+ eth_get_dev()->state = ETH_STATE_ACTIVE;
+
+ return 0;
+}
+/* Set passive state */
+static inline __attribute__((always_inline)) void eth_halt_state_only(void)
+{
+ eth_get_dev()->state = ETH_STATE_PASSIVE;
+}
+
+/*
+ * Set the hardware address for an ethernet interface based on 'eth%daddr'
+ * environment variable (or just 'ethaddr' if eth_number is 0).
+ * Args:
+ * base_name - base name for device (normally "eth")
+ * eth_number - value of %d (0 for first device of this type)
+ * Returns:
+ * 0 is success, non-zero is error status from driver.
+ */
+int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
+ int eth_number);
+
#ifdef CONFIG_MCAST_TFTP
-int eth_mcast_join( IPaddr_t mcast_addr, u8 join);
-u32 ether_crc (size_t len, unsigned char const *p);
+int eth_mcast_join(IPaddr_t mcast_addr, u8 join);
+u32 ether_crc(size_t len, unsigned char const *p);
#endif
@@ -150,7 +198,17 @@ u32 ether_crc (size_t len, unsigned char const *p);
/*
* Ethernet header
*/
-typedef struct {
+
+struct ethernet_hdr {
+ uchar et_dest[6]; /* Destination node */
+ uchar et_src[6]; /* Source node */
+ ushort et_protlen; /* Protocol or length */
+};
+
+/* Ethernet header size */
+#define ETHER_HDR_SIZE (sizeof(struct ethernet_hdr))
+
+struct e802_hdr {
uchar et_dest[6]; /* Destination node */
uchar et_src[6]; /* Source node */
ushort et_protlen; /* Protocol or length */
@@ -161,23 +219,24 @@ typedef struct {
uchar et_snap2;
uchar et_snap3;
ushort et_prot; /* 802 protocol */
-} Ethernet_t;
+};
-#define ETHER_HDR_SIZE 14 /* Ethernet header size */
-#define E802_HDR_SIZE 22 /* 802 ethernet header size */
+/* 802 + SNAP + ethernet header size */
+#define E802_HDR_SIZE (sizeof(struct e802_hdr))
/*
- * Ethernet header
+ * Virtual LAN Ethernet header
*/
-typedef struct {
+struct vlan_ethernet_hdr {
uchar vet_dest[6]; /* Destination node */
uchar vet_src[6]; /* Source node */
ushort vet_vlan_type; /* PROT_VLAN */
ushort vet_tag; /* TAG of VLAN */
ushort vet_type; /* protocol type */
-} VLAN_Ethernet_t;
+};
-#define VLAN_ETHER_HDR_SIZE 18 /* VLAN Ethernet header size */
+/* VLAN Ethernet header size */
+#define VLAN_ETHER_HDR_SIZE (sizeof(struct vlan_ethernet_hdr))
#define PROT_IP 0x0800 /* IP protocol */
#define PROT_ARP 0x0806 /* IP ARP protocol */
@@ -190,7 +249,7 @@ typedef struct {
/*
* Internet Protocol (IP) header.
*/
-typedef struct {
+struct ip_hdr {
uchar ip_hl_v; /* header length and version */
uchar ip_tos; /* type of service */
ushort ip_len; /* total length */
@@ -201,11 +260,7 @@ typedef struct {
ushort ip_sum; /* checksum */
IPaddr_t ip_src; /* Source IP address */
IPaddr_t ip_dst; /* Destination IP address */
- ushort udp_src; /* UDP source port */
- ushort udp_dst; /* UDP destination port */
- ushort udp_len; /* Length of UDP packet */
- ushort udp_xsum; /* Checksum */
-} IP_t;
+};
#define IP_OFFS 0x1fff /* ip offset *= 8 */
#define IP_FLAGS 0xe000 /* first 3 bits */
@@ -213,20 +268,42 @@ typedef struct {
#define IP_FLAGS_DFRAG 0x4000 /* don't fragments */
#define IP_FLAGS_MFRAG 0x2000 /* more fragments */
-#define IP_HDR_SIZE_NO_UDP (sizeof (IP_t) - 8)
-#define IP_HDR_SIZE (sizeof (IP_t))
+#define IP_HDR_SIZE (sizeof(struct ip_hdr))
+
+/*
+ * Internet Protocol (IP) + UDP header.
+ */
+struct ip_udp_hdr {
+ uchar ip_hl_v; /* header length and version */
+ uchar ip_tos; /* type of service */
+ ushort ip_len; /* total length */
+ ushort ip_id; /* identification */
+ ushort ip_off; /* fragment offset field */
+ uchar ip_ttl; /* time to live */
+ uchar ip_p; /* protocol */
+ ushort ip_sum; /* checksum */
+ IPaddr_t ip_src; /* Source IP address */
+ IPaddr_t ip_dst; /* Destination IP address */
+ ushort udp_src; /* UDP source port */
+ ushort udp_dst; /* UDP destination port */
+ ushort udp_len; /* Length of UDP packet */
+ ushort udp_xsum; /* Checksum */
+};
+#define IP_UDP_HDR_SIZE (sizeof(struct ip_udp_hdr))
+#define UDP_HDR_SIZE (IP_UDP_HDR_SIZE - IP_HDR_SIZE)
/*
* Address Resolution Protocol (ARP) header.
*/
-typedef struct
-{
+struct arp_hdr {
ushort ar_hrd; /* Format of hardware address */
# define ARP_ETHER 1 /* Ethernet hardware address */
ushort ar_pro; /* Format of protocol address */
uchar ar_hln; /* Length of hardware address */
+# define ARP_HLEN 6
uchar ar_pln; /* Length of protocol address */
+# define ARP_PLEN 4
ushort ar_op; /* Operation */
# define ARPOP_REQUEST 1 /* Request to resolve address */
# define ARPOP_REPLY 2 /* Response to previous request */
@@ -240,13 +317,17 @@ typedef struct
* specific hardware/protocol combinations.
*/
uchar ar_data[0];
+#define ar_sha ar_data[0]
+#define ar_spa ar_data[ARP_HLEN]
+#define ar_tha ar_data[ARP_HLEN + ARP_PLEN]
+#define ar_tpa ar_data[ARP_HLEN + ARP_PLEN + ARP_HLEN]
#if 0
uchar ar_sha[]; /* Sender hardware address */
uchar ar_spa[]; /* Sender protocol address */
uchar ar_tha[]; /* Target hardware address */
uchar ar_tpa[]; /* Target protocol address */
#endif /* 0 */
-} ARP_t;
+};
#define ARP_HDR_SIZE (8+20) /* Size assuming ethernet */
@@ -254,6 +335,7 @@ typedef struct
* ICMP stuff (just enough to handle (host) redirect messages)
*/
#define ICMP_ECHO_REPLY 0 /* Echo reply */
+#define ICMP_NOT_REACH 3 /* Detination unreachable */
#define ICMP_REDIRECT 5 /* Redirect (change route) */
#define ICMP_ECHO_REQUEST 8 /* Echo request */
@@ -261,7 +343,10 @@ typedef struct
#define ICMP_REDIR_NET 0 /* Redirect Net */
#define ICMP_REDIR_HOST 1 /* Redirect Host */
-typedef struct icmphdr {
+/* Codes for NOT_REACH */
+#define ICMP_NOT_REACH_PORT 3 /* Port unreachable */
+
+struct icmp_hdr {
uchar type;
uchar code;
ushort checksum;
@@ -272,12 +357,15 @@ typedef struct icmphdr {
} echo;
ulong gateway;
struct {
- ushort __unused;
+ ushort unused;
ushort mtu;
} frag;
+ uchar data[0];
} un;
-} ICMP_t;
+};
+#define ICMP_HDR_SIZE (sizeof(struct icmp_hdr))
+#define IP_ICMP_HDR_SIZE (IP_HDR_SIZE + ICMP_HDR_SIZE)
/*
* Maximum packet size; used to allocate packet storage.
@@ -316,53 +404,44 @@ typedef struct icmphdr {
/* net.c */
/** BOOTP EXTENTIONS **/
-extern IPaddr_t NetOurGatewayIP; /* Our gateway IP addresse */
-extern IPaddr_t NetOurSubnetMask; /* Our subnet mask (0 = unknown)*/
-extern IPaddr_t NetOurDNSIP; /* Our Domain Name Server (0 = unknown)*/
+extern IPaddr_t NetOurGatewayIP; /* Our gateway IP address */
+extern IPaddr_t NetOurSubnetMask; /* Our subnet mask (0 = unknown) */
+extern IPaddr_t NetOurDNSIP; /* Our Domain Name Server (0 = unknown) */
#if defined(CONFIG_BOOTP_DNS2)
-extern IPaddr_t NetOurDNS2IP; /* Our 2nd Domain Name Server (0 = unknown)*/
+extern IPaddr_t NetOurDNS2IP; /* Our 2nd Domain Name Server (0 = unknown) */
#endif
-extern char NetOurNISDomain[32]; /* Our NIS domain */
-extern char NetOurHostName[32]; /* Our hostname */
-extern char NetOurRootPath[64]; /* Our root path */
-extern ushort NetBootFileSize; /* Our boot file size in blocks */
+extern char NetOurNISDomain[32]; /* Our NIS domain */
+extern char NetOurHostName[32]; /* Our hostname */
+extern char NetOurRootPath[64]; /* Our root path */
+extern ushort NetBootFileSize; /* Our boot file size in blocks */
/** END OF BOOTP EXTENTIONS **/
-extern ulong NetBootFileXferSize; /* size of bootfile in bytes */
-extern uchar NetOurEther[6]; /* Our ethernet address */
-extern uchar NetServerEther[6]; /* Boot server enet address */
-extern IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
-extern IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */
-extern volatile uchar * NetTxPacket; /* THE transmit packet */
-extern volatile uchar * NetRxPackets[PKTBUFSRX];/* Receive packets */
-extern volatile uchar * NetRxPacket; /* Current receive packet */
-extern int NetRxPacketLen; /* Current rx packet length */
-extern unsigned NetIPID; /* IP ID (counting) */
-extern uchar NetBcastAddr[6]; /* Ethernet boardcast address */
+extern ulong NetBootFileXferSize; /* size of bootfile in bytes */
+extern uchar NetOurEther[6]; /* Our ethernet address */
+extern uchar NetServerEther[6]; /* Boot server enet address */
+extern IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
+extern IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */
+extern uchar *NetTxPacket; /* THE transmit packet */
+extern uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */
+extern uchar *NetRxPacket; /* Current receive packet */
+extern int NetRxPacketLen; /* Current rx packet length */
+extern unsigned NetIPID; /* IP ID (counting) */
+extern uchar NetBcastAddr[6]; /* Ethernet boardcast address */
extern uchar NetEtherNullAddr[6];
-#define VLAN_NONE 4095 /* untagged */
-#define VLAN_IDMASK 0x0fff /* mask of valid vlan id */
-extern ushort NetOurVLAN; /* Our VLAN */
-extern ushort NetOurNativeVLAN; /* Our Native VLAN */
+#define VLAN_NONE 4095 /* untagged */
+#define VLAN_IDMASK 0x0fff /* mask of valid vlan id */
+extern ushort NetOurVLAN; /* Our VLAN */
+extern ushort NetOurNativeVLAN; /* Our Native VLAN */
-extern uchar NetCDPAddr[6]; /* Ethernet CDP address */
-extern ushort CDPNativeVLAN; /* CDP returned native VLAN */
-extern ushort CDPApplianceVLAN; /* CDP returned appliance VLAN */
+extern int NetRestartWrap; /* Tried all network devices */
-extern int NetState; /* Network loop state */
-#define NETLOOP_CONTINUE 1
-#define NETLOOP_RESTART 2
-#define NETLOOP_SUCCESS 3
-#define NETLOOP_FAIL 4
-
-#ifdef CONFIG_NET_MULTI
-extern int NetRestartWrap; /* Tried all network devices */
-#endif
-
-typedef enum { BOOTP, RARP, ARP, TFTP, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP } proto_t;
+enum proto_t {
+ BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
+ TFTPSRV, TFTPPUT, LINKLOCAL
+};
/* from net/net.c */
-extern char BootFile[128]; /* Boot File name */
+extern char BootFile[128]; /* Boot File name */
#if defined(CONFIG_CMD_DNS)
extern char *NetDNSResolve; /* The host to resolve */
@@ -370,22 +449,37 @@ extern char *NetDNSenvvar; /* the env var to put the ip into */
#endif
#if defined(CONFIG_CMD_PING)
-extern IPaddr_t NetPingIP; /* the ip address to ping */
+extern IPaddr_t NetPingIP; /* the ip address to ping */
#endif
#if defined(CONFIG_CMD_CDP)
/* when CDP completes these hold the return values */
-extern ushort CDPNativeVLAN;
-extern ushort CDPApplianceVLAN;
+extern ushort CDPNativeVLAN; /* CDP returned native VLAN */
+extern ushort CDPApplianceVLAN; /* CDP returned appliance VLAN */
+
+/*
+ * Check for a CDP packet by examining the received MAC address field
+ */
+static inline int is_cdp_packet(const uchar *et_addr)
+{
+ extern const uchar NetCDPAddr[6];
+
+ return memcmp(et_addr, NetCDPAddr, 6) == 0;
+}
#endif
#if defined(CONFIG_CMD_SNTP)
-extern IPaddr_t NetNtpServerIP; /* the ip address to NTP */
-extern int NetTimeOffset; /* offset time from UTC */
+extern IPaddr_t NetNtpServerIP; /* the ip address to NTP */
+extern int NetTimeOffset; /* offset time from UTC */
+#endif
+
+#if defined(CONFIG_MCAST_TFTP)
+extern IPaddr_t Mcast_addr;
#endif
/* Initialize the network adapter */
-extern int NetLoop(proto_t);
+extern void net_init(void);
+extern int NetLoop(enum proto_t);
/* Shutdown adapters and cleanup */
extern void NetStop(void);
@@ -397,27 +491,94 @@ extern void NetStartAgain(void);
extern int NetEthHdrSize(void);
/* Set ethernet header; returns the size of the header */
-extern int NetSetEther(volatile uchar *, uchar *, uint);
+extern int NetSetEther(uchar *, uchar *, uint);
+extern int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */
-extern void NetSetIP(volatile uchar *, IPaddr_t, int, int, int);
+extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source);
+extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport,
+ int sport, int len);
/* Checksum */
-extern int NetCksumOk(uchar *, int); /* Return true if cksum OK */
-extern uint NetCksum(uchar *, int); /* Calculate the checksum */
+extern int NetCksumOk(uchar *, int); /* Return true if cksum OK */
+extern uint NetCksum(uchar *, int); /* Calculate the checksum */
+
+/* Callbacks */
+extern rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */
+extern void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */
+extern rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */
+extern void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */
+extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */
+extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
+
+/* Network loop state */
+enum net_loop_state {
+ NETLOOP_CONTINUE,
+ NETLOOP_RESTART,
+ NETLOOP_SUCCESS,
+ NETLOOP_FAIL
+};
+extern enum net_loop_state net_state;
-/* Set callbacks */
-extern void NetSetHandler(rxhand_f *); /* Set RX packet handler */
-extern void NetSetTimeout(ulong, thand_f *);/* Set timeout handler */
+static inline void net_set_state(enum net_loop_state state)
+{
+ //debug_cond(DEBUG_INT_STATE, "--- NetState set to %d\n", state);
+ net_state = state;
+}
-/* Transmit "NetTxPacket" */
-extern void NetSendPacket(volatile uchar *, int);
+/* Transmit a packet */
+static inline void NetSendPacket(uchar *pkt, int len)
+{
+ (void) eth_send(pkt, len);
+}
-/* Transmit UDP packet, performing ARP request if needed */
-extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len);
+/*
+ * Transmit "NetTxPacket" as UDP packet, performing ARP request if needed
+ * (ether will be populated)
+ *
+ * @param ether Raw packet buffer
+ * @param dest IP address to send the datagram to
+ * @param dport Destination UDP port
+ * @param sport Source UDP port
+ * @param payload_len Length of data after the UDP header
+ */
+extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport,
+ int sport, int payload_len);
/* Processes a received packet */
-extern void NetReceive(volatile uchar *, int);
+extern void NetReceive(uchar *, int);
+
+#ifdef CONFIG_NETCONSOLE
+void NcStart(void);
+int nc_input_packet(uchar *pkt, IPaddr_t src_ip, unsigned dest_port,
+ unsigned src_port, unsigned len);
+#endif
+
+static inline __attribute__((always_inline)) int eth_is_on_demand_init(void)
+{
+#ifdef CONFIG_NETCONSOLE
+ extern enum proto_t net_loop_last_protocol;
+
+ return net_loop_last_protocol != NETCONS;
+#else
+ return 1;
+#endif
+}
+
+static inline void eth_set_last_protocol(int protocol)
+{
+#ifdef CONFIG_NETCONSOLE
+ extern enum proto_t net_loop_last_protocol;
+
+ net_loop_last_protocol = protocol;
+#endif
+}
+
+/*
+ * Check if autoload is enabled. If so, use either NFS or TFTP to download
+ * the boot file.
+ */
+void net_auto_load(void);
/*
* The following functions are a bit ugly, but necessary to deal with
@@ -427,10 +588,11 @@ extern void NetReceive(volatile uchar *, int);
* footprint in our tests.
*/
/* return IP *in network byteorder* */
-static inline IPaddr_t NetReadIP(volatile void *from)
+static inline IPaddr_t NetReadIP(void *from)
{
IPaddr_t ip;
- memcpy((void*)&ip, (void*)from, sizeof(ip));
+
+ memcpy((void *)&ip, (void *)from, sizeof(ip));
return ip;
}
@@ -438,26 +600,27 @@ static inline IPaddr_t NetReadIP(volatile void *from)
static inline ulong NetReadLong(ulong *from)
{
ulong l;
- memcpy((void*)&l, (void*)from, sizeof(l));
+
+ memcpy((void *)&l, (void *)from, sizeof(l));
return l;
}
/* write IP *in network byteorder* */
static inline void NetWriteIP(void *to, IPaddr_t ip)
{
- memcpy(to, (void*)&ip, sizeof(ip));
+ memcpy(to, (void *)&ip, sizeof(ip));
}
/* copy IP */
-static inline void NetCopyIP(volatile void *to, void *from)
+static inline void NetCopyIP(void *to, void *from)
{
- memcpy((void*)to, from, sizeof(IPaddr_t));
+ memcpy((void *)to, from, sizeof(IPaddr_t));
}
/* copy ulong */
static inline void NetCopyLong(ulong *to, ulong *from)
{
- memcpy((void*)to, (void*)from, sizeof(ulong));
+ memcpy((void *)to, (void *)from, sizeof(ulong));
}
/**
@@ -480,7 +643,7 @@ static inline int is_zero_ether_addr(const u8 *addr)
*/
static inline int is_multicast_ether_addr(const u8 *addr)
{
- return (0x01 & addr[0]);
+ return 0x01 & addr[0];
}
/*
@@ -491,7 +654,8 @@ static inline int is_multicast_ether_addr(const u8 *addr)
*/
static inline int is_broadcast_ether_addr(const u8 *addr)
{
- return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
+ return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) ==
+ 0xff;
}
/*
@@ -511,26 +675,29 @@ static inline int is_valid_ether_addr(const u8 *addr)
}
/* Convert an IP address to a string */
-extern void ip_to_string (IPaddr_t x, char *s);
+extern void ip_to_string(IPaddr_t x, char *s);
/* Convert a string to ip address */
-extern IPaddr_t string_to_ip(char *s);
+extern IPaddr_t string_to_ip(const char *s);
/* Convert a VLAN id to a string */
-extern void VLAN_to_string (ushort x, char *s);
+extern void VLAN_to_string(ushort x, char *s);
/* Convert a string to a vlan id */
-extern ushort string_to_VLAN(char *s);
+extern ushort string_to_VLAN(const char *s);
/* read a VLAN id from an environment variable */
extern ushort getenv_VLAN(char *);
/* copy a filename (allow for "..." notation, limit length) */
-extern void copy_filename (char *dst, char *src, int size);
+extern void copy_filename(char *dst, const char *src, int size);
/* get a random source port */
extern unsigned int random_port(void);
+/* Update U-Boot over TFTP */
+extern int update_tftp(ulong addr);
+
/**********************************************************************/
#endif /* __NET_H__ */
diff --git a/include/phy.h b/include/phy.h
new file mode 100644
index 0000000000..f0f522a9c2
--- /dev/null
+++ b/include/phy.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Andy Fleming <afleming@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This file pretty much stolen from Linux's mii.h/ethtool.h/phy.h
+ */
+
+#ifndef _PHY_H
+#define _PHY_H
+
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/mdio.h>
+
+#define PHY_MAX_ADDR 32
+
+#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
+ SUPPORTED_10baseT_Full | \
+ SUPPORTED_100baseT_Half | \
+ SUPPORTED_100baseT_Full | \
+ SUPPORTED_Autoneg | \
+ SUPPORTED_TP | \
+ SUPPORTED_MII)
+
+#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
+ SUPPORTED_1000baseT_Half | \
+ SUPPORTED_1000baseT_Full)
+
+#define PHY_10G_FEATURES (PHY_GBIT_FEATURES | \
+ SUPPORTED_10000baseT_Full)
+
+#define PHY_ANEG_TIMEOUT 4000
+
+
+typedef enum {
+ PHY_INTERFACE_MODE_MII,
+ PHY_INTERFACE_MODE_GMII,
+ PHY_INTERFACE_MODE_SGMII,
+ PHY_INTERFACE_MODE_QSGMII,
+ PHY_INTERFACE_MODE_TBI,
+ PHY_INTERFACE_MODE_RMII,
+ PHY_INTERFACE_MODE_RGMII,
+ PHY_INTERFACE_MODE_RGMII_ID,
+ PHY_INTERFACE_MODE_RGMII_RXID,
+ PHY_INTERFACE_MODE_RGMII_TXID,
+ PHY_INTERFACE_MODE_RTBI,
+ PHY_INTERFACE_MODE_XGMII,
+ PHY_INTERFACE_MODE_NONE /* Must be last */
+} phy_interface_t;
+
+static const char *phy_interface_strings[] = {
+ [PHY_INTERFACE_MODE_MII] = "mii",
+ [PHY_INTERFACE_MODE_GMII] = "gmii",
+ [PHY_INTERFACE_MODE_SGMII] = "sgmii",
+ [PHY_INTERFACE_MODE_QSGMII] = "qsgmii",
+ [PHY_INTERFACE_MODE_TBI] = "tbi",
+ [PHY_INTERFACE_MODE_RMII] = "rmii",
+ [PHY_INTERFACE_MODE_RGMII] = "rgmii",
+ [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id",
+ [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
+ [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+ [PHY_INTERFACE_MODE_RTBI] = "rtbi",
+ [PHY_INTERFACE_MODE_XGMII] = "xgmii",
+ [PHY_INTERFACE_MODE_NONE] = "",
+};
+
+static inline const char *phy_string_for_interface(phy_interface_t i)
+{
+ /* Default to unknown */
+ if (i > PHY_INTERFACE_MODE_NONE)
+ i = PHY_INTERFACE_MODE_NONE;
+
+ return phy_interface_strings[i];
+}
+
+
+struct phy_device;
+
+#define MDIO_NAME_LEN 32
+
+struct mii_dev {
+ struct list_head link;
+ char name[MDIO_NAME_LEN];
+ void *priv;
+ int (*read)(struct mii_dev *bus, int addr, int devad, int reg);
+ int (*write)(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val);
+ int (*reset)(struct mii_dev *bus);
+ struct phy_device *phymap[PHY_MAX_ADDR];
+ u32 phy_mask;
+};
+
+/* struct phy_driver: a structure which defines PHY behavior
+ *
+ * uid will contain a number which represents the PHY. During
+ * startup, the driver will poll the PHY to find out what its
+ * UID--as defined by registers 2 and 3--is. The 32-bit result
+ * gotten from the PHY will be masked to
+ * discard any bits which may change based on revision numbers
+ * unimportant to functionality
+ *
+ */
+struct phy_driver {
+ char *name;
+ unsigned int uid;
+ unsigned int mask;
+ unsigned int mmds;
+
+ u32 features;
+
+ /* Called to do any driver startup necessities */
+ /* Will be called during phy_connect */
+ int (*probe)(struct phy_device *phydev);
+
+ /* Called to configure the PHY, and modify the controller
+ * based on the results. Should be called after phy_connect */
+ int (*config)(struct phy_device *phydev);
+
+ /* Called when starting up the controller */
+ int (*startup)(struct phy_device *phydev);
+
+ /* Called when bringing down the controller */
+ int (*shutdown)(struct phy_device *phydev);
+
+ struct list_head list;
+};
+
+struct phy_device {
+ /* Information about the PHY type */
+ /* And management functions */
+ struct mii_dev *bus;
+ struct phy_driver *drv;
+ void *priv;
+
+ struct eth_device *dev;
+
+ /* forced speed & duplex (no autoneg)
+ * partner speed & duplex & pause (autoneg)
+ */
+ int speed;
+ int duplex;
+
+ /* The most recently read link state */
+ int link;
+ int port;
+ phy_interface_t interface;
+
+ u32 advertising;
+ u32 supported;
+ u32 mmds;
+
+ int autoneg;
+ int addr;
+ int pause;
+ int asym_pause;
+ u32 phy_id;
+ u32 flags;
+};
+
+static inline int phy_read(struct phy_device *phydev, int devad, int regnum)
+{
+ struct mii_dev *bus = phydev->bus;
+
+ return bus->read(bus, phydev->addr, devad, regnum);
+}
+
+static inline int phy_write(struct phy_device *phydev, int devad, int regnum,
+ u16 val)
+{
+ struct mii_dev *bus = phydev->bus;
+
+ return bus->write(bus, phydev->addr, devad, regnum, val);
+}
+
+#ifdef CONFIG_PHYLIB_10G
+extern struct phy_driver gen10g_driver;
+
+/* For now, XGMII is the only 10G interface */
+static inline int is_10g_interface(phy_interface_t interface)
+{
+ return interface == PHY_INTERFACE_MODE_XGMII;
+}
+
+#endif
+
+int phy_init(void);
+int phy_reset(struct phy_device *phydev);
+struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask,
+ phy_interface_t interface);
+void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev);
+struct phy_device *phy_connect(struct mii_dev *bus, int addr,
+ struct eth_device *dev,
+ phy_interface_t interface);
+int phy_startup(struct phy_device *phydev);
+int phy_config(struct phy_device *phydev);
+int phy_shutdown(struct phy_device *phydev);
+int phy_register(struct phy_driver *drv);
+int genphy_config_aneg(struct phy_device *phydev);
+int genphy_restart_aneg(struct phy_device *phydev);
+int genphy_update_link(struct phy_device *phydev);
+int genphy_parse_link(struct phy_device *phydev);
+int genphy_config(struct phy_device *phydev);
+int genphy_startup(struct phy_device *phydev);
+int genphy_shutdown(struct phy_device *phydev);
+int gen10g_config(struct phy_device *phydev);
+int gen10g_startup(struct phy_device *phydev);
+int gen10g_shutdown(struct phy_device *phydev);
+int gen10g_discover_mmds(struct phy_device *phydev);
+
+int phy_atheros_init(void);
+int phy_broadcom_init(void);
+int phy_davicom_init(void);
+int phy_et1011c_init(void);
+int phy_lxt_init(void);
+int phy_marvell_init(void);
+int phy_micrel_init(void);
+int phy_natsemi_init(void);
+int phy_realtek_init(void);
+int phy_smsc_init(void);
+int phy_teranetics_init(void);
+int phy_vitesse_init(void);
+
+/* PHY UIDs for various PHYs that are referenced in external code */
+#define PHY_UID_TN2020 0x00a19410
+
+#endif
diff --git a/include/usb_ether.h b/include/usb_ether.h
new file mode 100644
index 0000000000..678c9dff25
--- /dev/null
+++ b/include/usb_ether.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __USB_ETHER_H__
+#define __USB_ETHER_H__
+
+#include <net.h>
+
+/*
+ * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
+ * and FCS/CRC (frame check sequence).
+ */
+#define ETH_ALEN 6 /* Octets in one ethernet addr */
+#define ETH_HLEN 14 /* Total octets in header. */
+#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN 1500 /* Max. octets in payload */
+#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */
+#define ETH_FCS_LEN 4 /* Octets in the FCS */
+
+struct ueth_data {
+ /* eth info */
+ struct eth_device eth_dev; /* used with eth_register */
+ int phy_id; /* mii phy id */
+
+ /* usb info */
+ struct usb_device *pusb_dev; /* this usb_device */
+ unsigned char ifnum; /* interface number */
+ unsigned char ep_in; /* in endpoint */
+ unsigned char ep_out; /* out ....... */
+ unsigned char ep_int; /* interrupt . */
+ unsigned char subclass; /* as in overview */
+ unsigned char protocol; /* .............. */
+ unsigned char irqinterval; /* Intervall for IRQ Pipe */
+
+ /* driver private */
+ void *dev_priv;
+};
+
+/*
+ * Function definitions for each USB ethernet driver go here, bracketed by
+ * #ifdef CONFIG_USB_ETHER_xxx...#endif
+ */
+#ifdef CONFIG_USB_ETHER_ASIX
+void asix_eth_before_probe(void);
+int asix_eth_probe(struct usb_device *dev, unsigned int ifnum,
+ struct ueth_data *ss);
+int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+ struct eth_device *eth);
+#endif
+
+#ifdef CONFIG_USB_ETHER_SMSC95XX
+void smsc95xx_eth_before_probe(void);
+int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum,
+ struct ueth_data *ss);
+int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+ struct eth_device *eth);
+#endif
+
+#endif /* __USB_ETHER_H__ */
diff --git a/lib/display_options.c b/lib/display_options.c
index 5d24f19138..465a1c747d 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -67,17 +67,23 @@ void print_size(unsigned long long size, const char *s)
return;
}
+ n = size >> d;
f = size & ((1ULL << d) - 1);
/* If there's a remainder, deal with it */
if (f) {
- d -= 10;
- c = names[i+1];
- }
+ m = (10ULL * f + (1ULL << (d - 1))) >> d;
- n = size >> d;
+ if (m >= 10) {
+ m -= 10;
+ n += 1;
+ }
+ }
printf ("%lu", n);
+ if (m) {
+ printf (".%ld", m);
+ }
printf (" %ciB%s", c, s);
}
diff --git a/lib/net_utils.c b/lib/net_utils.c
index f03b098e9c..8d66163159 100644
--- a/lib/net_utils.c
+++ b/lib/net_utils.c
@@ -7,28 +7,12 @@
* Copyright 2000-2002 Wolfgang Denk, wd@denx.de
* Copyright 2009 Dirk Behme, dirk.behme@googlemail.com
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
-IPaddr_t string_to_ip(char *s)
+IPaddr_t string_to_ip(const char *s)
{
IPaddr_t addr;
char *e;
diff --git a/net/Makefile b/net/Makefile
index 0544f6bacd..4c9a97f04d 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -2,23 +2,7 @@
# (C) Copyright 2000-2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
-# See file CREDITS for list of people who contributed to this
-# project.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-# MA 02111-1307 USA
+# SPDX-License-Identifier: GPL-2.0+
#
include $(TOPDIR)/config.mk
@@ -27,16 +11,20 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libnet.o
+COBJS-$(CONFIG_CMD_NET) += arp.o
COBJS-$(CONFIG_CMD_NET) += bootp.o
+COBJS-$(CONFIG_CMD_CDP) += cdp.o
COBJS-$(CONFIG_CMD_DNS) += dns.o
COBJS-$(CONFIG_CMD_NET) += eth.o
+COBJS-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
COBJS-$(CONFIG_CMD_NET) += net.o
COBJS-$(CONFIG_CMD_NFS) += nfs.o
+COBJS-$(CONFIG_CMD_PING) += ping.o
COBJS-$(CONFIG_CMD_RARP) += rarp.o
COBJS-$(CONFIG_CMD_SNTP) += sntp.o
COBJS-$(CONFIG_CMD_NET) += tftp.o
-COBJS := $(COBJS-y)
+COBJS := $(sort $(COBJS-y))
SRCS := $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS))
diff --git a/net/arp.c b/net/arp.c
new file mode 100644
index 0000000000..20c6b2d42a
--- /dev/null
+++ b/net/arp.c
@@ -0,0 +1,236 @@
+/*
+ * Copied from Linux Monitor (LiMon) - Networking.
+ *
+ * Copyright 1994 - 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000 Roland Borde
+ * Copyright 2000 Paolo Scaffardi
+ * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
+ */
+
+#include <common.h>
+
+#include "arp.h"
+
+#ifndef CONFIG_ARP_TIMEOUT
+/* Milliseconds before trying ARP again */
+# define ARP_TIMEOUT 5000UL
+#else
+# define ARP_TIMEOUT CONFIG_ARP_TIMEOUT
+#endif
+
+
+#ifndef CONFIG_NET_RETRY_COUNT
+# define ARP_TIMEOUT_COUNT 5 /* # of timeouts before giving up */
+#else
+# define ARP_TIMEOUT_COUNT CONFIG_NET_RETRY_COUNT
+#endif
+
+IPaddr_t NetArpWaitPacketIP;
+static IPaddr_t NetArpWaitReplyIP;
+/* MAC address of waiting packet's destination */
+uchar *NetArpWaitPacketMAC;
+int NetArpWaitTxPacketSize;
+ulong NetArpWaitTimerStart;
+int NetArpWaitTry;
+
+static uchar *NetArpTxPacket; /* THE ARP transmit packet */
+static uchar NetArpPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
+
+void ArpInit(void)
+{
+ /* XXX problem with bss workaround */
+ NetArpWaitPacketMAC = NULL;
+ NetArpWaitPacketIP = 0;
+ NetArpWaitReplyIP = 0;
+ NetArpWaitTxPacketSize = 0;
+ NetArpTxPacket = &NetArpPacketBuf[0] + (PKTALIGN - 1);
+ NetArpTxPacket -= (ulong)NetArpTxPacket % PKTALIGN;
+}
+
+void arp_raw_request(IPaddr_t sourceIP, const uchar *targetEther,
+ IPaddr_t targetIP)
+{
+ uchar *pkt;
+ struct arp_hdr *arp;
+ int eth_hdr_size;
+
+ debug_cond(DEBUG_DEV_PKT, "ARP broadcast %d\n", NetArpWaitTry);
+
+ pkt = NetArpTxPacket;
+
+ eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_ARP);
+ pkt += eth_hdr_size;
+
+ arp = (struct arp_hdr *) pkt;
+
+ arp->ar_hrd = htons(ARP_ETHER);
+ arp->ar_pro = htons(PROT_IP);
+ arp->ar_hln = ARP_HLEN;
+ arp->ar_pln = ARP_PLEN;
+ arp->ar_op = htons(ARPOP_REQUEST);
+
+ memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN); /* source ET addr */
+ NetWriteIP(&arp->ar_spa, sourceIP); /* source IP addr */
+ memcpy(&arp->ar_tha, targetEther, ARP_HLEN); /* target ET addr */
+ NetWriteIP(&arp->ar_tpa, targetIP); /* target IP addr */
+
+ NetSendPacket(NetArpTxPacket, eth_hdr_size + ARP_HDR_SIZE);
+}
+
+void ArpRequest(void)
+{
+ if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
+ (NetOurIP & NetOurSubnetMask)) {
+ if (NetOurGatewayIP == 0) {
+ puts("## Warning: gatewayip needed but not set\n");
+ NetArpWaitReplyIP = NetArpWaitPacketIP;
+ } else {
+ NetArpWaitReplyIP = NetOurGatewayIP;
+ }
+ } else {
+ NetArpWaitReplyIP = NetArpWaitPacketIP;
+ }
+
+ arp_raw_request(NetOurIP, NetEtherNullAddr, NetArpWaitReplyIP);
+}
+
+void ArpTimeoutCheck(void)
+{
+ ulong t;
+
+ if (!NetArpWaitPacketIP)
+ return;
+
+ t = get_timer(0);
+
+ /* check for arp timeout */
+ if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT) {
+ NetArpWaitTry++;
+
+ if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
+ puts("\nARP Retry count exceeded; starting again\n");
+ NetArpWaitTry = 0;
+ NetStartAgain();
+ } else {
+ NetArpWaitTimerStart = t;
+ ArpRequest();
+ }
+ }
+}
+
+void ArpReceive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
+{
+ struct arp_hdr *arp;
+ IPaddr_t reply_ip_addr;
+ uchar *pkt;
+ int eth_hdr_size;
+
+ /*
+ * We have to deal with two types of ARP packets:
+ * - REQUEST packets will be answered by sending our
+ * IP address - if we know it.
+ * - REPLY packates are expected only after we asked
+ * for the TFTP server's or the gateway's ethernet
+ * address; so if we receive such a packet, we set
+ * the server ethernet address
+ */
+ debug_cond(DEBUG_NET_PKT, "Got ARP\n");
+
+ arp = (struct arp_hdr *)ip;
+ if (len < ARP_HDR_SIZE) {
+ printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
+ return;
+ }
+ if (ntohs(arp->ar_hrd) != ARP_ETHER)
+ return;
+ if (ntohs(arp->ar_pro) != PROT_IP)
+ return;
+ if (arp->ar_hln != ARP_HLEN)
+ return;
+ if (arp->ar_pln != ARP_PLEN)
+ return;
+
+ if (NetOurIP == 0)
+ return;
+
+ if (NetReadIP(&arp->ar_tpa) != NetOurIP)
+ return;
+
+ switch (ntohs(arp->ar_op)) {
+ case ARPOP_REQUEST:
+ /* reply with our IP address */
+ debug_cond(DEBUG_DEV_PKT, "Got ARP REQUEST, return our IP\n");
+ pkt = (uchar *)et;
+ eth_hdr_size = net_update_ether(et, et->et_src, PROT_ARP);
+ pkt += eth_hdr_size;
+ arp->ar_op = htons(ARPOP_REPLY);
+ memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN);
+ NetCopyIP(&arp->ar_tpa, &arp->ar_spa);
+ memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN);
+ NetCopyIP(&arp->ar_spa, &NetOurIP);
+
+#ifdef CONFIG_CMD_LINK_LOCAL
+ /*
+ * Work-around for brain-damaged Cisco equipment with
+ * arp-proxy enabled.
+ *
+ * If the requesting IP is not on our subnet, wait 5ms to
+ * reply to ARP request so that our reply will overwrite
+ * the arp-proxy's instead of the other way around.
+ */
+ if ((NetReadIP(&arp->ar_tpa) & NetOurSubnetMask) !=
+ (NetReadIP(&arp->ar_spa) & NetOurSubnetMask))
+ udelay(5000);
+#endif
+ NetSendPacket((uchar *)et, eth_hdr_size + ARP_HDR_SIZE);
+ return;
+
+ case ARPOP_REPLY: /* arp reply */
+ /* are we waiting for a reply */
+ if (!NetArpWaitPacketIP)
+ break;
+
+#ifdef CONFIG_KEEP_SERVERADDR
+ if (NetServerIP == NetArpWaitPacketIP) {
+ char buf[20];
+ sprintf(buf, "%pM", &arp->ar_sha);
+ setenv("serveraddr", buf);
+ }
+#endif
+
+ reply_ip_addr = NetReadIP(&arp->ar_spa);
+
+ /* matched waiting packet's address */
+ if (reply_ip_addr == NetArpWaitReplyIP) {
+ debug_cond(DEBUG_DEV_PKT,
+ "Got ARP REPLY, set eth addr (%pM)\n",
+ arp->ar_data);
+
+ /* save address for later use */
+ if (NetArpWaitPacketMAC != NULL)
+ memcpy(NetArpWaitPacketMAC,
+ &arp->ar_sha, ARP_HLEN);
+
+ net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr,
+ 0, len);
+
+ /* set the mac address in the waiting packet's header
+ and transmit it */
+ memcpy(((struct ethernet_hdr *)NetTxPacket)->et_dest,
+ &arp->ar_sha, ARP_HLEN);
+ NetSendPacket(NetTxPacket, NetArpWaitTxPacketSize);
+
+ /* no arp request pending now */
+ NetArpWaitPacketIP = 0;
+ NetArpWaitTxPacketSize = 0;
+ NetArpWaitPacketMAC = NULL;
+
+ }
+ return;
+ default:
+ debug("Unexpected ARP opcode 0x%x\n",
+ ntohs(arp->ar_op));
+ return;
+ }
+}
diff --git a/net/arp.h b/net/arp.h
new file mode 100644
index 0000000000..bfd57e0105
--- /dev/null
+++ b/net/arp.h
@@ -0,0 +1,30 @@
+/*
+ * Copied from Linux Monitor (LiMon) - Networking.
+ *
+ * Copyright 1994 - 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000 Roland Borde
+ * Copyright 2000 Paolo Scaffardi
+ * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
+ */
+
+#ifndef __ARP_H__
+#define __ARP_H__
+
+#include <common.h>
+
+extern IPaddr_t NetArpWaitPacketIP;
+/* MAC address of waiting packet's destination */
+extern uchar *NetArpWaitPacketMAC;
+extern int NetArpWaitTxPacketSize;
+extern ulong NetArpWaitTimerStart;
+extern int NetArpWaitTry;
+
+void ArpInit(void);
+void ArpRequest(void);
+void arp_raw_request(IPaddr_t sourceIP, const uchar *targetEther,
+ IPaddr_t targetIP);
+void ArpTimeoutCheck(void);
+void ArpReceive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len);
+
+#endif /* __ARP_H__ */
diff --git a/net/bootp.c b/net/bootp.c
index 1a717867d4..4300f1c2f1 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -17,34 +17,35 @@
#ifdef CONFIG_STATUS_LED
#include <status_led.h>
#endif
+#ifdef CONFIG_BOOTP_RANDOM_DELAY
+#include "net_rand.h"
+#endif
-#define BOOTP_VENDOR_MAGIC 0x63825363 /* RFC1048 Magic Cookie */
+#define BOOTP_VENDOR_MAGIC 0x63825363 /* RFC1048 Magic Cookie */
#define TIMEOUT 5000UL /* Milliseconds before trying BOOTP again */
#ifndef CONFIG_NET_RETRY_COUNT
-# define TIMEOUT_COUNT 5 /* # of timeouts before giving up */
+# define TIMEOUT_COUNT 5 /* # of timeouts before giving up */
#else
# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
#endif
-#define PORT_BOOTPS 67 /* BOOTP server UDP port */
-#define PORT_BOOTPC 68 /* BOOTP client UDP port */
+#define PORT_BOOTPS 67 /* BOOTP server UDP port */
+#define PORT_BOOTPC 68 /* BOOTP client UDP port */
-#ifndef CONFIG_DHCP_MIN_EXT_LEN /* minimal length of extension list */
+#ifndef CONFIG_DHCP_MIN_EXT_LEN /* minimal length of extension list */
#define CONFIG_DHCP_MIN_EXT_LEN 64
#endif
ulong BootpID;
int BootpTry;
-#ifdef CONFIG_BOOTP_RANDOM_DELAY
-ulong seed1, seed2;
-#endif
#if defined(CONFIG_CMD_DHCP)
-dhcp_state_t dhcp_state = INIT;
-unsigned long dhcp_leasetime = 0;
-IPaddr_t NetDHCPServerIP = 0;
-static void DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len);
+static dhcp_state_t dhcp_state = INIT;
+static unsigned long dhcp_leasetime;
+static IPaddr_t NetDHCPServerIP;
+static void DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+ unsigned len);
/* For Debug */
#if 0
@@ -62,37 +63,29 @@ static char *dhcpmsg2str(int type)
}
}
#endif
-
-#if defined(CONFIG_BOOTP_VENDOREX)
-extern u8 *dhcp_vendorex_prep (u8 *e); /*rtn new e after add own opts. */
-extern u8 *dhcp_vendorex_proc (u8 *e); /*rtn next e if mine,else NULL */
-#endif
-
#endif
static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
{
- Bootp_t *bp = (Bootp_t *) pkt;
+ struct Bootp_t *bp = (struct Bootp_t *) pkt;
int retval = 0;
if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
retval = -1;
- else if (len < sizeof (Bootp_t) - OPT_SIZE)
+ else if (len < sizeof(struct Bootp_t) - OPT_FIELD_SIZE)
retval = -2;
else if (bp->bp_op != OP_BOOTREQUEST &&
- bp->bp_op != OP_BOOTREPLY &&
- bp->bp_op != DHCP_OFFER &&
- bp->bp_op != DHCP_ACK &&
- bp->bp_op != DHCP_NAK ) {
+ bp->bp_op != OP_BOOTREPLY &&
+ bp->bp_op != DHCP_OFFER &&
+ bp->bp_op != DHCP_ACK &&
+ bp->bp_op != DHCP_NAK)
retval = -3;
- }
else if (bp->bp_htype != HWT_ETHER)
retval = -4;
else if (bp->bp_hlen != HWL_ETHER)
retval = -5;
- else if (NetReadLong((ulong*)&bp->bp_id) != BootpID) {
+ else if (NetReadLong((ulong *)&bp->bp_id) != BootpID)
retval = -6;
- }
debug("Filtering pkt = %d\n", retval);
@@ -102,19 +95,19 @@ static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
/*
* Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
*/
-static void BootpCopyNetParams(Bootp_t *bp)
+static void BootpCopyNetParams(struct Bootp_t *bp)
{
+#if !defined(CONFIG_BOOTP_SERVERIP)
IPaddr_t tmp_ip;
- NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
-#if !defined(CONFIG_BOOTP_SERVERIP)
NetCopyIP(&tmp_ip, &bp->bp_siaddr);
if (tmp_ip != 0)
NetCopyIP(&NetServerIP, &bp->bp_siaddr);
- memcpy (NetServerEther, ((Ethernet_t *)NetRxPacket)->et_src, 6);
+ memcpy(NetServerEther, ((struct ethernet_hdr *)NetRxPacket)->et_src, 6);
#endif
+ NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
if (strlen(bp->bp_file) > 0)
- copy_filename (BootFile, bp->bp_file, sizeof(BootFile));
+ copy_filename(BootFile, bp->bp_file, sizeof(BootFile));
debug("Bootfile: %s\n", BootFile);
@@ -122,97 +115,95 @@ static void BootpCopyNetParams(Bootp_t *bp)
* don't delete exising entry when BOOTP / DHCP reply does
* not contain a new value
*/
- if (*BootFile) {
- setenv ("bootfile", BootFile);
- }
+ if (*BootFile)
+ setenv("bootfile", BootFile);
}
-static int truncate_sz (const char *name, int maxlen, int curlen)
+static int truncate_sz(const char *name, int maxlen, int curlen)
{
if (curlen >= maxlen) {
- printf("*** WARNING: %s is too long (%d - max: %d) - truncated\n",
- name, curlen, maxlen);
+ printf("*** WARNING: %s is too long (%d - max: %d)"
+ " - truncated\n", name, curlen, maxlen);
curlen = maxlen - 1;
}
- return (curlen);
+ return curlen;
}
#if !defined(CONFIG_CMD_DHCP)
-static void BootpVendorFieldProcess (u8 * ext)
+static void BootpVendorFieldProcess(u8 *ext)
{
int size = *(ext + 1);
debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
- *(ext + 1));
+ *(ext + 1));
NetBootFileSize = 0;
switch (*ext) {
/* Fixed length fields */
- case 1: /* Subnet mask */
+ case 1: /* Subnet mask */
if (NetOurSubnetMask == 0)
- NetCopyIP (&NetOurSubnetMask, (IPaddr_t *) (ext + 2));
+ NetCopyIP(&NetOurSubnetMask, (IPaddr_t *) (ext + 2));
break;
- case 2: /* Time offset - Not yet supported */
+ case 2: /* Time offset - Not yet supported */
break;
/* Variable length fields */
- case 3: /* Gateways list */
- if (NetOurGatewayIP == 0) {
- NetCopyIP (&NetOurGatewayIP, (IPaddr_t *) (ext + 2));
- }
+ case 3: /* Gateways list */
+ if (NetOurGatewayIP == 0)
+ NetCopyIP(&NetOurGatewayIP, (IPaddr_t *) (ext + 2));
break;
- case 4: /* Time server - Not yet supported */
+ case 4: /* Time server - Not yet supported */
break;
- case 5: /* IEN-116 name server - Not yet supported */
+ case 5: /* IEN-116 name server - Not yet supported */
break;
case 6:
- if (NetOurDNSIP == 0) {
- NetCopyIP (&NetOurDNSIP, (IPaddr_t *) (ext + 2));
- }
+ if (NetOurDNSIP == 0)
+ NetCopyIP(&NetOurDNSIP, (IPaddr_t *) (ext + 2));
#if defined(CONFIG_BOOTP_DNS2)
- if ((NetOurDNS2IP == 0) && (size > 4)) {
- NetCopyIP (&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4));
- }
+ if ((NetOurDNS2IP == 0) && (size > 4))
+ NetCopyIP(&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4));
#endif
break;
- case 7: /* Log server - Not yet supported */
+ case 7: /* Log server - Not yet supported */
break;
- case 8: /* Cookie/Quote server - Not yet supported */
+ case 8: /* Cookie/Quote server - Not yet supported */
break;
- case 9: /* LPR server - Not yet supported */
+ case 9: /* LPR server - Not yet supported */
break;
- case 10: /* Impress server - Not yet supported */
+ case 10: /* Impress server - Not yet supported */
break;
- case 11: /* RPL server - Not yet supported */
+ case 11: /* RPL server - Not yet supported */
break;
- case 12: /* Host name */
+ case 12: /* Host name */
if (NetOurHostName[0] == 0) {
- size = truncate_sz ("Host Name", sizeof (NetOurHostName), size);
- memcpy (&NetOurHostName, ext + 2, size);
+ size = truncate_sz("Host Name",
+ sizeof(NetOurHostName), size);
+ memcpy(&NetOurHostName, ext + 2, size);
NetOurHostName[size] = 0;
}
break;
- case 13: /* Boot file size */
+ case 13: /* Boot file size */
if (size == 2)
- NetBootFileSize = ntohs (*(ushort *) (ext + 2));
+ NetBootFileSize = ntohs(*(ushort *) (ext + 2));
else if (size == 4)
- NetBootFileSize = ntohl (*(ulong *) (ext + 2));
+ NetBootFileSize = ntohl(*(ulong *) (ext + 2));
break;
- case 14: /* Merit dump file - Not yet supported */
+ case 14: /* Merit dump file - Not yet supported */
break;
- case 15: /* Domain name - Not yet supported */
+ case 15: /* Domain name - Not yet supported */
break;
- case 16: /* Swap server - Not yet supported */
+ case 16: /* Swap server - Not yet supported */
break;
- case 17: /* Root path */
+ case 17: /* Root path */
if (NetOurRootPath[0] == 0) {
- size = truncate_sz ("Root Path", sizeof (NetOurRootPath), size);
- memcpy (&NetOurRootPath, ext + 2, size);
+ size = truncate_sz("Root Path",
+ sizeof(NetOurRootPath), size);
+ memcpy(&NetOurRootPath, ext + 2, size);
NetOurRootPath[size] = 0;
}
break;
- case 18: /* Extension path - Not yet supported */
+ case 18: /* Extension path - Not yet supported */
/*
* This can be used to send the information of the
* vendor area in another file that the client can
@@ -220,15 +211,21 @@ static void BootpVendorFieldProcess (u8 * ext)
*/
break;
/* IP host layer fields */
- case 40: /* NIS Domain name */
+ case 40: /* NIS Domain name */
if (NetOurNISDomain[0] == 0) {
- size = truncate_sz ("NIS Domain Name", sizeof (NetOurNISDomain), size);
- memcpy (&NetOurNISDomain, ext + 2, size);
+ size = truncate_sz("NIS Domain Name",
+ sizeof(NetOurNISDomain), size);
+ memcpy(&NetOurNISDomain, ext + 2, size);
NetOurNISDomain[size] = 0;
}
break;
+#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
+ case 42: /* NTP server IP */
+ NetCopyIP(&NetNtpServerIP, (IPaddr_t *) (ext + 2));
+ break;
+#endif
/* Application layer fields */
- case 43: /* Vendor specific info - Not yet supported */
+ case 43: /* Vendor specific info - Not yet supported */
/*
* Binary information to exchange specific
* product information.
@@ -238,7 +235,7 @@ static void BootpVendorFieldProcess (u8 * ext)
}
}
-static void BootpVendorProcess (u8 * ext, int size)
+static void BootpVendorProcess(u8 *ext, int size)
{
u8 *end = ext + size;
@@ -252,11 +249,11 @@ static void BootpVendorProcess (u8 * ext, int size)
ext += ext[1] + 2;
if (ext <= end)
- BootpVendorFieldProcess (opt);
+ BootpVendorFieldProcess(opt);
}
}
- debug("[BOOTP] Received fields: \n");
+ debug("[BOOTP] Received fields:\n");
if (NetOurSubnetMask)
debug("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask);
@@ -277,61 +274,50 @@ static void BootpVendorProcess (u8 * ext, int size)
if (NetBootFileSize)
debug("NetBootFileSize: %d\n", NetBootFileSize);
+
+#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
+ if (NetNtpServerIP)
+ debug("NetNtpServerIP : %pI4\n", &NetNtpServerIP);
+#endif
}
+
/*
* Handle a BOOTP received packet.
*/
static void
-BootpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
+BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+ unsigned len)
{
- Bootp_t *bp;
- char *s;
+ struct Bootp_t *bp;
debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
- src, dest, len, sizeof (Bootp_t));
+ src, dest, len, sizeof(struct Bootp_t));
- bp = (Bootp_t *)pkt;
+ bp = (struct Bootp_t *)pkt;
- if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
+ /* Filter out pkts we don't want */
+ if (BootpCheckPkt(pkt, dest, src, len))
return;
/*
* Got a good BOOTP reply. Copy the data into our variables.
*/
#ifdef CONFIG_STATUS_LED
- status_led_set (STATUS_LED_BOOT, STATUS_LED_OFF);
+ status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF);
#endif
BootpCopyNetParams(bp); /* Store net parameters from reply */
/* Retrieve extended information (we must parse the vendor area) */
- if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
+ if (NetReadLong((ulong *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
BootpVendorProcess((uchar *)&bp->bp_vend[4], len);
NetSetTimeout(0, (thand_f *)0);
+ bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
debug("Got good BOOTP\n");
- if ((s = getenv("autoload")) != NULL) {
- if (*s == 'n') {
- /*
- * Just use BOOTP to configure system;
- * Do not use TFTP to load the bootfile.
- */
- NetState = NETLOOP_SUCCESS;
- return;
-#if defined(CONFIG_CMD_NFS)
- } else if (strcmp(s, "NFS") == 0) {
- /*
- * Use NFS to load the bootfile.
- */
- NfsStart();
- return;
-#endif
- }
- }
-
- TftpStart();
+ net_auto_load();
}
#endif
@@ -342,22 +328,41 @@ static void
BootpTimeout(void)
{
if (BootpTry >= TIMEOUT_COUNT) {
- puts ("\nRetry count exceeded; starting again\n");
- NetStartAgain ();
+#ifdef CONFIG_BOOTP_MAY_FAIL
+ puts("\nRetry count exceeded\n");
+ net_set_state(NETLOOP_FAIL);
+#else
+ puts("\nRetry count exceeded; starting again\n");
+ NetStartAgain();
+#endif
} else {
- NetSetTimeout (TIMEOUT, BootpTimeout);
- BootpRequest ();
+ NetSetTimeout(TIMEOUT, BootpTimeout);
+ BootpRequest();
}
}
+#define put_vci(e, str) \
+ do { \
+ size_t vci_strlen = strlen(str); \
+ *e++ = 60; /* Vendor Class Identifier */ \
+ *e++ = vci_strlen; \
+ memcpy(e, str, vci_strlen); \
+ e += vci_strlen; \
+ } while (0)
+
/*
* Initialize BOOTP extension fields in the request.
*/
#if defined(CONFIG_CMD_DHCP)
-static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)
+static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID,
+ IPaddr_t RequestedIP)
{
u8 *start = e;
u8 *cnt;
+#if defined(CONFIG_BOOTP_PXE)
+ char *uuid;
+ u16 clientarch;
+#endif
#if defined(CONFIG_BOOTP_VENDOREX)
u8 *x;
@@ -377,11 +382,11 @@ static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t R
*e++ = 57; /* Maximum DHCP Message Size */
*e++ = 2;
- *e++ = (576 - 312 + OPT_SIZE) >> 8;
- *e++ = (576 - 312 + OPT_SIZE) & 0xff;
+ *e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8;
+ *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
if (ServerID) {
- int tmp = ntohl (ServerID);
+ int tmp = ntohl(ServerID);
*e++ = 54; /* ServerID */
*e++ = 4;
@@ -392,7 +397,7 @@ static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t R
}
if (RequestedIP) {
- int tmp = ntohl (RequestedIP);
+ int tmp = ntohl(RequestedIP);
*e++ = 50; /* Requested IP */
*e++ = 4;
@@ -402,18 +407,53 @@ static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t R
*e++ = tmp & 0xff;
}
#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
- if ((hostname = getenv ("hostname"))) {
- int hostnamelen = strlen (hostname);
+ hostname = getenv("hostname");
+ if (hostname) {
+ int hostnamelen = strlen(hostname);
*e++ = 12; /* Hostname */
*e++ = hostnamelen;
- memcpy (e, hostname, hostnamelen);
+ memcpy(e, hostname, hostnamelen);
e += hostnamelen;
}
#endif
+#if defined(CONFIG_BOOTP_PXE)
+ clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
+ *e++ = 93; /* Client System Architecture */
+ *e++ = 2;
+ *e++ = (clientarch >> 8) & 0xff;
+ *e++ = clientarch & 0xff;
+
+ *e++ = 94; /* Client Network Interface Identifier */
+ *e++ = 3;
+ *e++ = 1; /* type field for UNDI */
+ *e++ = 0; /* major revision */
+ *e++ = 0; /* minor revision */
+
+ uuid = getenv("pxeuuid");
+
+ if (uuid) {
+ if (uuid_str_valid(uuid)) {
+ *e++ = 97; /* Client Machine Identifier */
+ *e++ = 17;
+ *e++ = 0; /* type 0 - UUID */
+
+ uuid_str_to_bin(uuid, e);
+ e += 16;
+ } else {
+ printf("Invalid pxeuuid: %s\n", uuid);
+ }
+ }
+#endif
+
+#ifdef CONFIG_BOOTP_VCI_STRING
+ put_vci(e, CONFIG_BOOTP_VCI_STRING);
+#endif
+
#if defined(CONFIG_BOOTP_VENDOREX)
- if ((x = dhcp_vendorex_prep (e)))
+ x = dhcp_vendorex_prep(e);
+ if (x)
return x - start;
#endif
@@ -464,7 +504,7 @@ static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t R
/* Pad to minimal length */
#ifdef CONFIG_DHCP_MIN_EXT_LEN
- while ((e - start) <= CONFIG_DHCP_MIN_EXT_LEN)
+ while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
*e++ = 0;
#endif
@@ -473,9 +513,9 @@ static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t R
#else
/*
- * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
+ * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
*/
-static int BootpExtended (u8 * e)
+static int BootpExtended(u8 *e)
{
u8 *start = e;
@@ -491,8 +531,17 @@ static int BootpExtended (u8 * e)
*e++ = 57; /* Maximum DHCP Message Size */
*e++ = 2;
- *e++ = (576 - 312 + OPT_SIZE) >> 16;
- *e++ = (576 - 312 + OPT_SIZE) & 0xff;
+ *e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16;
+ *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
+#endif
+
+#if defined(CONFIG_BOOTP_VCI_STRING) || \
+ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING))
+#ifdef CONFIG_SPL_BUILD
+ put_vci(e, CONFIG_SPL_NET_VCI_STRING);
+#else
+ put_vci(e, CONFIG_BOOTP_VCI_STRING);
+#endif
#endif
#if defined(CONFIG_BOOTP_SUBNETMASK)
@@ -536,6 +585,11 @@ static int BootpExtended (u8 * e)
*e++ = 32;
e += 32;
#endif
+#if defined(CONFIG_BOOTP_NTPSERVER)
+ *e++ = 42;
+ *e++ = 4;
+ e += 4;
+#endif
*e++ = 255; /* End of the list */
@@ -544,93 +598,56 @@ static int BootpExtended (u8 * e)
#endif
void
-BootpRequest (void)
+BootpRequest(void)
{
- volatile uchar *pkt, *iphdr;
- Bootp_t *bp;
- int ext_len, pktlen, iplen;
+ uchar *pkt, *iphdr;
+ struct Bootp_t *bp;
+ int extlen, pktlen, iplen;
+ int eth_hdr_size;
+#ifdef CONFIG_BOOTP_RANDOM_DELAY
+ ulong i, rand_ms;
+#endif
+ bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
#if defined(CONFIG_CMD_DHCP)
dhcp_state = INIT;
#endif
#ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */
- unsigned char bi_enetaddr[6];
- int reg;
- ulong tst1, tst2, sum, m_mask, m_value = 0;
-
- if (BootpTry ==0) {
- /* get our mac */
- eth_getenv_enetaddr("ethaddr", bi_enetaddr);
-
- debug("BootpRequest => Our Mac: ");
- for (reg=0; reg<6; reg++)
- debug("%x%c", bi_enetaddr[reg], reg==5 ? '\n' : ':');
-
- /* Mac-Manipulation 2 get seed1 */
- tst1=0;
- tst2=0;
- for (reg=2; reg<6; reg++) {
- tst1 = tst1 << 8;
- tst1 = tst1 | bi_enetaddr[reg];
- }
- for (reg=0; reg<2; reg++) {
- tst2 = tst2 | bi_enetaddr[reg];
- tst2 = tst2 << 8;
- }
-
- seed1 = tst1^tst2;
-
- /* Mirror seed1*/
- m_mask=0x1;
- for (reg=1;reg<=32;reg++) {
- m_value |= (m_mask & seed1);
- seed1 = seed1 >> 1;
- m_value = m_value << 1;
- }
- seed1 = m_value;
- seed2 = 0xB78D0945;
- }
-
- /* Random Number Generator */
-
- for (reg=0;reg<=0;reg++) {
- sum = seed1 + seed2;
- if (sum < seed1 || sum < seed2)
- sum++;
- seed2 = seed1;
- seed1 = sum;
+ if (BootpTry == 0)
+ srand_mac();
- if (BootpTry<=2) { /* Start with max 1024 * 1ms */
- sum = sum >> (22-BootpTry);
- } else { /*After 3rd BOOTP request max 8192 * 1ms */
- sum = sum >> 19;
- }
- }
+ if (BootpTry <= 2) /* Start with max 1024 * 1ms */
+ rand_ms = rand() >> (22 - BootpTry);
+ else /* After 3rd BOOTP request max 8192 * 1ms */
+ rand_ms = rand() >> 19;
- printf ("Random delay: %ld ms...\n", sum);
- for (reg=0; reg <sum; reg++) {
+ printf("Random delay: %ld ms...\n", rand_ms);
+ for (i = 0; i < rand_ms; i++)
udelay(1000); /*Wait 1ms*/
- }
+
#endif /* CONFIG_BOOTP_RANDOM_DELAY */
printf("BOOTP broadcast %d\n", ++BootpTry);
pkt = NetTxPacket;
- memset ((void*)pkt, 0, PKTSIZE);
+ memset((void *)pkt, 0, PKTSIZE);
- pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
+ eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP);
+ pkt += eth_hdr_size;
/*
- * Next line results in incorrect packet size being transmitted, resulting
- * in errors in some DHCP servers, reporting missing bytes. Size must be
- * set in packet header after extension length has been determined.
+ * Next line results in incorrect packet size being transmitted,
+ * resulting in errors in some DHCP servers, reporting missing bytes.
+ * Size must be set in packet header after extension length has been
+ * determined.
* C. Hallinan, DS4.COM, Inc.
*/
- /* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (Bootp_t)); */
- iphdr = pkt; /* We need this later for NetSetIP() */
- pkt += IP_HDR_SIZE;
+ /* net_set_udp_header(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC,
+ sizeof (struct Bootp_t)); */
+ iphdr = pkt; /* We need this later for net_set_udp_header() */
+ pkt += IP_UDP_HDR_SIZE;
- bp = (Bootp_t *)pkt;
+ bp = (struct Bootp_t *)pkt;
bp->bp_op = OP_BOOTREQUEST;
bp->bp_htype = HWT_ETHER;
bp->bp_hlen = HWL_ETHER;
@@ -640,14 +657,14 @@ BootpRequest (void)
NetWriteIP(&bp->bp_yiaddr, 0);
NetWriteIP(&bp->bp_siaddr, 0);
NetWriteIP(&bp->bp_giaddr, 0);
- memcpy (bp->bp_chaddr, NetOurEther, 6);
- copy_filename (bp->bp_file, BootFile, sizeof(bp->bp_file));
+ memcpy(bp->bp_chaddr, NetOurEther, 6);
+ copy_filename(bp->bp_file, BootFile, sizeof(bp->bp_file));
/* Request additional information from the BOOTP/DHCP server */
#if defined(CONFIG_CMD_DHCP)
- ext_len = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
+ extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
#else
- ext_len = BootpExtended((u8 *)bp->bp_vend);
+ extlen = BootpExtended((u8 *)bp->bp_vend);
#endif
/*
@@ -666,22 +683,22 @@ BootpRequest (void)
* Calculate proper packet lengths taking into account the
* variable size of the options field
*/
- pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
- iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
- NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
+ iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
+ pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
+ net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
#if defined(CONFIG_CMD_DHCP)
dhcp_state = SELECTING;
- NetSetHandler(DhcpHandler);
+ net_set_udp_handler(DhcpHandler);
#else
- NetSetHandler(BootpHandler);
+ net_set_udp_handler(BootpHandler);
#endif
NetSendPacket(NetTxPacket, pktlen);
}
#if defined(CONFIG_CMD_DHCP)
-static void DhcpOptionsProcess (uchar * popt, Bootp_t *bp)
+static void DhcpOptionsProcess(uchar *popt, struct Bootp_t *bp)
{
uchar *end = popt + BOOTP_HDR_SIZE;
int oplen, size;
@@ -693,50 +710,53 @@ static void DhcpOptionsProcess (uchar * popt, Bootp_t *bp)
oplen = *(popt + 1);
switch (*popt) {
case 1:
- NetCopyIP (&NetOurSubnetMask, (popt + 2));
+ NetCopyIP(&NetOurSubnetMask, (popt + 2));
break;
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
case 2: /* Time offset */
to_ptr = &NetTimeOffset;
- NetCopyLong ((ulong *)to_ptr, (ulong *)(popt + 2));
- NetTimeOffset = ntohl (NetTimeOffset);
+ NetCopyLong((ulong *)to_ptr, (ulong *)(popt + 2));
+ NetTimeOffset = ntohl(NetTimeOffset);
break;
#endif
case 3:
- NetCopyIP (&NetOurGatewayIP, (popt + 2));
+ NetCopyIP(&NetOurGatewayIP, (popt + 2));
break;
case 6:
- NetCopyIP (&NetOurDNSIP, (popt + 2));
+ NetCopyIP(&NetOurDNSIP, (popt + 2));
#if defined(CONFIG_BOOTP_DNS2)
- if (*(popt + 1) > 4) {
- NetCopyIP (&NetOurDNS2IP, (popt + 2 + 4));
- }
+ if (*(popt + 1) > 4)
+ NetCopyIP(&NetOurDNS2IP, (popt + 2 + 4));
#endif
break;
case 12:
- size = truncate_sz ("Host Name", sizeof (NetOurHostName), oplen);
- memcpy (&NetOurHostName, popt + 2, size);
+ size = truncate_sz("Host Name",
+ sizeof(NetOurHostName), oplen);
+ memcpy(&NetOurHostName, popt + 2, size);
NetOurHostName[size] = 0;
break;
case 15: /* Ignore Domain Name Option */
break;
case 17:
- size = truncate_sz ("Root Path", sizeof (NetOurRootPath), oplen);
- memcpy (&NetOurRootPath, popt + 2, size);
+ size = truncate_sz("Root Path",
+ sizeof(NetOurRootPath), oplen);
+ memcpy(&NetOurRootPath, popt + 2, size);
NetOurRootPath[size] = 0;
break;
+ case 28: /* Ignore Broadcast Address Option */
+ break;
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
case 42: /* NTP server IP */
- NetCopyIP (&NetNtpServerIP, (popt + 2));
+ NetCopyIP(&NetNtpServerIP, (popt + 2));
break;
#endif
case 51:
- NetCopyLong (&dhcp_leasetime, (ulong *) (popt + 2));
+ NetCopyLong(&dhcp_leasetime, (ulong *) (popt + 2));
break;
case 53: /* Ignore Message Type Option */
break;
case 54:
- NetCopyIP (&NetDHCPServerIP, (popt + 2));
+ NetCopyIP(&NetDHCPServerIP, (popt + 2));
break;
case 58: /* Ignore Renewal Time Option */
break;
@@ -751,7 +771,7 @@ static void DhcpOptionsProcess (uchar * popt, Bootp_t *bp)
* pass the bootp packet pointer into here as the
* second arg
*/
- size = truncate_sz ("Opt Boot File",
+ size = truncate_sz("Opt Boot File",
sizeof(bp->bp_file),
oplen);
if (bp->bp_file[0] == '\0' && size > 0) {
@@ -772,10 +792,11 @@ static void DhcpOptionsProcess (uchar * popt, Bootp_t *bp)
break;
default:
#if defined(CONFIG_BOOTP_VENDOREX)
- if (dhcp_vendorex_proc (popt))
+ if (dhcp_vendorex_proc(popt))
break;
#endif
- printf ("*** Unhandled DHCP Option in OFFER/ACK: %d\n", *popt);
+ printf("*** Unhandled DHCP Option in OFFER/ACK:"
+ " %d\n", *popt);
break;
}
popt += oplen + 2; /* Process next option */
@@ -784,42 +805,44 @@ static void DhcpOptionsProcess (uchar * popt, Bootp_t *bp)
static int DhcpMessageType(unsigned char *popt)
{
- if (NetReadLong((ulong*)popt) != htonl(BOOTP_VENDOR_MAGIC))
+ if (NetReadLong((ulong *)popt) != htonl(BOOTP_VENDOR_MAGIC))
return -1;
popt += 4;
- while ( *popt != 0xff ) {
- if ( *popt == 53 ) /* DHCP Message Type */
+ while (*popt != 0xff) {
+ if (*popt == 53) /* DHCP Message Type */
return *(popt + 2);
popt += *(popt + 1) + 2; /* Scan through all options */
}
return -1;
}
-static void DhcpSendRequestPkt(Bootp_t *bp_offer)
+static void DhcpSendRequestPkt(struct Bootp_t *bp_offer)
{
- volatile uchar *pkt, *iphdr;
- Bootp_t *bp;
+ uchar *pkt, *iphdr;
+ struct Bootp_t *bp;
int pktlen, iplen, extlen;
+ int eth_hdr_size;
IPaddr_t OfferedIP;
debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
pkt = NetTxPacket;
- memset ((void*)pkt, 0, PKTSIZE);
+ memset((void *)pkt, 0, PKTSIZE);
- pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
+ eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP);
+ pkt += eth_hdr_size;
- iphdr = pkt; /* We'll need this later to set proper pkt size */
- pkt += IP_HDR_SIZE;
+ iphdr = pkt; /* We'll need this later to set proper pkt size */
+ pkt += IP_UDP_HDR_SIZE;
- bp = (Bootp_t *)pkt;
+ bp = (struct Bootp_t *)pkt;
bp->bp_op = OP_BOOTREQUEST;
bp->bp_htype = HWT_ETHER;
bp->bp_hlen = HWL_ETHER;
bp->bp_hops = 0;
bp->bp_secs = htons(get_timer(0) / 1000);
- /* Do not set the client IP, your IP, or server IP yet, since it hasn't been ACK'ed by
- * the server yet */
+ /* Do not set the client IP, your IP, or server IP yet, since it
+ * hasn't been ACK'ed by the server yet */
/*
* RFC3046 requires Relay Agents to discard packets with
@@ -827,7 +850,7 @@ static void DhcpSendRequestPkt(Bootp_t *bp_offer)
*/
NetWriteIP(&bp->bp_giaddr, 0);
- memcpy (bp->bp_chaddr, NetOurEther, 6);
+ memcpy(bp->bp_chaddr, NetOurEther, 6);
/*
* ID is the id of the OFFER packet
@@ -841,16 +864,17 @@ static void DhcpSendRequestPkt(Bootp_t *bp_offer)
/* Copy offered IP into the parameters request list */
NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr);
- extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP);
+ extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST,
+ NetDHCPServerIP, OfferedIP);
- pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
- iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
- NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
+ iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
+ pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
+ net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
- debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
#endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
+ debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
NetSendPacket(NetTxPacket, pktlen);
}
@@ -858,38 +882,41 @@ static void DhcpSendRequestPkt(Bootp_t *bp_offer)
* Handle DHCP received packets.
*/
static void
-DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
+DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+ unsigned len)
{
- Bootp_t *bp = (Bootp_t *)pkt;
+ struct Bootp_t *bp = (struct Bootp_t *)pkt;
debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
src, dest, len, dhcp_state);
- if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
+ /* Filter out pkts we don't want */
+ if (BootpCheckPkt(pkt, dest, src, len))
return;
- debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n",
- src, dest, len, dhcp_state);
+ debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state:"
+ " %d\n", src, dest, len, dhcp_state);
switch (dhcp_state) {
case SELECTING:
/*
* Wait an appropriate time for any potential DHCPOFFER packets
- * to arrive. Then select one, and generate DHCPREQUEST response.
- * If filename is in format we recognize, assume it is a valid
- * OFFER from a server we want.
+ * to arrive. Then select one, and generate DHCPREQUEST
+ * response. If filename is in format we recognize, assume it
+ * is a valid OFFER from a server we want.
*/
debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
#ifdef CONFIG_SYS_BOOTFILE_PREFIX
if (strncmp(bp->bp_file,
CONFIG_SYS_BOOTFILE_PREFIX,
- strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0 ) {
+ strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
debug("TRANSITIONING TO REQUESTING STATE\n");
dhcp_state = REQUESTING;
- if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
+ if (NetReadLong((ulong *)&bp->bp_vend[0]) ==
+ htonl(BOOTP_VENDOR_MAGIC))
DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
NetSetTimeout(TIMEOUT, BootpTimeout);
@@ -903,35 +930,19 @@ DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
case REQUESTING:
debug("DHCP State: REQUESTING\n");
- if ( DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK ) {
- char *s;
-
- if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
+ if (DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK) {
+ if (NetReadLong((ulong *)&bp->bp_vend[0]) ==
+ htonl(BOOTP_VENDOR_MAGIC))
DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
- BootpCopyNetParams(bp); /* Store net params from reply */
+ /* Store net params from reply */
+ BootpCopyNetParams(bp);
dhcp_state = BOUND;
- printf ("DHCP client bound to address %pI4\n", &NetOurIP);
-
- /* Obey the 'autoload' setting */
- if ((s = getenv("autoload")) != NULL) {
- if (*s == 'n') {
- /*
- * Just use BOOTP to configure system;
- * Do not use TFTP to load the bootfile.
- */
- NetState = NETLOOP_SUCCESS;
- return;
-#if defined(CONFIG_CMD_NFS)
- } else if (strcmp(s, "NFS") == 0) {
- /*
- * Use NFS to load the bootfile.
- */
- NfsStart();
- return;
-#endif
- }
- }
- TftpStart();
+ printf("DHCP client bound to address %pI4\n",
+ &NetOurIP);
+ bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
+ "bootp_stop");
+
+ net_auto_load();
return;
}
break;
@@ -939,7 +950,7 @@ DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
/* DHCP client bound to address */
break;
default:
- puts ("DHCP: INVALID STATE\n");
+ puts("DHCP: INVALID STATE\n");
break;
}
diff --git a/net/bootp.h b/net/bootp.h
index 50625abea1..ecbcc4d509 100644
--- a/net/bootp.h
+++ b/net/bootp.h
@@ -10,7 +10,7 @@
#define __BOOTP_H__
#ifndef __NET_H__
-#include <net.h>
+#include <net.h>
#endif /* __NET_H__ */
/**********************************************************************/
@@ -19,36 +19,39 @@
* BOOTP header.
*/
#if defined(CONFIG_CMD_DHCP)
-#define OPT_SIZE 312 /* Minimum DHCP Options size per RFC2131 - results in 576 byte pkt */
+/* Minimum DHCP Options size per RFC2131 - results in 576 byte pkt */
+#define OPT_FIELD_SIZE 312
+#if defined(CONFIG_BOOTP_VENDOREX)
+extern u8 *dhcp_vendorex_prep(u8 *e); /*rtn new e after add own opts. */
+extern u8 *dhcp_vendorex_proc(u8 *e); /*rtn next e if mine,else NULL */
+#endif
#else
-#define OPT_SIZE 64
+#define OPT_FIELD_SIZE 64
#endif
-typedef struct
-{
- uchar bp_op; /* Operation */
+struct Bootp_t {
+ uchar bp_op; /* Operation */
# define OP_BOOTREQUEST 1
# define OP_BOOTREPLY 2
- uchar bp_htype; /* Hardware type */
+ uchar bp_htype; /* Hardware type */
# define HWT_ETHER 1
- uchar bp_hlen; /* Hardware address length */
+ uchar bp_hlen; /* Hardware address length */
# define HWL_ETHER 6
- uchar bp_hops; /* Hop count (gateway thing) */
- ulong bp_id; /* Transaction ID */
- ushort bp_secs; /* Seconds since boot */
- ushort bp_spare1; /* Alignment */
- IPaddr_t bp_ciaddr; /* Client IP address */
- IPaddr_t bp_yiaddr; /* Your (client) IP address */
- IPaddr_t bp_siaddr; /* Server IP address */
- IPaddr_t bp_giaddr; /* Gateway IP address */
- uchar bp_chaddr[16]; /* Client hardware address */
- char bp_sname[64]; /* Server host name */
- char bp_file[128]; /* Boot file name */
- char bp_vend[OPT_SIZE]; /* Vendor information */
-} Bootp_t;
-
-#define BOOTP_HDR_SIZE sizeof (Bootp_t)
-#define BOOTP_SIZE (ETHER_HDR_SIZE + IP_HDR_SIZE + BOOTP_HDR_SIZE)
+ uchar bp_hops; /* Hop count (gateway thing) */
+ ulong bp_id; /* Transaction ID */
+ ushort bp_secs; /* Seconds since boot */
+ ushort bp_spare1; /* Alignment */
+ IPaddr_t bp_ciaddr; /* Client IP address */
+ IPaddr_t bp_yiaddr; /* Your (client) IP address */
+ IPaddr_t bp_siaddr; /* Server IP address */
+ IPaddr_t bp_giaddr; /* Gateway IP address */
+ uchar bp_chaddr[16]; /* Client hardware address */
+ char bp_sname[64]; /* Server host name */
+ char bp_file[128]; /* Boot file name */
+ char bp_vend[OPT_FIELD_SIZE]; /* Vendor information */
+};
+
+#define BOOTP_HDR_SIZE sizeof(struct Bootp_t)
/**********************************************************************/
/*
@@ -56,16 +59,13 @@ typedef struct
*/
/* bootp.c */
-extern ulong BootpID; /* ID of cur BOOTP request */
-extern char BootFile[128]; /* Boot file name */
+extern ulong BootpID; /* ID of cur BOOTP request */
+extern char BootFile[128]; /* Boot file name */
extern int BootpTry;
-#ifdef CONFIG_BOOTP_RANDOM_DELAY
-extern ulong seed1, seed2; /* seed for random BOOTP delay */
-#endif
/* Send a BOOTP request */
-extern void BootpRequest (void);
+extern void BootpRequest(void);
/****************** DHCP Support *********************/
extern void DhcpRequest(void);
diff --git a/net/cdp.c b/net/cdp.c
new file mode 100644
index 0000000000..3d9559eb3b
--- /dev/null
+++ b/net/cdp.c
@@ -0,0 +1,366 @@
+/*
+ * Copied from Linux Monitor (LiMon) - Networking.
+ *
+ * Copyright 1994 - 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000 Roland Borde
+ * Copyright 2000 Paolo Scaffardi
+ * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
+ */
+
+#include <common.h>
+#include <net.h>
+#if defined(CONFIG_CDP_VERSION)
+#include <timestamp.h>
+#endif
+
+#include "cdp.h"
+
+/* Ethernet bcast address */
+const uchar NetCDPAddr[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
+
+#define CDP_DEVICE_ID_TLV 0x0001
+#define CDP_ADDRESS_TLV 0x0002
+#define CDP_PORT_ID_TLV 0x0003
+#define CDP_CAPABILITIES_TLV 0x0004
+#define CDP_VERSION_TLV 0x0005
+#define CDP_PLATFORM_TLV 0x0006
+#define CDP_NATIVE_VLAN_TLV 0x000a
+#define CDP_APPLIANCE_VLAN_TLV 0x000e
+#define CDP_TRIGGER_TLV 0x000f
+#define CDP_POWER_CONSUMPTION_TLV 0x0010
+#define CDP_SYSNAME_TLV 0x0014
+#define CDP_SYSOBJECT_TLV 0x0015
+#define CDP_MANAGEMENT_ADDRESS_TLV 0x0016
+
+#define CDP_TIMEOUT 250UL /* one packet every 250ms */
+
+static int CDPSeq;
+static int CDPOK;
+
+ushort CDPNativeVLAN;
+ushort CDPApplianceVLAN;
+
+static const uchar CDP_SNAP_hdr[8] = {
+ 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
+
+static ushort
+CDP_compute_csum(const uchar *buff, ushort len)
+{
+ ushort csum;
+ int odd;
+ ulong result = 0;
+ ushort leftover;
+ ushort *p;
+
+ if (len > 0) {
+ odd = 1 & (ulong)buff;
+ if (odd) {
+ result = *buff << 8;
+ len--;
+ buff++;
+ }
+ while (len > 1) {
+ p = (ushort *)buff;
+ result += *p++;
+ buff = (uchar *)p;
+ if (result & 0x80000000)
+ result = (result & 0xFFFF) + (result >> 16);
+ len -= 2;
+ }
+ if (len) {
+ leftover = (signed short)(*(const signed char *)buff);
+ /*
+ * CISCO SUCKS big time! (and blows too):
+ * CDP uses the IP checksum algorithm with a twist;
+ * for the last byte it *sign* extends and sums.
+ */
+ result = (result & 0xffff0000) |
+ ((result + leftover) & 0x0000ffff);
+ }
+ while (result >> 16)
+ result = (result & 0xFFFF) + (result >> 16);
+
+ if (odd)
+ result = ((result >> 8) & 0xff) |
+ ((result & 0xff) << 8);
+ }
+
+ /* add up 16-bit and 17-bit words for 17+c bits */
+ result = (result & 0xffff) + (result >> 16);
+ /* add up 16-bit and 2-bit for 16+c bit */
+ result = (result & 0xffff) + (result >> 16);
+ /* add up carry.. */
+ result = (result & 0xffff) + (result >> 16);
+
+ /* negate */
+ csum = ~(ushort)result;
+
+ /* run time endian detection */
+ if (csum != htons(csum)) /* little endian */
+ csum = htons(csum);
+
+ return csum;
+}
+
+static int
+CDPSendTrigger(void)
+{
+ uchar *pkt;
+ ushort *s;
+ ushort *cp;
+ struct ethernet_hdr *et;
+ int len;
+ ushort chksum;
+#if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \
+ defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM)
+ char buf[32];
+#endif
+
+ pkt = NetTxPacket;
+ et = (struct ethernet_hdr *)pkt;
+
+ /* NOTE: trigger sent not on any VLAN */
+
+ /* form ethernet header */
+ memcpy(et->et_dest, NetCDPAddr, 6);
+ memcpy(et->et_src, NetOurEther, 6);
+
+ pkt += ETHER_HDR_SIZE;
+
+ /* SNAP header */
+ memcpy((uchar *)pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr));
+ pkt += sizeof(CDP_SNAP_hdr);
+
+ /* CDP header */
+ *pkt++ = 0x02; /* CDP version 2 */
+ *pkt++ = 180; /* TTL */
+ s = (ushort *)pkt;
+ cp = s;
+ /* checksum (0 for later calculation) */
+ *s++ = htons(0);
+
+ /* CDP fields */
+#ifdef CONFIG_CDP_DEVICE_ID
+ *s++ = htons(CDP_DEVICE_ID_TLV);
+ *s++ = htons(CONFIG_CDP_DEVICE_ID);
+ sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther);
+ memcpy((uchar *)s, buf, 16);
+ s += 16 / 2;
+#endif
+
+#ifdef CONFIG_CDP_PORT_ID
+ *s++ = htons(CDP_PORT_ID_TLV);
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
+ len = strlen(buf);
+ if (len & 1) /* make it even */
+ len++;
+ *s++ = htons(len + 4);
+ memcpy((uchar *)s, buf, len);
+ s += len / 2;
+#endif
+
+#ifdef CONFIG_CDP_CAPABILITIES
+ *s++ = htons(CDP_CAPABILITIES_TLV);
+ *s++ = htons(8);
+ *(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
+ s += 2;
+#endif
+
+#ifdef CONFIG_CDP_VERSION
+ *s++ = htons(CDP_VERSION_TLV);
+ memset(buf, 0, sizeof(buf));
+ strcpy(buf, CONFIG_CDP_VERSION);
+ len = strlen(buf);
+ if (len & 1) /* make it even */
+ len++;
+ *s++ = htons(len + 4);
+ memcpy((uchar *)s, buf, len);
+ s += len / 2;
+#endif
+
+#ifdef CONFIG_CDP_PLATFORM
+ *s++ = htons(CDP_PLATFORM_TLV);
+ memset(buf, 0, sizeof(buf));
+ strcpy(buf, CONFIG_CDP_PLATFORM);
+ len = strlen(buf);
+ if (len & 1) /* make it even */
+ len++;
+ *s++ = htons(len + 4);
+ memcpy((uchar *)s, buf, len);
+ s += len / 2;
+#endif
+
+#ifdef CONFIG_CDP_TRIGGER
+ *s++ = htons(CDP_TRIGGER_TLV);
+ *s++ = htons(8);
+ *(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
+ s += 2;
+#endif
+
+#ifdef CONFIG_CDP_POWER_CONSUMPTION
+ *s++ = htons(CDP_POWER_CONSUMPTION_TLV);
+ *s++ = htons(6);
+ *s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
+#endif
+
+ /* length of ethernet packet */
+ len = (uchar *)s - ((uchar *)NetTxPacket + ETHER_HDR_SIZE);
+ et->et_protlen = htons(len);
+
+ len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr);
+ chksum = CDP_compute_csum((uchar *)NetTxPacket + len,
+ (uchar *)s - (NetTxPacket + len));
+ if (chksum == 0)
+ chksum = 0xFFFF;
+ *cp = htons(chksum);
+
+ NetSendPacket(NetTxPacket, (uchar *)s - NetTxPacket);
+ return 0;
+}
+
+static void
+CDPTimeout(void)
+{
+ CDPSeq++;
+
+ if (CDPSeq < 3) {
+ NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
+ CDPSendTrigger();
+ return;
+ }
+
+ /* if not OK try again */
+ if (!CDPOK)
+ NetStartAgain();
+ else
+ net_set_state(NETLOOP_SUCCESS);
+}
+
+void cdp_receive(const uchar *pkt, unsigned len)
+{
+ const uchar *t;
+ const ushort *ss;
+ ushort type, tlen;
+ ushort vlan, nvlan;
+
+ /* minimum size? */
+ if (len < sizeof(CDP_SNAP_hdr) + 4)
+ goto pkt_short;
+
+ /* check for valid CDP SNAP header */
+ if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0)
+ return;
+
+ pkt += sizeof(CDP_SNAP_hdr);
+ len -= sizeof(CDP_SNAP_hdr);
+
+ /* Version of CDP protocol must be >= 2 and TTL != 0 */
+ if (pkt[0] < 0x02 || pkt[1] == 0)
+ return;
+
+ /*
+ * if version is greater than 0x02 maybe we'll have a problem;
+ * output a warning
+ */
+ if (pkt[0] != 0x02)
+ printf("**WARNING: CDP packet received with a protocol version "
+ "%d > 2\n", pkt[0] & 0xff);
+
+ if (CDP_compute_csum(pkt, len) != 0)
+ return;
+
+ pkt += 4;
+ len -= 4;
+
+ vlan = htons(-1);
+ nvlan = htons(-1);
+ while (len > 0) {
+ if (len < 4)
+ goto pkt_short;
+
+ ss = (const ushort *)pkt;
+ type = ntohs(ss[0]);
+ tlen = ntohs(ss[1]);
+ if (tlen > len)
+ goto pkt_short;
+
+ pkt += tlen;
+ len -= tlen;
+
+ ss += 2; /* point ss to the data of the TLV */
+ tlen -= 4;
+
+ switch (type) {
+ case CDP_DEVICE_ID_TLV:
+ break;
+ case CDP_ADDRESS_TLV:
+ break;
+ case CDP_PORT_ID_TLV:
+ break;
+ case CDP_CAPABILITIES_TLV:
+ break;
+ case CDP_VERSION_TLV:
+ break;
+ case CDP_PLATFORM_TLV:
+ break;
+ case CDP_NATIVE_VLAN_TLV:
+ nvlan = *ss;
+ break;
+ case CDP_APPLIANCE_VLAN_TLV:
+ t = (const uchar *)ss;
+ while (tlen > 0) {
+ if (tlen < 3)
+ goto pkt_short;
+
+ ss = (const ushort *)(t + 1);
+
+#ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
+ if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
+ vlan = *ss;
+#else
+ /* XXX will this work; dunno */
+ vlan = ntohs(*ss);
+#endif
+ t += 3; tlen -= 3;
+ }
+ break;
+ case CDP_TRIGGER_TLV:
+ break;
+ case CDP_POWER_CONSUMPTION_TLV:
+ break;
+ case CDP_SYSNAME_TLV:
+ break;
+ case CDP_SYSOBJECT_TLV:
+ break;
+ case CDP_MANAGEMENT_ADDRESS_TLV:
+ break;
+ }
+ }
+
+ CDPApplianceVLAN = vlan;
+ CDPNativeVLAN = nvlan;
+
+ CDPOK = 1;
+ return;
+
+ pkt_short:
+ printf("** CDP packet is too short\n");
+ return;
+}
+
+void
+CDPStart(void)
+{
+ printf("Using %s device\n", eth_get_name());
+ CDPSeq = 0;
+ CDPOK = 0;
+
+ CDPNativeVLAN = htons(-1);
+ CDPApplianceVLAN = htons(-1);
+
+ NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
+
+ CDPSendTrigger();
+}
diff --git a/net/cdp.h b/net/cdp.h
new file mode 100644
index 0000000000..ec7315af79
--- /dev/null
+++ b/net/cdp.h
@@ -0,0 +1,21 @@
+/*
+ * Copied from Linux Monitor (LiMon) - Networking.
+ *
+ * Copyright 1994 - 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000 Roland Borde
+ * Copyright 2000 Paolo Scaffardi
+ * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
+ */
+
+#if defined(CONFIG_CMD_CDP)
+
+#ifndef __CDP_H__
+#define __CDP_H__
+
+void CDPStart(void);
+/* Process a received CDP packet */
+void cdp_receive(const uchar *pkt, unsigned len);
+
+#endif /* __CDP_H__ */
+#endif
diff --git a/net/dns.c b/net/dns.c
index bb3e3f54e0..ff9ddffc9d 100644
--- a/net/dns.c
+++ b/net/dns.c
@@ -25,6 +25,7 @@
#include <common.h>
#include <command.h>
#include <net.h>
+#include <asm/unaligned.h>
#include "dns.h"
@@ -44,7 +45,7 @@ DnsSend(void)
enum dns_query_type qtype = DNS_A_RECORD;
name = NetDNSResolve;
- pkt = p = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE);
+ pkt = p = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE);
/* Prepare DNS packet header */
header = (struct header *) pkt;
@@ -97,11 +98,11 @@ static void
DnsTimeout(void)
{
puts("Timeout\n");
- NetState = NETLOOP_FAIL;
+ net_set_state(NETLOOP_FAIL);
}
static void
-DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
+DnsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
{
struct header *header;
const unsigned char *p, *e, *s;
@@ -109,7 +110,6 @@ DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
int found, stop, dlen;
char IPStr[22];
IPaddr_t IPAddress;
- short tmp;
debug("%s\n", __func__);
@@ -120,15 +120,15 @@ DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
debug("0x%p - 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
pkt+i, pkt[i], pkt[i+1], pkt[i+2], pkt[i+3]);
- /* We sent 1 query. We want to see more that 1 answer. */
+ /* We sent one query. We want to have a single answer: */
header = (struct header *) pkt;
if (ntohs(header->nqueries) != 1)
return;
/* Received 0 answers */
if (header->nanswers == 0) {
- puts("DNS server returned no answers\n");
- NetState = NETLOOP_SUCCESS;
+ puts("DNS: host not found\n");
+ net_set_state(NETLOOP_SUCCESS);
return;
}
@@ -139,10 +139,9 @@ DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
continue;
/* We sent query class 1, query type 1 */
- tmp = p[1] | (p[2] << 8);
- if (&p[5] > e || ntohs(tmp) != DNS_A_RECORD) {
- puts("DNS response was not A record\n");
- NetState = NETLOOP_SUCCESS;
+ if (&p[5] > e || get_unaligned_be16(p+1) != DNS_A_RECORD) {
+ puts("DNS: response was not an A record\n");
+ net_set_state(NETLOOP_SUCCESS);
return;
}
@@ -160,14 +159,12 @@ DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
}
debug("Name (Offset in header): %d\n", p[1]);
- tmp = p[2] | (p[3] << 8);
- type = ntohs(tmp);
+ type = get_unaligned_be16(p+2);
debug("type = %d\n", type);
if (type == DNS_CNAME_RECORD) {
/* CNAME answer. shift to the next section */
debug("Found canonical name\n");
- tmp = p[10] | (p[11] << 8);
- dlen = ntohs(tmp);
+ dlen = get_unaligned_be16(p+10);
debug("dlen = %d\n", dlen);
p += 12 + dlen;
} else if (type == DNS_A_RECORD) {
@@ -181,8 +178,7 @@ DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
if (found && &p[12] < e) {
- tmp = p[10] | (p[11] << 8);
- dlen = ntohs(tmp);
+ dlen = get_unaligned_be16(p+10);
p += 12;
memcpy(&IPAddress, p, 4);
@@ -195,7 +191,7 @@ DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
puts("server responded with invalid IP number\n");
}
- NetState = NETLOOP_SUCCESS;
+ net_set_state(NETLOOP_SUCCESS);
}
void
@@ -204,7 +200,7 @@ DnsStart(void)
debug("%s\n", __func__);
NetSetTimeout(DNS_TIMEOUT, DnsTimeout);
- NetSetHandler(DnsHandler);
+ net_set_udp_handler(DnsHandler);
DnsSend();
}
diff --git a/net/dns.h b/net/dns.h
index 277c093ed3..dbc3890df9 100644
--- a/net/dns.h
+++ b/net/dns.h
@@ -2,10 +2,7 @@
* (C) Masami Komiya <mkomiya@sonare.it> 2005
* Copyright 2009, Robin Getz <rgetz@blackfin.uclinux.org>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __DNS_H__
diff --git a/net/eth.c b/net/eth.c
index fe64867a8c..c96e767e8e 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -2,33 +2,14 @@
* (C) Copyright 2001-2010
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <net.h>
#include <miiphy.h>
-
-#if defined(CONFIG_S5P6450)
-DECLARE_GLOBAL_DATA_PTR;
-#endif
+#include <phy.h>
void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
{
@@ -57,14 +38,22 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
return setenv(name, buf);
}
-int eth_getenv_enetaddr_by_index(int index, uchar *enetaddr)
+int eth_getenv_enetaddr_by_index(const char *base_name, int index,
+ uchar *enetaddr)
{
char enetvar[32];
- sprintf(enetvar, index ? "eth%daddr" : "ethaddr", index);
+ sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
return eth_getenv_enetaddr(enetvar, enetaddr);
}
-#ifdef CONFIG_NET_MULTI
+static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
+ uchar *enetaddr)
+{
+ char enetvar[32];
+ sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
+ return eth_setenv_enetaddr(enetvar, enetaddr);
+}
+
static int eth_mac_skip(int index)
{
@@ -74,6 +63,28 @@ static int eth_mac_skip(int index)
return ((skip_state = getenv(enetvar)) != NULL);
}
+#ifdef CONFIG_RANDOM_MACADDR
+void eth_random_enetaddr(uchar *enetaddr)
+{
+ uint32_t rval;
+
+ srand(get_timer(0));
+
+ rval = rand();
+ enetaddr[0] = rval & 0xff;
+ enetaddr[1] = (rval >> 8) & 0xff;
+ enetaddr[2] = (rval >> 16) & 0xff;
+
+ rval = rand();
+ enetaddr[3] = rval & 0xff;
+ enetaddr[4] = (rval >> 8) & 0xff;
+ enetaddr[5] = (rval >> 16) & 0xff;
+
+ /* make sure it's local and unicast */
+ enetaddr[0] = (enetaddr[0] | 0x02) & ~0x01;
+}
+#endif
+
/*
* CPU and board-specific Ethernet initializations. Aliased function
* signals caller to move on
@@ -85,31 +96,24 @@ static int __def_eth_init(bd_t *bis)
int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
-extern int mv6436x_eth_initialize(bd_t *);
-extern int mv6446x_eth_initialize(bd_t *);
-
#ifdef CONFIG_API
-extern void (*push_packet)(volatile void *, int);
-
static struct {
uchar data[PKTSIZE];
int length;
} eth_rcv_bufs[PKTBUFSRX];
-static unsigned int eth_rcv_current = 0, eth_rcv_last = 0;
+static unsigned int eth_rcv_current, eth_rcv_last;
#endif
-static struct eth_device *eth_devices, *eth_current;
-
-struct eth_device *eth_get_dev(void)
-{
- return eth_current;
-}
+static struct eth_device *eth_devices;
+struct eth_device *eth_current;
struct eth_device *eth_get_dev_by_name(const char *devname)
{
struct eth_device *dev, *target_dev;
+ BUG_ON(devname == NULL);
+
if (!eth_devices)
return NULL;
@@ -129,7 +133,6 @@ struct eth_device *eth_get_dev_by_name(const char *devname)
struct eth_device *eth_get_dev_by_index(int index)
{
struct eth_device *dev, *target_dev;
- int idx = 0;
if (!eth_devices)
return NULL;
@@ -137,77 +140,155 @@ struct eth_device *eth_get_dev_by_index(int index)
dev = eth_devices;
target_dev = NULL;
do {
- if (idx == index) {
+ if (dev->index == index) {
target_dev = dev;
break;
}
dev = dev->next;
- idx++;
} while (dev != eth_devices);
return target_dev;
}
-int eth_get_dev_index (void)
+int eth_get_dev_index(void)
{
- struct eth_device *dev;
- int num = 0;
+ if (!eth_current)
+ return -1;
- if (!eth_devices) {
- return (-1);
+ return eth_current->index;
+}
+
+static void eth_current_changed(void)
+{
+ char *act = getenv("ethact");
+ /* update current ethernet name */
+ if (eth_current) {
+ if (act == NULL || strcmp(act, eth_current->name) != 0)
+ setenv("ethact", eth_current->name);
}
+ /*
+ * remove the variable completely if there is no active
+ * interface
+ */
+ else if (act != NULL)
+ setenv("ethact", NULL);
+}
- for (dev = eth_devices; dev; dev = dev->next) {
- if (dev == eth_current)
- break;
- ++num;
+int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
+ int eth_number)
+{
+ unsigned char env_enetaddr[6];
+ int ret = 0;
+
+ eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
+
+ if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
+ if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
+ memcmp(dev->enetaddr, env_enetaddr, 6)) {
+ printf("\nWarning: %s MAC addresses don't match:\n",
+ dev->name);
+ printf("Address in SROM is %pM\n",
+ dev->enetaddr);
+ printf("Address in environment is %pM\n",
+ env_enetaddr);
+ }
+
+ memcpy(dev->enetaddr, env_enetaddr, 6);
+ } else if (is_valid_ether_addr(dev->enetaddr)) {
+ eth_setenv_enetaddr_by_index(base_name, eth_number,
+ dev->enetaddr);
+ printf("\nWarning: %s using MAC address from net device\n",
+ dev->name);
}
- if (dev) {
- return (num);
+ if (dev->write_hwaddr &&
+ !eth_mac_skip(eth_number)) {
+ if (!is_valid_ether_addr(dev->enetaddr))
+ return -1;
+
+ ret = dev->write_hwaddr(dev);
}
- return (0);
+ return ret;
}
-int eth_register(struct eth_device* dev)
+int eth_register(struct eth_device *dev)
{
struct eth_device *d;
+ static int index;
+
+ assert(strlen(dev->name) < sizeof(dev->name));
if (!eth_devices) {
eth_current = eth_devices = dev;
-#ifdef CONFIG_NET_MULTI
- /* update current ethernet name */
- {
- char *act = getenv("ethact");
- if (act == NULL || strcmp(act, eth_current->name) != 0)
- setenv("ethact", eth_current->name);
- }
-#endif
+ eth_current_changed();
} else {
- for (d=eth_devices; d->next!=eth_devices; d=d->next)
+ for (d = eth_devices; d->next != eth_devices; d = d->next)
;
d->next = dev;
}
dev->state = ETH_STATE_INIT;
dev->next = eth_devices;
+ dev->index = index++;
return 0;
}
-int eth_initialize(bd_t *bis)
+int eth_unregister(struct eth_device *dev)
{
- unsigned char env_enetaddr[6];
- int eth_number = 0;
+ struct eth_device *cur;
+
+ /* No device */
+ if (!eth_devices)
+ return -1;
+ for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
+ cur = cur->next)
+ ;
+
+ /* Device not found */
+ if (cur->next != dev)
+ return -1;
+
+ cur->next = dev->next;
+
+ if (eth_devices == dev)
+ eth_devices = dev->next == eth_devices ? NULL : dev->next;
+
+ if (eth_current == dev) {
+ eth_current = eth_devices;
+ eth_current_changed();
+ }
+
+ return 0;
+}
+
+static void eth_env_init(bd_t *bis)
+{
+ const char *s;
+
+ if ((s = getenv("bootfile")) != NULL)
+ copy_filename(BootFile, s, sizeof(BootFile));
+}
+
+int eth_initialize(bd_t *bis)
+{
+ int num_devices = 0;
eth_devices = NULL;
eth_current = NULL;
- show_boot_progress (64);
+ bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
miiphy_init();
#endif
+
+#ifdef CONFIG_PHYLIB
+ phy_init();
+#endif
+
+ eth_env_init(bis);
+
/*
* If board-specific initialization exists, call it.
* If not, call a CPU-specific one
@@ -221,72 +302,41 @@ int eth_initialize(bd_t *bis)
} else
printf("Net Initialization Skipped\n");
-#if defined(CONFIG_DB64360) || defined(CONFIG_CPCI750)
- mv6436x_eth_initialize(bis);
-#endif
-#if defined(CONFIG_DB64460) || defined(CONFIG_P3Mx)
- mv6446x_eth_initialize(bis);
-#endif
if (!eth_devices) {
- puts ("No ethernet found.\n");
- show_boot_progress (-64);
+ puts("No ethernet found.\n");
+ bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
} else {
struct eth_device *dev = eth_devices;
- char *ethprime = getenv ("ethprime");
+ char *ethprime = getenv("ethprime");
- show_boot_progress (65);
+ bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
do {
- if (eth_number)
- puts (", ");
+ if (dev->index)
+ puts(", ");
printf("%s", dev->name);
- if (ethprime && strcmp (dev->name, ethprime) == 0) {
+ if (ethprime && strcmp(dev->name, ethprime) == 0) {
eth_current = dev;
- puts (" [PRIME]");
+ puts(" [PRIME]");
}
if (strchr(dev->name, ' '))
- puts("\nWarning: eth device name has a space!\n");
-
- eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);
-
- if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
- if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
- memcmp(dev->enetaddr, env_enetaddr, 6))
- {
- printf ("\nWarning: %s MAC addresses don't match:\n",
- dev->name);
- printf ("Address in SROM is %pM\n",
- dev->enetaddr);
- printf ("Address in environment is %pM\n",
- env_enetaddr);
- }
-
- memcpy(dev->enetaddr, env_enetaddr, 6);
- }
- if (dev->write_hwaddr &&
- !eth_mac_skip(eth_number) &&
- is_valid_ether_addr(dev->enetaddr)) {
- dev->write_hwaddr(dev);
- }
+ puts("\nWarning: eth device name has a space!"
+ "\n");
- eth_number++;
- dev = dev->next;
- } while(dev != eth_devices);
+ if (eth_write_hwaddr(dev, "eth", dev->index))
+ puts("\nWarning: failed to set MAC address\n");
- /* update current ethernet name */
- if (eth_current) {
- char *act = getenv("ethact");
- if (act == NULL || strcmp(act, eth_current->name) != 0)
- setenv("ethact", eth_current->name);
- } else
- setenv("ethact", NULL);
+ dev = dev->next;
+ num_devices++;
+ } while (dev != eth_devices);
- putc ('\n');
+ eth_current_changed();
+ putc('\n');
}
- return eth_number;
+ return num_devices;
}
#ifdef CONFIG_MCAST_TFTP
@@ -294,9 +344,9 @@ int eth_initialize(bd_t *bis)
* mcast_addr: multicast ipaddr from which multicast Mac is made
* join: 1=join, 0=leave.
*/
-int eth_mcast_join( IPaddr_t mcast_ip, u8 join)
+int eth_mcast_join(IPaddr_t mcast_ip, u8 join)
{
- u8 mcast_mac[6];
+ u8 mcast_mac[6];
if (!eth_current || !eth_current->mcast)
return -1;
mcast_mac[5] = htonl(mcast_ip) & 0xff;
@@ -313,7 +363,7 @@ int eth_mcast_join( IPaddr_t mcast_ip, u8 join)
* some other adapter -- hash tables
*/
#define CRCPOLY_LE 0xedb88320
-u32 ether_crc (size_t len, unsigned char const *p)
+u32 ether_crc(size_t len, unsigned char const *p)
{
int i;
u32 crc;
@@ -337,24 +387,22 @@ u32 ether_crc (size_t len, unsigned char const *p)
int eth_init(bd_t *bis)
{
- int eth_number;
struct eth_device *old_current, *dev;
if (!eth_current) {
- puts ("No ethernet found.\n");
+ puts("No ethernet found.\n");
return -1;
}
/* Sync environment with network devices */
- eth_number = 0;
dev = eth_devices;
do {
uchar env_enetaddr[6];
- if (eth_getenv_enetaddr_by_index(eth_number, env_enetaddr))
+ if (eth_getenv_enetaddr_by_index("eth", dev->index,
+ env_enetaddr))
memcpy(dev->enetaddr, env_enetaddr, 6);
- ++eth_number;
dev = dev->next;
} while (dev != eth_devices);
@@ -362,7 +410,7 @@ int eth_init(bd_t *bis)
do {
debug("Trying %s\n", eth_current->name);
- if (eth_current->init(eth_current,bis) >= 0) {
+ if (eth_current->init(eth_current, bis) >= 0) {
eth_current->state = ETH_STATE_ACTIVE;
return 0;
@@ -385,7 +433,7 @@ void eth_halt(void)
eth_current->state = ETH_STATE_PASSIVE;
}
-int eth_send(volatile void *packet, int length)
+int eth_send(void *packet, int length)
{
if (!eth_current)
return -1;
@@ -402,9 +450,9 @@ int eth_rx(void)
}
#ifdef CONFIG_API
-static void eth_save_packet(volatile void *packet, int length)
+static void eth_save_packet(void *packet, int length)
{
- volatile char *p = packet;
+ char *p = packet;
int i;
if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
@@ -420,9 +468,9 @@ static void eth_save_packet(volatile void *packet, int length)
eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
}
-int eth_receive(volatile void *packet, int length)
+int eth_receive(void *packet, int length)
{
- volatile char *p = packet;
+ char *p = packet;
void *pp = push_packet;
int i;
@@ -435,10 +483,7 @@ int eth_receive(volatile void *packet, int length)
return -1;
}
- if (length < eth_rcv_bufs[eth_rcv_current].length)
- return -1;
-
- length = eth_rcv_bufs[eth_rcv_current].length;
+ length = min(eth_rcv_bufs[eth_rcv_current].length, length);
for (i = 0; i < length; i++)
p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
@@ -450,41 +495,36 @@ int eth_receive(volatile void *packet, int length)
void eth_try_another(int first_restart)
{
- static struct eth_device *first_failed = NULL;
- char *ethrotate, *act;
+ static struct eth_device *first_failed;
+ char *ethrotate;
/*
* Do not rotate between network interfaces when
* 'ethrotate' variable is set to 'no'.
*/
- if (((ethrotate = getenv ("ethrotate")) != NULL) &&
- (strcmp(ethrotate, "no") == 0))
+ ethrotate = getenv("ethrotate");
+ if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
return;
if (!eth_current)
return;
- if (first_restart) {
+ if (first_restart)
first_failed = eth_current;
- }
eth_current = eth_current->next;
- /* update current ethernet name */
- act = getenv("ethact");
- if (act == NULL || strcmp(act, eth_current->name) != 0)
- setenv("ethact", eth_current->name);
+ eth_current_changed();
- if (first_failed == eth_current) {
+ if (first_failed == eth_current)
NetRestartWrap = 1;
- }
}
void eth_set_current(void)
{
- static char *act = NULL;
- static int env_changed_id = 0;
- struct eth_device* old_current;
+ static char *act;
+ static int env_changed_id;
+ struct eth_device *old_current;
int env_id;
if (!eth_current) /* XXX no current */
@@ -504,38 +544,10 @@ void eth_set_current(void)
} while (old_current != eth_current);
}
- setenv("ethact", eth_current->name);
-}
-
-char *eth_get_name (void)
-{
- return (eth_current ? eth_current->name : "unknown");
+ eth_current_changed();
}
-#else /* !CONFIG_NET_MULTI */
-
-#warning Ethernet driver is deprecated. Please update to use CONFIG_NET_MULTI
-
-extern int at91rm9200_miiphy_initialize(bd_t *bis);
-extern int mcf52x2_miiphy_initialize(bd_t *bis);
-extern int ns7520_miiphy_initialize(bd_t *bis);
-
-
-int eth_initialize(bd_t *bis)
+char *eth_get_name(void)
{
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- miiphy_init();
-#endif
-
-#if defined(CONFIG_AT91RM9200)
- at91rm9200_miiphy_initialize(bis);
-#endif
-#if defined(CONFIG_MCF52x2)
- mcf52x2_miiphy_initialize(bis);
-#endif
-#if defined(CONFIG_DRIVER_NS7520_ETHERNET)
- ns7520_miiphy_initialize(bis);
-#endif
- return 0;
+ return eth_current ? eth_current->name : "unknown";
}
-#endif
diff --git a/net/link_local.c b/net/link_local.c
new file mode 100644
index 0000000000..4152fae5ba
--- /dev/null
+++ b/net/link_local.c
@@ -0,0 +1,345 @@
+/*
+ * RFC3927 ZeroConf IPv4 Link-Local addressing
+ * (see <http://www.zeroconf.org/>)
+ *
+ * Copied from BusyBox - networking/zcip.c
+ *
+ * Copyright (C) 2003 by Arthur van Hoff (avh@strangeberry.com)
+ * Copyright (C) 2004 by David Brownell
+ * Copyright (C) 2010 by Joe Hershberger
+ *
+ * Licensed under the GPL v2 or later
+ */
+
+#include <common.h>
+#include <net.h>
+#include "arp.h"
+#include "net_rand.h"
+
+/* We don't need more than 32 bits of the counter */
+#define MONOTONIC_MS() ((unsigned)get_timer(0) * (1000 / CONFIG_SYS_HZ))
+
+enum {
+/* 169.254.0.0 */
+ LINKLOCAL_ADDR = 0xa9fe0000,
+
+ IN_CLASSB_NET = 0xffff0000,
+ IN_CLASSB_HOST = 0x0000ffff,
+
+/* protocol timeout parameters, specified in seconds */
+ PROBE_WAIT = 1,
+ PROBE_MIN = 1,
+ PROBE_MAX = 2,
+ PROBE_NUM = 3,
+ MAX_CONFLICTS = 10,
+ RATE_LIMIT_INTERVAL = 60,
+ ANNOUNCE_WAIT = 2,
+ ANNOUNCE_NUM = 2,
+ ANNOUNCE_INTERVAL = 2,
+ DEFEND_INTERVAL = 10
+};
+
+/* States during the configuration process. */
+static enum ll_state_t {
+ PROBE = 0,
+ RATE_LIMIT_PROBE,
+ ANNOUNCE,
+ MONITOR,
+ DEFEND,
+ DISABLED
+} state = DISABLED;
+
+static IPaddr_t ip;
+static int timeout_ms = -1;
+static unsigned deadline_ms;
+static unsigned conflicts;
+static unsigned nprobes;
+static unsigned nclaims;
+static int ready;
+static unsigned int seed;
+
+static void link_local_timeout(void);
+
+/**
+ * Pick a random link local IP address on 169.254/16, except that
+ * the first and last 256 addresses are reserved.
+ */
+static IPaddr_t pick(void)
+{
+ unsigned tmp;
+
+ do {
+ tmp = rand_r(&seed) & IN_CLASSB_HOST;
+ } while (tmp > (IN_CLASSB_HOST - 0x0200));
+ return (IPaddr_t) htonl((LINKLOCAL_ADDR + 0x0100) + tmp);
+}
+
+/**
+ * Return milliseconds of random delay, up to "secs" seconds.
+ */
+static inline unsigned random_delay_ms(unsigned secs)
+{
+ return rand_r(&seed) % (secs * 1000);
+}
+
+static void configure_wait(void)
+{
+ if (timeout_ms == -1)
+ return;
+
+ /* poll, being ready to adjust current timeout */
+ if (!timeout_ms)
+ timeout_ms = random_delay_ms(PROBE_WAIT);
+
+ /* set deadline_ms to the point in time when we timeout */
+ deadline_ms = MONOTONIC_MS() + timeout_ms;
+
+ debug_cond(DEBUG_DEV_PKT, "...wait %d %s nprobes=%u, nclaims=%u\n",
+ timeout_ms, eth_get_name(), nprobes, nclaims);
+
+ NetSetTimeout(timeout_ms, link_local_timeout);
+}
+
+void link_local_start(void)
+{
+ ip = getenv_IPaddr("llipaddr");
+ if (ip != 0 && (ntohl(ip) & IN_CLASSB_NET) != LINKLOCAL_ADDR) {
+ puts("invalid link address");
+ net_set_state(NETLOOP_FAIL);
+ return;
+ }
+ NetOurSubnetMask = IN_CLASSB_NET;
+
+ seed = seed_mac();
+ if (ip == 0)
+ ip = pick();
+
+ state = PROBE;
+ timeout_ms = 0;
+ conflicts = 0;
+ nprobes = 0;
+ nclaims = 0;
+ ready = 0;
+
+ configure_wait();
+}
+
+static void link_local_timeout(void)
+{
+ switch (state) {
+ case PROBE:
+ /* timeouts in the PROBE state mean no conflicting ARP packets
+ have been received, so we can progress through the states */
+ if (nprobes < PROBE_NUM) {
+ nprobes++;
+ debug_cond(DEBUG_LL_STATE, "probe/%u %s@%pI4\n",
+ nprobes, eth_get_name(), &ip);
+ arp_raw_request(0, NetEtherNullAddr, ip);
+ timeout_ms = PROBE_MIN * 1000;
+ timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
+ } else {
+ /* Switch to announce state */
+ state = ANNOUNCE;
+ nclaims = 0;
+ debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n",
+ nclaims, eth_get_name(), &ip);
+ arp_raw_request(ip, NetOurEther, ip);
+ timeout_ms = ANNOUNCE_INTERVAL * 1000;
+ }
+ break;
+ case RATE_LIMIT_PROBE:
+ /* timeouts in the RATE_LIMIT_PROBE state mean no conflicting
+ ARP packets have been received, so we can move immediately
+ to the announce state */
+ state = ANNOUNCE;
+ nclaims = 0;
+ debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n",
+ nclaims, eth_get_name(), &ip);
+ arp_raw_request(ip, NetOurEther, ip);
+ timeout_ms = ANNOUNCE_INTERVAL * 1000;
+ break;
+ case ANNOUNCE:
+ /* timeouts in the ANNOUNCE state mean no conflicting ARP
+ packets have been received, so we can progress through
+ the states */
+ if (nclaims < ANNOUNCE_NUM) {
+ nclaims++;
+ debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n",
+ nclaims, eth_get_name(), &ip);
+ arp_raw_request(ip, NetOurEther, ip);
+ timeout_ms = ANNOUNCE_INTERVAL * 1000;
+ } else {
+ /* Switch to monitor state */
+ state = MONITOR;
+ printf("Successfully assigned %pI4\n", &ip);
+ NetCopyIP(&NetOurIP, &ip);
+ ready = 1;
+ conflicts = 0;
+ timeout_ms = -1;
+ /* Never timeout in the monitor state */
+ NetSetTimeout(0, NULL);
+
+ /* NOTE: all other exit paths should deconfig ... */
+ net_set_state(NETLOOP_SUCCESS);
+ return;
+ }
+ break;
+ case DEFEND:
+ /* We won! No ARP replies, so just go back to monitor */
+ state = MONITOR;
+ timeout_ms = -1;
+ conflicts = 0;
+ break;
+ default:
+ /* Invalid, should never happen. Restart the whole protocol */
+ state = PROBE;
+ ip = pick();
+ timeout_ms = 0;
+ nprobes = 0;
+ nclaims = 0;
+ break;
+ }
+ configure_wait();
+}
+
+void link_local_receive_arp(struct arp_hdr *arp, int len)
+{
+ int source_ip_conflict;
+ int target_ip_conflict;
+ IPaddr_t null_ip = 0;
+
+ if (state == DISABLED)
+ return;
+
+ /* We need to adjust the timeout in case we didn't receive a
+ conflicting packet. */
+ if (timeout_ms > 0) {
+ unsigned diff = deadline_ms - MONOTONIC_MS();
+ if ((int)(diff) < 0) {
+ /* Current time is greater than the expected timeout
+ time. This should never happen */
+ debug_cond(DEBUG_LL_STATE,
+ "missed an expected timeout\n");
+ timeout_ms = 0;
+ } else {
+ debug_cond(DEBUG_INT_STATE, "adjusting timeout\n");
+ timeout_ms = diff | 1; /* never 0 */
+ }
+ }
+#if 0
+ /* XXX Don't bother with ethernet link just yet */
+ if ((fds[0].revents & POLLIN) == 0) {
+ if (fds[0].revents & POLLERR) {
+ /*
+ * FIXME: links routinely go down;
+ */
+ bb_error_msg("iface %s is down", eth_get_name());
+ if (ready) {
+ run(argv, "deconfig", &ip);
+ }
+ return EXIT_FAILURE;
+ }
+ continue;
+ }
+#endif
+
+ debug_cond(DEBUG_INT_STATE, "%s recv arp type=%d, op=%d,\n",
+ eth_get_name(), ntohs(arp->ar_pro),
+ ntohs(arp->ar_op));
+ debug_cond(DEBUG_INT_STATE, "\tsource=%pM %pI4\n",
+ &arp->ar_sha,
+ &arp->ar_spa);
+ debug_cond(DEBUG_INT_STATE, "\ttarget=%pM %pI4\n",
+ &arp->ar_tha,
+ &arp->ar_tpa);
+
+ if (arp->ar_op != htons(ARPOP_REQUEST)
+ && arp->ar_op != htons(ARPOP_REPLY)
+ ) {
+ configure_wait();
+ return;
+ }
+
+ source_ip_conflict = 0;
+ target_ip_conflict = 0;
+
+ if (memcmp(&arp->ar_spa, &ip, ARP_PLEN) == 0
+ && memcmp(&arp->ar_sha, NetOurEther, ARP_HLEN) != 0
+ ) {
+ source_ip_conflict = 1;
+ }
+
+ /*
+ * According to RFC 3927, section 2.2.1:
+ * Check if packet is an ARP probe by checking for a null source IP
+ * then check that target IP is equal to ours and source hw addr
+ * is not equal to ours. This condition should cause a conflict only
+ * during probe.
+ */
+ if (arp->ar_op == htons(ARPOP_REQUEST) &&
+ memcmp(&arp->ar_spa, &null_ip, ARP_PLEN) == 0 &&
+ memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 &&
+ memcmp(&arp->ar_sha, NetOurEther, ARP_HLEN) != 0) {
+ target_ip_conflict = 1;
+ }
+
+ debug_cond(DEBUG_NET_PKT,
+ "state = %d, source ip conflict = %d, target ip conflict = "
+ "%d\n", state, source_ip_conflict, target_ip_conflict);
+ switch (state) {
+ case PROBE:
+ case ANNOUNCE:
+ /* When probing or announcing, check for source IP conflicts
+ and other hosts doing ARP probes (target IP conflicts). */
+ if (source_ip_conflict || target_ip_conflict) {
+ conflicts++;
+ state = PROBE;
+ if (conflicts >= MAX_CONFLICTS) {
+ debug("%s ratelimit\n", eth_get_name());
+ timeout_ms = RATE_LIMIT_INTERVAL * 1000;
+ state = RATE_LIMIT_PROBE;
+ }
+
+ /* restart the whole protocol */
+ ip = pick();
+ timeout_ms = 0;
+ nprobes = 0;
+ nclaims = 0;
+ }
+ break;
+ case MONITOR:
+ /* If a conflict, we try to defend with a single ARP probe */
+ if (source_ip_conflict) {
+ debug("monitor conflict -- defending\n");
+ state = DEFEND;
+ timeout_ms = DEFEND_INTERVAL * 1000;
+ arp_raw_request(ip, NetOurEther, ip);
+ }
+ break;
+ case DEFEND:
+ /* Well, we tried. Start over (on conflict) */
+ if (source_ip_conflict) {
+ state = PROBE;
+ debug("defend conflict -- starting over\n");
+ ready = 0;
+ NetOurIP = 0;
+
+ /* restart the whole protocol */
+ ip = pick();
+ timeout_ms = 0;
+ nprobes = 0;
+ nclaims = 0;
+ }
+ break;
+ default:
+ /* Invalid, should never happen. Restart the whole protocol */
+ debug("invalid state -- starting over\n");
+ state = PROBE;
+ ip = pick();
+ timeout_ms = 0;
+ nprobes = 0;
+ nclaims = 0;
+ break;
+ }
+ configure_wait();
+}
diff --git a/net/link_local.h b/net/link_local.h
new file mode 100644
index 0000000000..bb998164df
--- /dev/null
+++ b/net/link_local.h
@@ -0,0 +1,24 @@
+/*
+ * RFC3927 ZeroConf IPv4 Link-Local addressing
+ * (see <http://www.zeroconf.org/>)
+ *
+ * Copied from BusyBox - networking/zcip.c
+ *
+ * Copyright (C) 2003 by Arthur van Hoff (avh@strangeberry.com)
+ * Copyright (C) 2004 by David Brownell
+ *
+ * Licensed under the GPL v2 or later
+ */
+
+#if defined(CONFIG_CMD_LINK_LOCAL)
+
+#ifndef __LINK_LOCAL_H__
+#define __LINK_LOCAL_H__
+
+#include <common.h>
+
+void link_local_receive_arp(struct arp_hdr *arp, int len);
+void link_local_start(void);
+
+#endif /* __LINK_LOCAL_H__ */
+#endif
diff --git a/net/net.c b/net/net.c
index d5a5429d1c..1a524fc95f 100644
--- a/net/net.c
+++ b/net/net.c
@@ -23,6 +23,12 @@
* - name of bootfile
* Next step: ARP
*
+ * LINK_LOCAL:
+ *
+ * Prerequisites: - own ethernet address
+ * We want: - own IP address
+ * Next step: ARP
+ *
* RARP:
*
* Prerequisites: - own ethernet address
@@ -75,56 +81,52 @@
#include <common.h>
-#include <watchdog.h>
#include <command.h>
+#include <environment.h>
#include <net.h>
+#if defined(CONFIG_STATUS_LED)
+#include <miiphy.h>
+#include <status_led.h>
+#endif
+#include <watchdog.h>
+#include <linux/compiler.h>
+#include "arp.h"
#include "bootp.h"
-#include "tftp.h"
-#ifdef CONFIG_CMD_RARP
-#include "rarp.h"
+#include "cdp.h"
+#if defined(CONFIG_CMD_DNS)
+#include "dns.h"
#endif
+#include "link_local.h"
#include "nfs.h"
-#ifdef CONFIG_STATUS_LED
-#include <status_led.h>
-#include <miiphy.h>
-#endif
+#include "ping.h"
+#include "rarp.h"
#if defined(CONFIG_CMD_SNTP)
#include "sntp.h"
#endif
-#if defined(CONFIG_CDP_VERSION)
-#include <timestamp.h>
-#endif
-#if defined(CONFIG_CMD_DNS)
-#include "dns.h"
-#endif
+#include "tftp.h"
DECLARE_GLOBAL_DATA_PTR;
-#ifndef CONFIG_ARP_TIMEOUT
-# define ARP_TIMEOUT 5000UL /* Milliseconds before trying ARP again */
-#else
-# define ARP_TIMEOUT CONFIG_ARP_TIMEOUT
-#endif
-
-
-#ifndef CONFIG_NET_RETRY_COUNT
-# define ARP_TIMEOUT_COUNT 5 /* # of timeouts before giving up */
-#else
-# define ARP_TIMEOUT_COUNT CONFIG_NET_RETRY_COUNT
-#endif
-
/** BOOTP EXTENTIONS **/
-IPaddr_t NetOurSubnetMask=0; /* Our subnet mask (0=unknown) */
-IPaddr_t NetOurGatewayIP=0; /* Our gateways IP address */
-IPaddr_t NetOurDNSIP=0; /* Our DNS IP address */
+/* Our subnet mask (0=unknown) */
+IPaddr_t NetOurSubnetMask;
+/* Our gateways IP address */
+IPaddr_t NetOurGatewayIP;
+/* Our DNS IP address */
+IPaddr_t NetOurDNSIP;
#if defined(CONFIG_BOOTP_DNS2)
-IPaddr_t NetOurDNS2IP=0; /* Our 2nd DNS IP address */
-#endif
-char NetOurNISDomain[32]={0,}; /* Our NIS domain */
-char NetOurHostName[32]={0,}; /* Our hostname */
-char NetOurRootPath[64]={0,}; /* Our bootpath */
-ushort NetBootFileSize=0; /* Our bootfile size in blocks */
+/* Our 2nd DNS IP address */
+IPaddr_t NetOurDNS2IP;
+#endif
+/* Our NIS domain */
+char NetOurNISDomain[32] = {0,};
+/* Our hostname */
+char NetOurHostName[32] = {0,};
+/* Our bootpath */
+char NetOurRootPath[64] = {0,};
+/* Our bootfile size in blocks */
+ushort NetBootFileSize;
#ifdef CONFIG_MCAST_TFTP /* Multicast TFTP */
IPaddr_t Mcast_addr;
@@ -132,163 +134,144 @@ IPaddr_t Mcast_addr;
/** END OF BOOTP EXTENTIONS **/
-ulong NetBootFileXferSize; /* The actual transferred size of the bootfile (in bytes) */
-uchar NetOurEther[6]; /* Our ethernet address */
-uchar NetServerEther[6] = /* Boot server enet address */
- { 0, 0, 0, 0, 0, 0 };
-IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
-IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */
-volatile uchar *NetRxPacket; /* Current receive packet */
-int NetRxPacketLen; /* Current rx packet length */
-unsigned NetIPID; /* IP packet ID */
-uchar NetBcastAddr[6] = /* Ethernet bcast address */
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-uchar NetEtherNullAddr[6] =
- { 0, 0, 0, 0, 0, 0 };
+/* The actual transferred size of the bootfile (in bytes) */
+ulong NetBootFileXferSize;
+/* Our ethernet address */
+uchar NetOurEther[6];
+/* Boot server enet address */
+uchar NetServerEther[6];
+/* Our IP addr (0 = unknown) */
+IPaddr_t NetOurIP;
+/* Server IP addr (0 = unknown) */
+IPaddr_t NetServerIP;
+/* Current receive packet */
+uchar *NetRxPacket;
+/* Current rx packet length */
+int NetRxPacketLen;
+/* IP packet ID */
+unsigned NetIPID;
+/* Ethernet bcast address */
+uchar NetBcastAddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+uchar NetEtherNullAddr[6];
#ifdef CONFIG_API
-void (*push_packet)(volatile void *, int len) = 0;
-#endif
-#if defined(CONFIG_CMD_CDP)
-uchar NetCDPAddr[6] = /* Ethernet bcast address */
- { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
-#endif
-int NetState; /* Network loop state */
-#ifdef CONFIG_NET_MULTI
-int NetRestartWrap = 0; /* Tried all network devices */
-static int NetRestarted = 0; /* Network loop restarted */
-static int NetDevExists = 0; /* At least one device configured */
+void (*push_packet)(void *, int len) = 0;
#endif
+/* Network loop state */
+enum net_loop_state net_state;
+/* Tried all network devices */
+int NetRestartWrap;
+/* Network loop restarted */
+static int NetRestarted;
+/* At least one device configured */
+static int NetDevExists;
/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
-ushort NetOurVLAN = 0xFFFF; /* default is without VLAN */
-ushort NetOurNativeVLAN = 0xFFFF; /* ditto */
-
-char BootFile[128]; /* Boot File name */
-
-#if defined(CONFIG_CMD_PING)
-IPaddr_t NetPingIP; /* the ip address to ping */
+/* default is without VLAN */
+ushort NetOurVLAN = 0xFFFF;
+/* ditto */
+ushort NetOurNativeVLAN = 0xFFFF;
-static void PingStart(void);
-#endif
-
-#if defined(CONFIG_CMD_CDP)
-static void CDPStart(void);
-#endif
+/* Boot File name */
+char BootFile[128];
#if defined(CONFIG_CMD_SNTP)
-IPaddr_t NetNtpServerIP; /* NTP server IP address */
-int NetTimeOffset=0; /* offset time from UTC */
-#endif
-
-#ifdef CONFIG_NETCONSOLE
-void NcStart(void);
-int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len);
+/* NTP server IP address */
+IPaddr_t NetNtpServerIP;
+/* offset time from UTC */
+int NetTimeOffset;
#endif
-volatile uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
+static uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
-volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */
+/* Receive packet */
+uchar *NetRxPackets[PKTBUFSRX];
-static rxhand_f *packetHandler; /* Current RX packet handler */
-static thand_f *timeHandler; /* Current timeout handler */
-static ulong timeStart; /* Time base value */
-static ulong timeDelta; /* Current timeout value */
-volatile uchar *NetTxPacket = 0; /* THE transmit packet */
+/* Current UDP RX packet handler */
+static rxhand_f *udp_packet_handler;
+/* Current ARP RX packet handler */
+static rxhand_f *arp_packet_handler;
+#ifdef CONFIG_CMD_TFTPPUT
+/* Current ICMP rx handler */
+static rxhand_icmp_f *packet_icmp_handler;
+#endif
+/* Current timeout handler */
+static thand_f *timeHandler;
+/* Time base value */
+static ulong timeStart;
+/* Current timeout value */
+static ulong timeDelta;
+/* THE transmit packet */
+uchar *NetTxPacket;
-static int net_check_prereq (proto_t protocol);
+static int net_check_prereq(enum proto_t protocol);
static int NetTryCount;
+int __maybe_unused net_busy_flag;
+
/**********************************************************************/
-IPaddr_t NetArpWaitPacketIP;
-IPaddr_t NetArpWaitReplyIP;
-uchar *NetArpWaitPacketMAC; /* MAC address of waiting packet's destination */
-uchar *NetArpWaitTxPacket; /* THE transmit packet */
-int NetArpWaitTxPacketSize;
-uchar NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
-ulong NetArpWaitTimerStart;
-int NetArpWaitTry;
+enum env_op {
+ env_op_create,
+ env_op_delete,
+ env_op_overwrite,
+};
-void ArpRequest (void)
+static int on_bootfile(const char *name, const char *value, enum env_op op,
+ int flags)
{
- int i;
- volatile uchar *pkt;
- ARP_t *arp;
-
- debug("ARP broadcast %d\n", NetArpWaitTry);
-
- pkt = NetTxPacket;
-
- pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);
-
- arp = (ARP_t *) pkt;
-
- arp->ar_hrd = htons (ARP_ETHER);
- arp->ar_pro = htons (PROT_IP);
- arp->ar_hln = 6;
- arp->ar_pln = 4;
- arp->ar_op = htons (ARPOP_REQUEST);
-
- memcpy (&arp->ar_data[0], NetOurEther, 6); /* source ET addr */
- NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP); /* source IP addr */
- for (i = 10; i < 16; ++i) {
- arp->ar_data[i] = 0; /* dest ET addr = 0 */
- }
-
- if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
- (NetOurIP & NetOurSubnetMask)) {
- if (NetOurGatewayIP == 0) {
- puts ("## Warning: gatewayip needed but not set\n");
- NetArpWaitReplyIP = NetArpWaitPacketIP;
- } else {
- NetArpWaitReplyIP = NetOurGatewayIP;
- }
- } else {
- NetArpWaitReplyIP = NetArpWaitPacketIP;
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+ copy_filename(BootFile, value, sizeof(BootFile));
+ break;
+ default:
+ break;
}
- NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP);
- (void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
+ return 0;
}
+U_BOOT_ENV_CALLBACK(bootfile, on_bootfile);
-void ArpTimeoutCheck(void)
+/*
+ * Check if autoload is enabled. If so, use either NFS or TFTP to download
+ * the boot file.
+ */
+void net_auto_load(void)
{
- ulong t;
+#if defined(CONFIG_CMD_NFS)
+ const char *s = getenv("autoload");
- if (!NetArpWaitPacketIP)
+ if (s != NULL && strcmp(s, "NFS") == 0) {
+ /*
+ * Use NFS to load the bootfile.
+ */
+ NfsStart();
+ return;
+ }
+#endif
+ if (getenv_yesno("autoload") == 0) {
+ /*
+ * Just use BOOTP/RARP to configure system;
+ * Do not use TFTP to load the bootfile.
+ */
+ net_set_state(NETLOOP_SUCCESS);
return;
-
- t = get_timer(0);
-
- /* check for arp timeout */
- if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT) {
- NetArpWaitTry++;
-
- if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
- puts ("\nARP Retry count exceeded; starting again\n");
- NetArpWaitTry = 0;
- NetStartAgain();
- } else {
- NetArpWaitTimerStart = t;
- ArpRequest();
- }
}
+ TftpStart(TFTPGET);
}
-static void
-NetInitLoop(proto_t protocol)
+static void NetInitLoop(void)
{
- static int env_changed_id = 0;
- bd_t *bd = gd->bd;
- int env_id = get_env_id ();
+ static int env_changed_id;
+ int env_id = get_env_id();
/* update only when the environment has changed */
if (env_changed_id != env_id) {
- NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
- NetOurGatewayIP = getenv_IPaddr ("gatewayip");
- NetOurSubnetMask= getenv_IPaddr ("netmask");
- NetServerIP = getenv_IPaddr ("serverip");
+ NetOurIP = getenv_IPaddr("ipaddr");
+ NetOurGatewayIP = getenv_IPaddr("gatewayip");
+ NetOurSubnetMask = getenv_IPaddr("netmask");
+ NetServerIP = getenv_IPaddr("serverip");
NetOurNativeVLAN = getenv_VLAN("nvlan");
NetOurVLAN = getenv_VLAN("vlan");
#if defined(CONFIG_CMD_DNS)
@@ -296,99 +279,116 @@ NetInitLoop(proto_t protocol)
#endif
env_changed_id = env_id;
}
+ if (eth_get_dev())
+ memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
return;
}
-/**********************************************************************/
-/*
- * Main network processing loop.
- */
-
-int
-NetLoop(proto_t protocol)
+static void net_clear_handlers(void)
{
- bd_t *bd = gd->bd;
+ net_set_udp_handler(NULL);
+ net_set_arp_handler(NULL);
+ NetSetTimeout(0, NULL);
+}
-#ifdef CONFIG_NET_MULTI
- NetRestarted = 0;
- NetDevExists = 0;
-#endif
+static void net_cleanup_loop(void)
+{
+ net_clear_handlers();
+}
- /* XXX problem with bss workaround */
- NetArpWaitPacketMAC = NULL;
- NetArpWaitTxPacket = NULL;
- NetArpWaitPacketIP = 0;
- NetArpWaitReplyIP = 0;
- NetArpWaitTxPacket = NULL;
- NetTxPacket = NULL;
- NetTryCount = 1;
+void net_init(void)
+{
+ static int first_call = 1;
- if (!NetTxPacket) {
- int i;
+ if (first_call) {
/*
* Setup packet buffers, aligned correctly.
*/
+ int i;
+
NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
- for (i = 0; i < PKTBUFSRX; i++) {
- NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
- }
- }
+ for (i = 0; i < PKTBUFSRX; i++)
+ NetRxPackets[i] = NetTxPacket + (i + 1) * PKTSIZE_ALIGN;
+
+ ArpInit();
+ net_clear_handlers();
- if (!NetArpWaitTxPacket) {
- NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
- NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
- NetArpWaitTxPacketSize = 0;
+ /* Only need to setup buffer pointers once. */
+ first_call = 0;
}
- eth_halt();
-#ifdef CONFIG_NET_MULTI
- eth_set_current();
-#endif
- if (eth_init(bd) < 0) {
+ NetInitLoop();
+}
+
+/**********************************************************************/
+/*
+ * Main network processing loop.
+ */
+
+int NetLoop(enum proto_t protocol)
+{
+ bd_t *bd = gd->bd;
+ int ret = -1;
+
+ NetRestarted = 0;
+ NetDevExists = 0;
+ NetTryCount = 1;
+ debug_cond(DEBUG_INT_STATE, "--- NetLoop Entry\n");
+
+ bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
+ net_init();
+ if (eth_is_on_demand_init() || protocol != NETCONS) {
eth_halt();
- return(-1);
- }
+ eth_set_current();
+ if (eth_init(bd) < 0) {
+ eth_halt();
+ return -1;
+ }
+ } else
+ eth_init_state_only(bd);
restart:
-#ifdef CONFIG_NET_MULTI
- memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
-#else
- eth_getenv_enetaddr("ethaddr", NetOurEther);
+#ifdef CONFIG_USB_KEYBOARD
+ net_busy_flag = 0;
#endif
-
- NetState = NETLOOP_CONTINUE;
+ net_set_state(NETLOOP_CONTINUE);
/*
* Start the ball rolling with the given start function. From
* here on, this code is a state machine driven by received
* packets and timer events.
*/
- NetInitLoop(protocol);
+ debug_cond(DEBUG_INT_STATE, "--- NetLoop Init\n");
+ NetInitLoop();
- switch (net_check_prereq (protocol)) {
+ switch (net_check_prereq(protocol)) {
case 1:
/* network not configured */
eth_halt();
- return (-1);
+ return -1;
-#ifdef CONFIG_NET_MULTI
case 2:
/* network device not configured */
break;
-#endif /* CONFIG_NET_MULTI */
case 0:
-#ifdef CONFIG_NET_MULTI
NetDevExists = 1;
-#endif
+ NetBootFileXferSize = 0;
switch (protocol) {
- case TFTP:
+ case TFTPGET:
+#ifdef CONFIG_CMD_TFTPPUT
+ case TFTPPUT:
+#endif
/* always use ARP to get server ethernet address */
- TftpStart();
+ TftpStart(protocol);
break;
-
+#ifdef CONFIG_CMD_TFTPSRV
+ case TFTPSRV:
+ TftpStartServer();
+ break;
+#endif
#if defined(CONFIG_CMD_DHCP)
case DHCP:
BootpTry = 0;
@@ -400,19 +400,19 @@ restart:
case BOOTP:
BootpTry = 0;
NetOurIP = 0;
- BootpRequest ();
+ BootpRequest();
break;
#if defined(CONFIG_CMD_RARP)
case RARP:
RarpTry = 0;
NetOurIP = 0;
- RarpRequest ();
+ RarpRequest();
break;
#endif
#if defined(CONFIG_CMD_PING)
case PING:
- PingStart();
+ ping_start();
break;
#endif
#if defined(CONFIG_CMD_NFS)
@@ -440,38 +440,43 @@ restart:
DnsStart();
break;
#endif
+#if defined(CONFIG_CMD_LINK_LOCAL)
+ case LINKLOCAL:
+ link_local_start();
+ break;
+#endif
default:
break;
}
- NetBootFileXferSize = 0;
break;
}
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
-#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
+#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
+ defined(CONFIG_STATUS_LED) && \
+ defined(STATUS_LED_RED)
/*
* Echo the inverted link state to the fault LED.
*/
- if(miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) {
- status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
- } else {
- status_led_set (STATUS_LED_RED, STATUS_LED_ON);
- }
+ if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR))
+ status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
+ else
+ status_led_set(STATUS_LED_RED, STATUS_LED_ON);
#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
#endif /* CONFIG_MII, ... */
+#ifdef CONFIG_USB_KEYBOARD
+ net_busy_flag = 1;
+#endif
/*
* Main packet reception loop. Loop receiving packets until
- * someone sets `NetState' to a state that terminates.
+ * someone sets `net_state' to a state that terminates.
*/
for (;;) {
WATCHDOG_RESET();
#ifdef CONFIG_SHOW_ACTIVITY
- {
- extern void show_activity(int arg);
- show_activity(1);
- }
+ show_activity(1);
#endif
/*
* Check the ethernet for a new packet. The ethernet
@@ -483,9 +488,19 @@ restart:
* Abort if ctrl-c was pressed.
*/
if (ctrlc()) {
+ /* cancel any ARP that may not have completed */
+ NetArpWaitPacketIP = 0;
+
+ net_cleanup_loop();
eth_halt();
- puts ("\nAbort\n");
- return (-1);
+ /* Invalidate the last protocol */
+ eth_set_last_protocol(BOOTP);
+
+ puts("\nAbort\n");
+ /* include a debug print as well incase the debug
+ messages are directed to stderr */
+ debug_cond(DEBUG_INT_STATE, "--- NetLoop Abort!\n");
+ goto done;
}
ArpTimeoutCheck();
@@ -498,52 +513,75 @@ restart:
thand_f *x;
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
-# if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
- defined(CONFIG_STATUS_LED) && \
- defined(STATUS_LED_RED)
+#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
+ defined(CONFIG_STATUS_LED) && \
+ defined(STATUS_LED_RED)
/*
* Echo the inverted link state to the fault LED.
*/
- if(miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) {
- status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
+ if (miiphy_link(eth_get_dev()->name,
+ CONFIG_SYS_FAULT_MII_ADDR)) {
+ status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
} else {
- status_led_set (STATUS_LED_RED, STATUS_LED_ON);
+ status_led_set(STATUS_LED_RED, STATUS_LED_ON);
}
-# endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
+#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
#endif /* CONFIG_MII, ... */
+ debug_cond(DEBUG_INT_STATE, "--- NetLoop timeout\n");
x = timeHandler;
timeHandler = (thand_f *)0;
(*x)();
}
- switch (NetState) {
+ switch (net_state) {
case NETLOOP_RESTART:
-#ifdef CONFIG_NET_MULTI
NetRestarted = 1;
-#endif
goto restart;
case NETLOOP_SUCCESS:
+ net_cleanup_loop();
if (NetBootFileXferSize > 0) {
- char buf[20];
printf("Bytes transferred = %ld (%lx hex)\n",
NetBootFileXferSize,
NetBootFileXferSize);
- sprintf(buf, "%lX", NetBootFileXferSize);
- setenv("filesize", buf);
-
- sprintf(buf, "%lX", (unsigned long)load_addr);
- setenv("fileaddr", buf);
+ setenv_hex("filesize", NetBootFileXferSize);
+ setenv_hex("fileaddr", load_addr);
}
- eth_halt();
- return NetBootFileXferSize;
+ if (protocol != NETCONS)
+ eth_halt();
+ else
+ eth_halt_state_only();
+
+ eth_set_last_protocol(protocol);
+
+ ret = NetBootFileXferSize;
+ debug_cond(DEBUG_INT_STATE, "--- NetLoop Success!\n");
+ goto done;
case NETLOOP_FAIL:
- return (-1);
+ net_cleanup_loop();
+ /* Invalidate the last protocol */
+ eth_set_last_protocol(BOOTP);
+ debug_cond(DEBUG_INT_STATE, "--- NetLoop Fail!\n");
+ goto done;
+
+ case NETLOOP_CONTINUE:
+ continue;
}
}
+
+done:
+#ifdef CONFIG_USB_KEYBOARD
+ net_busy_flag = 0;
+#endif
+#ifdef CONFIG_CMD_TFTPPUT
+ /* Clear out the handlers */
+ net_set_udp_handler(NULL);
+ net_set_icmp_handler(NULL);
+#endif
+ return ret;
}
/**********************************************************************/
@@ -551,16 +589,10 @@ restart:
static void
startAgainTimeout(void)
{
- NetState = NETLOOP_RESTART;
-}
-
-static void
-startAgainHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
-{
- /* Totally ignore the packet */
+ net_set_state(NETLOOP_RESTART);
}
-void NetStartAgain (void)
+void NetStartAgain(void)
{
char *nretry;
int retry_forever = 0;
@@ -581,33 +613,28 @@ void NetStartAgain (void)
if ((!retry_forever) && (NetTryCount >= retrycnt)) {
eth_halt();
- NetState = NETLOOP_FAIL;
+ net_set_state(NETLOOP_FAIL);
return;
}
NetTryCount++;
-#ifndef CONFIG_NET_MULTI
- NetSetTimeout (10000UL, startAgainTimeout);
- NetSetHandler (startAgainHandler);
-#else /* !CONFIG_NET_MULTI*/
- eth_halt ();
+ eth_halt();
#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
- eth_try_another (!NetRestarted);
+ eth_try_another(!NetRestarted);
#endif
- eth_init (gd->bd);
+ eth_init(gd->bd);
if (NetRestartWrap) {
NetRestartWrap = 0;
if (NetDevExists) {
- NetSetTimeout (10000UL, startAgainTimeout);
- NetSetHandler (startAgainHandler);
+ NetSetTimeout(10000UL, startAgainTimeout);
+ net_set_udp_handler(NULL);
} else {
- NetState = NETLOOP_FAIL;
+ net_set_state(NETLOOP_FAIL);
}
} else {
- NetState = NETLOOP_RESTART;
+ net_set_state(NETLOOP_RESTART);
}
-#endif /* CONFIG_NET_MULTI */
}
/**********************************************************************/
@@ -615,36 +642,74 @@ void NetStartAgain (void)
* Miscelaneous bits.
*/
-void
-NetSetHandler(rxhand_f * f)
+static void dummy_handler(uchar *pkt, unsigned dport,
+ IPaddr_t sip, unsigned sport,
+ unsigned len)
+{
+}
+
+rxhand_f *net_get_udp_handler(void)
+{
+ return udp_packet_handler;
+}
+
+void net_set_udp_handler(rxhand_f *f)
+{
+ debug_cond(DEBUG_INT_STATE, "--- NetLoop UDP handler set (%p)\n", f);
+ if (f == NULL)
+ udp_packet_handler = dummy_handler;
+ else
+ udp_packet_handler = f;
+}
+
+rxhand_f *net_get_arp_handler(void)
+{
+ return arp_packet_handler;
+}
+
+void net_set_arp_handler(rxhand_f *f)
{
- packetHandler = f;
+ debug_cond(DEBUG_INT_STATE, "--- NetLoop ARP handler set (%p)\n", f);
+ if (f == NULL)
+ arp_packet_handler = dummy_handler;
+ else
+ arp_packet_handler = f;
}
+#ifdef CONFIG_CMD_TFTPPUT
+void net_set_icmp_handler(rxhand_icmp_f *f)
+{
+ packet_icmp_handler = f;
+}
+#endif
void
-NetSetTimeout(ulong iv, thand_f * f)
+NetSetTimeout(ulong iv, thand_f *f)
{
if (iv == 0) {
+ debug_cond(DEBUG_INT_STATE,
+ "--- NetLoop timeout handler cancelled\n");
timeHandler = (thand_f *)0;
} else {
+ debug_cond(DEBUG_INT_STATE,
+ "--- NetLoop timeout handler set (%p)\n", f);
timeHandler = f;
timeStart = get_timer(0);
- timeDelta = iv;
+ timeDelta = iv * CONFIG_SYS_HZ / 1000;
}
}
-
-void
-NetSendPacket(volatile uchar * pkt, int len)
-{
- (void) eth_send(pkt, len);
-}
-
-int
-NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
+int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport,
+ int payload_len)
{
uchar *pkt;
+ int eth_hdr_size;
+ int pkt_hdr_size;
+
+ /* make sure the NetTxPacket is initialized (NetInit() was called) */
+ assert(NetTxPacket != NULL);
+ if (NetTxPacket == NULL)
+ return -1;
/* convert to new style broadcast */
if (dest == 0)
@@ -654,477 +719,37 @@ NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
if (dest == 0xFFFFFFFF)
ether = NetBcastAddr;
- /* if MAC address was not discovered yet, save the packet and do an ARP request */
- if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
+ pkt = (uchar *)NetTxPacket;
- debug("sending ARP for %08lx\n", dest);
+ eth_hdr_size = NetSetEther(pkt, ether, PROT_IP);
+ pkt += eth_hdr_size;
+ net_set_udp_header(pkt, dest, dport, sport, payload_len);
+ pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE;
+ /* if MAC address was not discovered yet, do an ARP request */
+ if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
+ debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &dest);
+
+ /* save the ip and eth addr for the packet to send after arp */
NetArpWaitPacketIP = dest;
NetArpWaitPacketMAC = ether;
- pkt = NetArpWaitTxPacket;
- pkt += NetSetEther (pkt, NetArpWaitPacketMAC, PROT_IP);
-
- NetSetIP (pkt, dest, dport, sport, len);
- memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket + (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
-
/* size of the waiting packet */
- NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE + len;
+ NetArpWaitTxPacketSize = pkt_hdr_size + payload_len;
/* and do the ARP request */
NetArpWaitTry = 1;
NetArpWaitTimerStart = get_timer(0);
ArpRequest();
return 1; /* waiting */
+ } else {
+ debug_cond(DEBUG_DEV_PKT, "sending UDP to %pI4/%pM\n",
+ &dest, ether);
+ NetSendPacket(NetTxPacket, pkt_hdr_size + payload_len);
+ return 0; /* transmitted */
}
-
- debug("sending UDP to %08lx/%pM\n", dest, ether);
-
- pkt = (uchar *)NetTxPacket;
- pkt += NetSetEther (pkt, ether, PROT_IP);
- NetSetIP (pkt, dest, dport, sport, len);
- (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
-
- return 0; /* transmitted */
-}
-
-#if defined(CONFIG_CMD_PING)
-static ushort PingSeqNo;
-
-int PingSend(void)
-{
- static uchar mac[6];
- volatile IP_t *ip;
- volatile ushort *s;
- uchar *pkt;
-
- /* XXX always send arp request */
-
- memcpy(mac, NetEtherNullAddr, 6);
-
- debug("sending ARP for %08lx\n", NetPingIP);
-
- NetArpWaitPacketIP = NetPingIP;
- NetArpWaitPacketMAC = mac;
-
- pkt = NetArpWaitTxPacket;
- pkt += NetSetEther(pkt, mac, PROT_IP);
-
- ip = (volatile IP_t *)pkt;
-
- /*
- * Construct an IP and ICMP header. (need to set no fragment bit - XXX)
- */
- ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
- ip->ip_tos = 0;
- ip->ip_len = htons(IP_HDR_SIZE_NO_UDP + 8);
- ip->ip_id = htons(NetIPID++);
- ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
- ip->ip_ttl = 255;
- ip->ip_p = 0x01; /* ICMP */
- ip->ip_sum = 0;
- NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
- NetCopyIP((void*)&ip->ip_dst, &NetPingIP); /* - "" - */
- ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
-
- s = &ip->udp_src; /* XXX ICMP starts here */
- s[0] = htons(0x0800); /* echo-request, code */
- s[1] = 0; /* checksum */
- s[2] = 0; /* identifier */
- s[3] = htons(PingSeqNo++); /* sequence number */
- s[1] = ~NetCksum((uchar *)s, 8/2);
-
- /* size of the waiting packet */
- NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
-
- /* and do the ARP request */
- NetArpWaitTry = 1;
- NetArpWaitTimerStart = get_timer(0);
- ArpRequest();
- return 1; /* waiting */
-}
-
-static void
-PingTimeout (void)
-{
- eth_halt();
- NetState = NETLOOP_FAIL; /* we did not get the reply */
-}
-
-static void
-PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
-{
- IPaddr_t tmp;
- volatile IP_t *ip = (volatile IP_t *)pkt;
-
- tmp = NetReadIP((void *)&ip->ip_src);
- if (tmp != NetPingIP)
- return;
-
- NetState = NETLOOP_SUCCESS;
-}
-
-static void PingStart(void)
-{
-#if defined(CONFIG_NET_MULTI)
- printf ("Using %s device\n", eth_get_name());
-#endif /* CONFIG_NET_MULTI */
- NetSetTimeout (10000UL, PingTimeout);
- NetSetHandler (PingHandler);
-
- PingSend();
-}
-#endif
-
-#if defined(CONFIG_CMD_CDP)
-
-#define CDP_DEVICE_ID_TLV 0x0001
-#define CDP_ADDRESS_TLV 0x0002
-#define CDP_PORT_ID_TLV 0x0003
-#define CDP_CAPABILITIES_TLV 0x0004
-#define CDP_VERSION_TLV 0x0005
-#define CDP_PLATFORM_TLV 0x0006
-#define CDP_NATIVE_VLAN_TLV 0x000a
-#define CDP_APPLIANCE_VLAN_TLV 0x000e
-#define CDP_TRIGGER_TLV 0x000f
-#define CDP_POWER_CONSUMPTION_TLV 0x0010
-#define CDP_SYSNAME_TLV 0x0014
-#define CDP_SYSOBJECT_TLV 0x0015
-#define CDP_MANAGEMENT_ADDRESS_TLV 0x0016
-
-#define CDP_TIMEOUT 250UL /* one packet every 250ms */
-
-static int CDPSeq;
-static int CDPOK;
-
-ushort CDPNativeVLAN;
-ushort CDPApplianceVLAN;
-
-static const uchar CDP_SNAP_hdr[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
-
-static ushort CDP_compute_csum(const uchar *buff, ushort len)
-{
- ushort csum;
- int odd;
- ulong result = 0;
- ushort leftover;
- ushort *p;
-
- if (len > 0) {
- odd = 1 & (ulong)buff;
- if (odd) {
- result = *buff << 8;
- len--;
- buff++;
- }
- while (len > 1) {
- p = (ushort *)buff;
- result += *p++;
- buff = (uchar *)p;
- if (result & 0x80000000)
- result = (result & 0xFFFF) + (result >> 16);
- len -= 2;
- }
- if (len) {
- leftover = (signed short)(*(const signed char *)buff);
- /* CISCO SUCKS big time! (and blows too):
- * CDP uses the IP checksum algorithm with a twist;
- * for the last byte it *sign* extends and sums.
- */
- result = (result & 0xffff0000) | ((result + leftover) & 0x0000ffff);
- }
- while (result >> 16)
- result = (result & 0xFFFF) + (result >> 16);
-
- if (odd)
- result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
- }
-
- /* add up 16-bit and 17-bit words for 17+c bits */
- result = (result & 0xffff) + (result >> 16);
- /* add up 16-bit and 2-bit for 16+c bit */
- result = (result & 0xffff) + (result >> 16);
- /* add up carry.. */
- result = (result & 0xffff) + (result >> 16);
-
- /* negate */
- csum = ~(ushort)result;
-
- /* run time endian detection */
- if (csum != htons(csum)) /* little endian */
- csum = htons(csum);
-
- return csum;
-}
-
-int CDPSendTrigger(void)
-{
- volatile uchar *pkt;
- volatile ushort *s;
- volatile ushort *cp;
- Ethernet_t *et;
- int len;
- ushort chksum;
-#if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \
- defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM)
- char buf[32];
-#endif
-
- pkt = NetTxPacket;
- et = (Ethernet_t *)pkt;
-
- /* NOTE: trigger sent not on any VLAN */
-
- /* form ethernet header */
- memcpy(et->et_dest, NetCDPAddr, 6);
- memcpy(et->et_src, NetOurEther, 6);
-
- pkt += ETHER_HDR_SIZE;
-
- /* SNAP header */
- memcpy((uchar *)pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr));
- pkt += sizeof(CDP_SNAP_hdr);
-
- /* CDP header */
- *pkt++ = 0x02; /* CDP version 2 */
- *pkt++ = 180; /* TTL */
- s = (volatile ushort *)pkt;
- cp = s;
- *s++ = htons(0); /* checksum (0 for later calculation) */
-
- /* CDP fields */
-#ifdef CONFIG_CDP_DEVICE_ID
- *s++ = htons(CDP_DEVICE_ID_TLV);
- *s++ = htons(CONFIG_CDP_DEVICE_ID);
- sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther);
- memcpy((uchar *)s, buf, 16);
- s += 16 / 2;
-#endif
-
-#ifdef CONFIG_CDP_PORT_ID
- *s++ = htons(CDP_PORT_ID_TLV);
- memset(buf, 0, sizeof(buf));
- sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
- len = strlen(buf);
- if (len & 1) /* make it even */
- len++;
- *s++ = htons(len + 4);
- memcpy((uchar *)s, buf, len);
- s += len / 2;
-#endif
-
-#ifdef CONFIG_CDP_CAPABILITIES
- *s++ = htons(CDP_CAPABILITIES_TLV);
- *s++ = htons(8);
- *(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
- s += 2;
-#endif
-
-#ifdef CONFIG_CDP_VERSION
- *s++ = htons(CDP_VERSION_TLV);
- memset(buf, 0, sizeof(buf));
- strcpy(buf, CONFIG_CDP_VERSION);
- len = strlen(buf);
- if (len & 1) /* make it even */
- len++;
- *s++ = htons(len + 4);
- memcpy((uchar *)s, buf, len);
- s += len / 2;
-#endif
-
-#ifdef CONFIG_CDP_PLATFORM
- *s++ = htons(CDP_PLATFORM_TLV);
- memset(buf, 0, sizeof(buf));
- strcpy(buf, CONFIG_CDP_PLATFORM);
- len = strlen(buf);
- if (len & 1) /* make it even */
- len++;
- *s++ = htons(len + 4);
- memcpy((uchar *)s, buf, len);
- s += len / 2;
-#endif
-
-#ifdef CONFIG_CDP_TRIGGER
- *s++ = htons(CDP_TRIGGER_TLV);
- *s++ = htons(8);
- *(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
- s += 2;
-#endif
-
-#ifdef CONFIG_CDP_POWER_CONSUMPTION
- *s++ = htons(CDP_POWER_CONSUMPTION_TLV);
- *s++ = htons(6);
- *s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
-#endif
-
- /* length of ethernet packet */
- len = (uchar *)s - ((uchar *)NetTxPacket + ETHER_HDR_SIZE);
- et->et_protlen = htons(len);
-
- len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr);
- chksum = CDP_compute_csum((uchar *)NetTxPacket + len, (uchar *)s - (NetTxPacket + len));
- if (chksum == 0)
- chksum = 0xFFFF;
- *cp = htons(chksum);
-
- (void) eth_send(NetTxPacket, (uchar *)s - NetTxPacket);
- return 0;
-}
-
-static void
-CDPTimeout (void)
-{
- CDPSeq++;
-
- if (CDPSeq < 3) {
- NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
- CDPSendTrigger();
- return;
- }
-
- /* if not OK try again */
- if (!CDPOK)
- NetStartAgain();
- else
- NetState = NETLOOP_SUCCESS;
-}
-
-static void
-CDPDummyHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
-{
- /* nothing */
-}
-
-static void
-CDPHandler(const uchar * pkt, unsigned len)
-{
- const uchar *t;
- const ushort *ss;
- ushort type, tlen;
- uchar applid;
- ushort vlan, nvlan;
-
- /* minimum size? */
- if (len < sizeof(CDP_SNAP_hdr) + 4)
- goto pkt_short;
-
- /* check for valid CDP SNAP header */
- if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0)
- return;
-
- pkt += sizeof(CDP_SNAP_hdr);
- len -= sizeof(CDP_SNAP_hdr);
-
- /* Version of CDP protocol must be >= 2 and TTL != 0 */
- if (pkt[0] < 0x02 || pkt[1] == 0)
- return;
-
- /* if version is greater than 0x02 maybe we'll have a problem; output a warning */
- if (pkt[0] != 0x02)
- printf("** WARNING: CDP packet received with a protocol version %d > 2\n",
- pkt[0] & 0xff);
-
- if (CDP_compute_csum(pkt, len) != 0)
- return;
-
- pkt += 4;
- len -= 4;
-
- vlan = htons(-1);
- nvlan = htons(-1);
- while (len > 0) {
- if (len < 4)
- goto pkt_short;
-
- ss = (const ushort *)pkt;
- type = ntohs(ss[0]);
- tlen = ntohs(ss[1]);
- if (tlen > len) {
- goto pkt_short;
- }
-
- pkt += tlen;
- len -= tlen;
-
- ss += 2; /* point ss to the data of the TLV */
- tlen -= 4;
-
- switch (type) {
- case CDP_DEVICE_ID_TLV:
- break;
- case CDP_ADDRESS_TLV:
- break;
- case CDP_PORT_ID_TLV:
- break;
- case CDP_CAPABILITIES_TLV:
- break;
- case CDP_VERSION_TLV:
- break;
- case CDP_PLATFORM_TLV:
- break;
- case CDP_NATIVE_VLAN_TLV:
- nvlan = *ss;
- break;
- case CDP_APPLIANCE_VLAN_TLV:
- t = (const uchar *)ss;
- while (tlen > 0) {
- if (tlen < 3)
- goto pkt_short;
-
- applid = t[0];
- ss = (const ushort *)(t + 1);
-
-#ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
- if (applid == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
- vlan = *ss;
-#else
- vlan = ntohs(*ss); /* XXX will this work; dunno */
-#endif
- t += 3; tlen -= 3;
- }
- break;
- case CDP_TRIGGER_TLV:
- break;
- case CDP_POWER_CONSUMPTION_TLV:
- break;
- case CDP_SYSNAME_TLV:
- break;
- case CDP_SYSOBJECT_TLV:
- break;
- case CDP_MANAGEMENT_ADDRESS_TLV:
- break;
- }
- }
-
- CDPApplianceVLAN = vlan;
- CDPNativeVLAN = nvlan;
-
- CDPOK = 1;
- return;
-
- pkt_short:
- printf("** CDP packet is too short\n");
- return;
}
-static void CDPStart(void)
-{
-#if defined(CONFIG_NET_MULTI)
- printf ("Using %s device\n", eth_get_name());
-#endif
- CDPSeq = 0;
- CDPOK = 0;
-
- CDPNativeVLAN = htons(-1);
- CDPApplianceVLAN = htons(-1);
-
- NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
- NetSetHandler (CDPDummyHandler);
-
- CDPSendTrigger();
-}
-#endif
-
#ifdef CONFIG_IP_DEFRAG
/*
* This function collects fragments in a single packet, according
@@ -1144,7 +769,7 @@ static void CDPStart(void)
static struct rpc_t rpc_specimen;
#define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG + sizeof(rpc_specimen.u.reply))
-#define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE_NO_UDP)
+#define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE)
/*
* this is the packet being assembled, either data or frag control.
@@ -1158,22 +783,22 @@ struct hole {
u16 unused;
};
-static IP_t *__NetDefragment(IP_t *ip, int *lenp)
+static struct ip_udp_hdr *__NetDefragment(struct ip_udp_hdr *ip, int *lenp)
{
- static uchar pkt_buff[IP_PKTSIZE] __attribute__((aligned(PKTALIGN)));
+ static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
static u16 first_hole, total_len;
struct hole *payload, *thisfrag, *h, *newh;
- IP_t *localip = (IP_t *)pkt_buff;
+ struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
uchar *indata = (uchar *)ip;
int offset8, start, len, done = 0;
u16 ip_off = ntohs(ip->ip_off);
/* payload starts after IP header, this fragment is in there */
- payload = (struct hole *)(pkt_buff + IP_HDR_SIZE_NO_UDP);
+ payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
offset8 = (ip_off & IP_OFFS);
thisfrag = payload + offset8;
start = offset8 * 8;
- len = ntohs(ip->ip_len) - IP_HDR_SIZE_NO_UDP;
+ len = ntohs(ip->ip_len) - IP_HDR_SIZE;
if (start + len > IP_MAXUDP) /* fragment extends too far */
return NULL;
@@ -1186,7 +811,7 @@ static IP_t *__NetDefragment(IP_t *ip, int *lenp)
payload[0].prev_hole = 0;
first_hole = 0;
/* any IP header will work, copy the first we received */
- memcpy(localip, ip, IP_HDR_SIZE_NO_UDP);
+ memcpy(localip, ip, IP_HDR_SIZE);
}
/*
@@ -1223,7 +848,7 @@ static IP_t *__NetDefragment(IP_t *ip, int *lenp)
* (thus being a superset of a previously-received fragment).
*/
- if ( (h >= thisfrag) && (h->last_byte <= start + len) ) {
+ if ((h >= thisfrag) && (h->last_byte <= start + len)) {
/* complete overlap with hole: remove hole */
if (!h->prev_hole && !h->next_hole) {
/* last remaining hole */
@@ -1269,16 +894,16 @@ static IP_t *__NetDefragment(IP_t *ip, int *lenp)
}
/* finally copy this fragment and possibly return whole packet */
- memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE_NO_UDP, len);
+ memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);
if (!done)
return NULL;
localip->ip_len = htons(total_len);
- *lenp = total_len + IP_HDR_SIZE_NO_UDP;
+ *lenp = total_len + IP_HDR_SIZE;
return localip;
}
-static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
+static inline struct ip_udp_hdr *NetDefragment(struct ip_udp_hdr *ip, int *lenp)
{
u16 ip_off = ntohs(ip->ip_off);
if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
@@ -1288,7 +913,7 @@ static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
#else /* !CONFIG_IP_DEFRAG */
-static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
+static inline struct ip_udp_hdr *NetDefragment(struct ip_udp_hdr *ip, int *lenp)
{
u16 ip_off = ntohs(ip->ip_off);
if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
@@ -1297,25 +922,56 @@ static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
}
#endif
+/**
+ * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
+ * drop others.
+ *
+ * @parma ip IP packet containing the ICMP
+ */
+static void receive_icmp(struct ip_udp_hdr *ip, int len,
+ IPaddr_t src_ip, struct ethernet_hdr *et)
+{
+ struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
+
+ switch (icmph->type) {
+ case ICMP_REDIRECT:
+ if (icmph->code != ICMP_REDIR_HOST)
+ return;
+ printf(" ICMP Host Redirect to %pI4 ",
+ &icmph->un.gateway);
+ break;
+ default:
+#if defined(CONFIG_CMD_PING)
+ ping_receive(et, ip, len);
+#endif
+#ifdef CONFIG_CMD_TFTPPUT
+ if (packet_icmp_handler)
+ packet_icmp_handler(icmph->type, icmph->code,
+ ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src),
+ icmph->un.data, ntohs(ip->udp_len));
+#endif
+ break;
+ }
+}
+
void
-NetReceive(volatile uchar * inpkt, int len)
+NetReceive(uchar *inpkt, int len)
{
- Ethernet_t *et;
- IP_t *ip;
- ARP_t *arp;
- IPaddr_t tmp;
- int x;
- uchar *pkt;
+ struct ethernet_hdr *et;
+ struct ip_udp_hdr *ip;
+ IPaddr_t dst_ip;
+ IPaddr_t src_ip;
+ int eth_proto;
#if defined(CONFIG_CMD_CDP)
int iscdp;
#endif
ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
- debug("packet received\n");
+ debug_cond(DEBUG_NET_PKT, "packet received\n");
NetRxPacket = inpkt;
NetRxPacketLen = len;
- et = (Ethernet_t *)inpkt;
+ et = (struct ethernet_hdr *)inpkt;
/* too small packet? */
if (len < ETHER_HDR_SIZE)
@@ -1330,7 +986,7 @@ NetReceive(volatile uchar * inpkt, int len)
#if defined(CONFIG_CMD_CDP)
/* keep track if packet is CDP */
- iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
+ iscdp = is_cdp_packet(et->et_dest);
#endif
myvlanid = ntohs(NetOurVLAN);
@@ -1340,27 +996,28 @@ NetReceive(volatile uchar * inpkt, int len)
if (mynvlanid == (ushort)-1)
mynvlanid = VLAN_NONE;
- x = ntohs(et->et_protlen);
-
- debug("packet received\n");
+ eth_proto = ntohs(et->et_protlen);
- if (x < 1514) {
+ if (eth_proto < 1514) {
+ struct e802_hdr *et802 = (struct e802_hdr *)et;
/*
- * Got a 802 packet. Check the other protocol field.
+ * Got a 802.2 packet. Check the other protocol field.
+ * XXX VLAN over 802.2+SNAP not implemented!
*/
- x = ntohs(et->et_prot);
+ eth_proto = ntohs(et802->et_prot);
- ip = (IP_t *)(inpkt + E802_HDR_SIZE);
+ ip = (struct ip_udp_hdr *)(inpkt + E802_HDR_SIZE);
len -= E802_HDR_SIZE;
- } else if (x != PROT_VLAN) { /* normal packet */
- ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
+ } else if (eth_proto != PROT_VLAN) { /* normal packet */
+ ip = (struct ip_udp_hdr *)(inpkt + ETHER_HDR_SIZE);
len -= ETHER_HDR_SIZE;
} else { /* VLAN packet */
- VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
+ struct vlan_ethernet_hdr *vet =
+ (struct vlan_ethernet_hdr *)et;
- debug("VLAN packet received\n");
+ debug_cond(DEBUG_NET_PKT, "VLAN packet received\n");
/* too small packet? */
if (len < VLAN_ETHER_HDR_SIZE)
@@ -1376,17 +1033,17 @@ NetReceive(volatile uchar * inpkt, int len)
cti = ntohs(vet->vet_tag);
vlanid = cti & VLAN_IDMASK;
- x = ntohs(vet->vet_type);
+ eth_proto = ntohs(vet->vet_type);
- ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
+ ip = (struct ip_udp_hdr *)(inpkt + VLAN_ETHER_HDR_SIZE);
len -= VLAN_ETHER_HDR_SIZE;
}
- debug("Receive from protocol 0x%x\n", x);
+ debug_cond(DEBUG_NET_PKT, "Receive from protocol 0x%x\n", eth_proto);
#if defined(CONFIG_CMD_CDP)
if (iscdp) {
- CDPHandler((uchar *)ip, len);
+ cdp_receive((uchar *)ip, len);
return;
}
#endif
@@ -1399,170 +1056,62 @@ NetReceive(volatile uchar * inpkt, int len)
return;
}
- switch (x) {
+ switch (eth_proto) {
case PROT_ARP:
- /*
- * We have to deal with two types of ARP packets:
- * - REQUEST packets will be answered by sending our
- * IP address - if we know it.
- * - REPLY packates are expected only after we asked
- * for the TFTP server's or the gateway's ethernet
- * address; so if we receive such a packet, we set
- * the server ethernet address
- */
- debug("Got ARP\n");
-
- arp = (ARP_t *)ip;
- if (len < ARP_HDR_SIZE) {
- printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
- return;
- }
- if (ntohs(arp->ar_hrd) != ARP_ETHER) {
- return;
- }
- if (ntohs(arp->ar_pro) != PROT_IP) {
- return;
- }
- if (arp->ar_hln != 6) {
- return;
- }
- if (arp->ar_pln != 4) {
- return;
- }
-
- if (NetOurIP == 0) {
- return;
- }
-
- if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {
- return;
- }
-
- switch (ntohs(arp->ar_op)) {
- case ARPOP_REQUEST: /* reply with our IP address */
- debug("Got ARP REQUEST, return our IP\n");
- pkt = (uchar *)et;
- pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
- arp->ar_op = htons(ARPOP_REPLY);
- memcpy (&arp->ar_data[10], &arp->ar_data[0], 6);
- NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
- memcpy (&arp->ar_data[ 0], NetOurEther, 6);
- NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
- (void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);
- return;
-
- case ARPOP_REPLY: /* arp reply */
- /* are we waiting for a reply */
- if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
- break;
-
-#ifdef CONFIG_KEEP_SERVERADDR
- if (NetServerIP == NetArpWaitPacketIP) {
- char buf[20];
- sprintf(buf, "%pM", arp->ar_data);
- setenv("serveraddr", buf);
- }
-#endif
-
- debug("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
- arp->ar_data);
-
- tmp = NetReadIP(&arp->ar_data[6]);
-
- /* matched waiting packet's address */
- if (tmp == NetArpWaitReplyIP) {
- debug("Got it\n");
- /* save address for later use */
- memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
-
-#ifdef CONFIG_NETCONSOLE
- (*packetHandler)(0,0,0,0);
-#endif
- /* modify header, and transmit it */
- memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
- (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);
-
- /* no arp request pending now */
- NetArpWaitPacketIP = 0;
- NetArpWaitTxPacketSize = 0;
- NetArpWaitPacketMAC = NULL;
-
- }
- return;
- default:
- debug("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
- return;
- }
+ ArpReceive(et, ip, len);
break;
#ifdef CONFIG_CMD_RARP
case PROT_RARP:
- debug("Got RARP\n");
- arp = (ARP_t *)ip;
- if (len < ARP_HDR_SIZE) {
- printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
- return;
- }
-
- if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
- (ntohs(arp->ar_hrd) != ARP_ETHER) ||
- (ntohs(arp->ar_pro) != PROT_IP) ||
- (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
-
- puts ("invalid RARP header\n");
- } else {
- NetCopyIP(&NetOurIP, &arp->ar_data[16]);
- if (NetServerIP == 0)
- NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
- memcpy (NetServerEther, &arp->ar_data[ 0], 6);
-
- (*packetHandler)(0,0,0,0);
- }
+ rarp_receive(ip, len);
break;
#endif
case PROT_IP:
- debug("Got IP\n");
+ debug_cond(DEBUG_NET_PKT, "Got IP\n");
/* Before we start poking the header, make sure it is there */
- if (len < IP_HDR_SIZE) {
- debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
+ if (len < IP_UDP_HDR_SIZE) {
+ debug("len bad %d < %lu\n", len,
+ (ulong)IP_UDP_HDR_SIZE);
return;
}
/* Check the packet length */
if (len < ntohs(ip->ip_len)) {
- printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
+ debug("len bad %d < %d\n", len, ntohs(ip->ip_len));
return;
}
len = ntohs(ip->ip_len);
- debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
+ debug_cond(DEBUG_NET_PKT, "len=%d, v=%02x\n",
+ len, ip->ip_hl_v & 0xff);
/* Can't deal with anything except IPv4 */
- if ((ip->ip_hl_v & 0xf0) != 0x40) {
+ if ((ip->ip_hl_v & 0xf0) != 0x40)
return;
- }
/* Can't deal with IP options (headers != 20 bytes) */
- if ((ip->ip_hl_v & 0x0f) > 0x05) {
+ if ((ip->ip_hl_v & 0x0f) > 0x05)
return;
- }
/* Check the Checksum of the header */
- if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
- puts ("checksum bad\n");
+ if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE / 2)) {
+ debug("checksum bad\n");
return;
}
/* If it is not for us, ignore it */
- tmp = NetReadIP(&ip->ip_dst);
- if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
+ dst_ip = NetReadIP(&ip->ip_dst);
+ if (NetOurIP && dst_ip != NetOurIP && dst_ip != 0xFFFFFFFF) {
#ifdef CONFIG_MCAST_TFTP
- if (Mcast_addr != tmp)
+ if (Mcast_addr != dst_ip)
#endif
- return;
+ return;
}
+ /* Read source IP address for later use */
+ src_ip = NetReadIP(&ip->ip_src);
/*
* The function returns the unchanged packet if it's not
* a fragment, and either the complete packet or NULL if
* it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
*/
- if (!(ip = NetDefragment(ip, &len)))
+ ip = NetDefragment(ip, &len);
+ if (!ip)
return;
/*
* watch for ICMP host redirects
@@ -1580,51 +1129,22 @@ NetReceive(volatile uchar * inpkt, int len)
* subnet. So this is probably a warning that your
* configuration might be wrong. But I'm not really
* sure if there aren't any other situations.
+ *
+ * Simon Glass <sjg@chromium.org>: We get an ICMP when
+ * we send a tftp packet to a dead connection, or when
+ * there is no server at the other end.
*/
if (ip->ip_p == IPPROTO_ICMP) {
- ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
-
- switch (icmph->type) {
- case ICMP_REDIRECT:
- if (icmph->code != ICMP_REDIR_HOST)
- return;
- printf (" ICMP Host Redirect to %pI4 ", &icmph->un.gateway);
- return;
-#if defined(CONFIG_CMD_PING)
- case ICMP_ECHO_REPLY:
- /*
- * IP header OK. Pass the packet to the current handler.
- */
- /* XXX point to ip packet */
- (*packetHandler)((uchar *)ip, 0, 0, 0);
- return;
- case ICMP_ECHO_REQUEST:
- debug("Got ICMP ECHO REQUEST, return %d bytes \n",
- ETHER_HDR_SIZE + len);
-
- memcpy (&et->et_dest[0], &et->et_src[0], 6);
- memcpy (&et->et_src[ 0], NetOurEther, 6);
-
- ip->ip_sum = 0;
- ip->ip_off = 0;
- NetCopyIP((void*)&ip->ip_dst, &ip->ip_src);
- NetCopyIP((void*)&ip->ip_src, &NetOurIP);
- ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP >> 1);
-
- icmph->type = ICMP_ECHO_REPLY;
- icmph->checksum = 0;
- icmph->checksum = ~NetCksum((uchar *)icmph,
- (len - IP_HDR_SIZE_NO_UDP) >> 1);
- (void) eth_send((uchar *)et, ETHER_HDR_SIZE + len);
- return;
-#endif
- default:
- return;
- }
+ receive_icmp(ip, len, src_ip, et);
+ return;
} else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
return;
}
+ debug_cond(DEBUG_DEV_PKT,
+ "received UDP (to=%pI4, from=%pI4, len=%d)\n",
+ &dst_ip, &src_ip, len);
+
#ifdef CONFIG_UDP_CHECKSUM
if (ip->udp_xsum != 0) {
ulong xsum;
@@ -1656,7 +1176,8 @@ NetReceive(volatile uchar * inpkt, int len)
xsum += sumdata;
}
while ((xsum >> 16) != 0) {
- xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
+ xsum = (xsum & 0x0000ffff) +
+ ((xsum >> 16) & 0x0000ffff);
}
if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
printf(" UDP wrong checksum %08lx %08x\n",
@@ -1668,18 +1189,20 @@ NetReceive(volatile uchar * inpkt, int len)
#ifdef CONFIG_NETCONSOLE
- nc_input_packet((uchar *)ip +IP_HDR_SIZE,
- ntohs(ip->udp_dst),
- ntohs(ip->udp_src),
- ntohs(ip->udp_len) - 8);
+ nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE,
+ src_ip,
+ ntohs(ip->udp_dst),
+ ntohs(ip->udp_src),
+ ntohs(ip->udp_len) - UDP_HDR_SIZE);
#endif
/*
* IP header OK. Pass the packet to the current handler.
*/
- (*packetHandler)((uchar *)ip +IP_HDR_SIZE,
- ntohs(ip->udp_dst),
- ntohs(ip->udp_src),
- ntohs(ip->udp_len) - 8);
+ (*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE,
+ ntohs(ip->udp_dst),
+ src_ip,
+ ntohs(ip->udp_src),
+ ntohs(ip->udp_len) - UDP_HDR_SIZE);
break;
}
}
@@ -1687,23 +1210,23 @@ NetReceive(volatile uchar * inpkt, int len)
/**********************************************************************/
-static int net_check_prereq (proto_t protocol)
+static int net_check_prereq(enum proto_t protocol)
{
switch (protocol) {
/* Fall through */
#if defined(CONFIG_CMD_PING)
case PING:
if (NetPingIP == 0) {
- puts ("*** ERROR: ping address not given\n");
- return (1);
+ puts("*** ERROR: ping address not given\n");
+ return 1;
}
goto common;
#endif
#if defined(CONFIG_CMD_SNTP)
case SNTP:
if (NetNtpServerIP == 0) {
- puts ("*** ERROR: NTP server address not given\n");
- return (1);
+ puts("*** ERROR: NTP server address not given\n");
+ return 1;
}
goto common;
#endif
@@ -1718,19 +1241,23 @@ static int net_check_prereq (proto_t protocol)
#if defined(CONFIG_CMD_NFS)
case NFS:
#endif
- case NETCONS:
- case TFTP:
+ case TFTPGET:
+ case TFTPPUT:
if (NetServerIP == 0) {
- puts ("*** ERROR: `serverip' not set\n");
- return (1);
+ puts("*** ERROR: `serverip' not set\n");
+ return 1;
}
-#if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP)
- common:
+#if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
+ defined(CONFIG_CMD_DNS)
+common:
#endif
+ /* Fall through */
+ case NETCONS:
+ case TFTPSRV:
if (NetOurIP == 0) {
- puts ("*** ERROR: `ipaddr' not set\n");
- return (1);
+ puts("*** ERROR: `ipaddr' not set\n");
+ return 1;
}
/* Fall through */
@@ -1740,48 +1267,43 @@ static int net_check_prereq (proto_t protocol)
case BOOTP:
case CDP:
case DHCP:
- if (memcmp (NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
-#ifdef CONFIG_NET_MULTI
- extern int eth_get_dev_index (void);
- int num = eth_get_dev_index ();
+ case LINKLOCAL:
+ if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
+ int num = eth_get_dev_index();
switch (num) {
case -1:
- puts ("*** ERROR: No ethernet found.\n");
- return (1);
+ puts("*** ERROR: No ethernet found.\n");
+ return 1;
case 0:
- puts ("*** ERROR: `ethaddr' not set\n");
+ puts("*** ERROR: `ethaddr' not set\n");
break;
default:
- printf ("*** ERROR: `eth%daddr' not set\n",
+ printf("*** ERROR: `eth%daddr' not set\n",
num);
break;
}
- NetStartAgain ();
- return (2);
-#else
- puts ("*** ERROR: `ethaddr' not set\n");
- return (1);
-#endif
+ NetStartAgain();
+ return 2;
}
/* Fall through */
default:
- return (0);
+ return 0;
}
- return (0); /* OK */
+ return 0; /* OK */
}
/**********************************************************************/
int
-NetCksumOk(uchar * ptr, int len)
+NetCksumOk(uchar *ptr, int len)
{
return !((NetCksum(ptr, len) + 1) & 0xfffe);
}
unsigned
-NetCksum(uchar * ptr, int len)
+NetCksum(uchar *ptr, int len)
{
ulong xsum;
ushort *p = (ushort *)ptr;
@@ -1791,7 +1313,7 @@ NetCksum(uchar * ptr, int len)
xsum += *p++;
xsum = (xsum & 0xffff) + (xsum >> 16);
xsum = (xsum & 0xffff) + (xsum >> 16);
- return (xsum & 0xffff);
+ return xsum & 0xffff;
}
int
@@ -1803,26 +1325,28 @@ NetEthHdrSize(void)
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
- return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE : VLAN_ETHER_HDR_SIZE;
+ return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
+ VLAN_ETHER_HDR_SIZE;
}
int
-NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
+NetSetEther(uchar *xet, uchar * addr, uint prot)
{
- Ethernet_t *et = (Ethernet_t *)xet;
+ struct ethernet_hdr *et = (struct ethernet_hdr *)xet;
ushort myvlanid;
myvlanid = ntohs(NetOurVLAN);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
- memcpy (et->et_dest, addr, 6);
- memcpy (et->et_src, NetOurEther, 6);
+ memcpy(et->et_dest, addr, 6);
+ memcpy(et->et_src, NetOurEther, 6);
if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
- et->et_protlen = htons(prot);
+ et->et_protlen = htons(prot);
return ETHER_HDR_SIZE;
} else {
- VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
+ struct vlan_ethernet_hdr *vet =
+ (struct vlan_ethernet_hdr *)xet;
vet->vet_vlan_type = htons(PROT_VLAN);
vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
@@ -1831,54 +1355,89 @@ NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
}
}
-void
-NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
+int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot)
{
- IP_t *ip = (IP_t *)xip;
+ ushort protlen;
- /*
- * If the data is an odd number of bytes, zero the
- * byte after the last byte so that the checksum
- * will work.
- */
- if (len & 1)
- xip[IP_HDR_SIZE + len] = 0;
+ memcpy(et->et_dest, addr, 6);
+ memcpy(et->et_src, NetOurEther, 6);
+ protlen = ntohs(et->et_protlen);
+ if (protlen == PROT_VLAN) {
+ struct vlan_ethernet_hdr *vet =
+ (struct vlan_ethernet_hdr *)et;
+ vet->vet_type = htons(prot);
+ return VLAN_ETHER_HDR_SIZE;
+ } else if (protlen > 1514) {
+ et->et_protlen = htons(prot);
+ return ETHER_HDR_SIZE;
+ } else {
+ /* 802.2 + SNAP */
+ struct e802_hdr *et802 = (struct e802_hdr *)et;
+ et802->et_prot = htons(prot);
+ return E802_HDR_SIZE;
+ }
+}
+
+void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source)
+{
+ struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt;
/*
- * Construct an IP and UDP header.
- * (need to set no fragment bit - XXX)
+ * Construct an IP header.
*/
- ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
+ /* IP_HDR_SIZE / 4 (not including UDP) */
+ ip->ip_hl_v = 0x45;
ip->ip_tos = 0;
- ip->ip_len = htons(IP_HDR_SIZE + len);
+ ip->ip_len = htons(IP_HDR_SIZE);
ip->ip_id = htons(NetIPID++);
ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
ip->ip_ttl = 255;
- ip->ip_p = 17; /* UDP */
ip->ip_sum = 0;
- NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
- NetCopyIP((void*)&ip->ip_dst, &dest); /* - "" - */
+ /* already in network byte order */
+ NetCopyIP((void *)&ip->ip_src, &source);
+ /* already in network byte order */
+ NetCopyIP((void *)&ip->ip_dst, &dest);
+}
+
+void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport,
+ int len)
+{
+ struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt;
+
+ /*
+ * If the data is an odd number of bytes, zero the
+ * byte after the last byte so that the checksum
+ * will work.
+ */
+ if (len & 1)
+ pkt[IP_UDP_HDR_SIZE + len] = 0;
+
+ net_set_ip_header(pkt, dest, NetOurIP);
+ ip->ip_len = htons(IP_UDP_HDR_SIZE + len);
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE >> 1);
+
ip->udp_src = htons(sport);
ip->udp_dst = htons(dport);
- ip->udp_len = htons(8 + len);
+ ip->udp_len = htons(UDP_HDR_SIZE + len);
ip->udp_xsum = 0;
- ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
}
-void copy_filename (char *dst, char *src, int size)
+void copy_filename(char *dst, const char *src, int size)
{
if (*src && (*src == '"')) {
++src;
--size;
}
- while ((--size > 0) && *src && (*src != '"')) {
+ while ((--size > 0) && *src && (*src != '"'))
*dst++ = *src++;
- }
*dst = '\0';
}
-#if defined(CONFIG_CMD_NFS) || defined(CONFIG_CMD_SNTP) || defined(CONFIG_CMD_DNS)
+#if defined(CONFIG_CMD_NFS) || \
+ defined(CONFIG_CMD_SNTP) || \
+ defined(CONFIG_CMD_DNS)
/*
* make port a little random (1024-17407)
* This keeps the math somewhat trivial to compute, and seems to work with
@@ -1890,13 +1449,13 @@ unsigned int random_port(void)
}
#endif
-void ip_to_string (IPaddr_t x, char *s)
+void ip_to_string(IPaddr_t x, char *s)
{
- x = ntohl (x);
- sprintf (s, "%d.%d.%d.%d",
- (int) ((x >> 24) & 0xff),
- (int) ((x >> 16) & 0xff),
- (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
+ x = ntohl(x);
+ sprintf(s, "%d.%d.%d.%d",
+ (int) ((x >> 24) & 0xff),
+ (int) ((x >> 16) & 0xff),
+ (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
);
}
@@ -1913,7 +1472,7 @@ void VLAN_to_string(ushort x, char *s)
sprintf(s, "%d", x & VLAN_IDMASK);
}
-ushort string_to_VLAN(char *s)
+ushort string_to_VLAN(const char *s)
{
ushort id;
@@ -1930,5 +1489,5 @@ ushort string_to_VLAN(char *s)
ushort getenv_VLAN(char *var)
{
- return (string_to_VLAN(getenv(var)));
+ return string_to_VLAN(getenv(var));
}
diff --git a/net/net_rand.h b/net/net_rand.h
new file mode 100644
index 0000000000..ba9d0642cf
--- /dev/null
+++ b/net/net_rand.h
@@ -0,0 +1,43 @@
+/*
+ * Copied from LiMon - BOOTP.
+ *
+ * Copyright 1994, 1995, 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000 Paolo Scaffardi
+ */
+
+#ifndef __NET_RAND_H__
+#define __NET_RAND_H__
+
+#include <common.h>
+
+/*
+ * Return a seed for the PRNG derived from the eth0 MAC address.
+ */
+static inline unsigned int seed_mac(void)
+{
+ unsigned char enetaddr[6];
+ unsigned int seed;
+
+ /* get our mac */
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+
+ seed = enetaddr[5];
+ seed ^= enetaddr[4] << 8;
+ seed ^= enetaddr[3] << 16;
+ seed ^= enetaddr[2] << 24;
+ seed ^= enetaddr[1];
+ seed ^= enetaddr[0] << 8;
+
+ return seed;
+}
+
+/*
+ * Seed the random number generator using the eth0 MAC address.
+ */
+static inline void srand_mac(void)
+{
+ srand(seed_mac());
+}
+
+#endif /* __NET_RAND_H__ */
diff --git a/net/nfs.c b/net/nfs.c
index d11bb4c15f..381b75f1c5 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -31,17 +31,25 @@
#define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */
#define NFS_RETRY_COUNT 30
-#define NFS_TIMEOUT 2000UL
+#ifndef CONFIG_NFS_TIMEOUT
+# define NFS_TIMEOUT 2000UL
+#else
+# define NFS_TIMEOUT CONFIG_NFS_TIMEOUT
+#endif
+
+#define NFS_RPC_ERR 1
+#define NFS_RPC_DROP 124
-static int fs_mounted = 0;
-static unsigned long rpc_id = 0;
+static int fs_mounted;
+static unsigned long rpc_id;
static int nfs_offset = -1;
static int nfs_len;
+static ulong nfs_timeout = NFS_TIMEOUT;
static char dirfh[NFS_FHSIZE]; /* file handle of directory */
static char filefh[NFS_FHSIZE]; /* file handle of kernel image */
-static int NfsDownloadState;
+static enum net_loop_state nfs_download_state;
static IPaddr_t NfsServerIP;
static int NfsSrvMountPort;
static int NfsSrvNfsPort;
@@ -61,14 +69,14 @@ static char *nfs_filename;
static char *nfs_path;
static char nfs_path_buff[2048];
-static __inline__ int
-store_block (uchar * src, unsigned offset, unsigned len)
+static inline int
+store_block(uchar *src, unsigned offset, unsigned len)
{
ulong newsize = offset + len;
#ifdef CONFIG_SYS_DIRECT_FLASH_NFS
int i, rc = 0;
- for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; i++) {
+ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
/* start address in flash? */
if (load_addr + offset >= flash_info[i].start[0]) {
rc = 1;
@@ -77,15 +85,15 @@ store_block (uchar * src, unsigned offset, unsigned len)
}
if (rc) { /* Flash is destination for this packet */
- rc = flash_write ((uchar *)src, (ulong)(load_addr+offset), len);
+ rc = flash_write((uchar *)src, (ulong)(load_addr+offset), len);
if (rc) {
- flash_perror (rc);
+ flash_perror(rc);
return -1;
}
} else
#endif /* CONFIG_SYS_DIRECT_FLASH_NFS */
{
- (void)memcpy ((void *)(load_addr + offset), src, len);
+ (void)memcpy((void *)(load_addr + offset), src, len);
}
if (NetBootFileXferSize < (offset+len))
@@ -94,7 +102,7 @@ store_block (uchar * src, unsigned offset, unsigned len)
}
static char*
-basename (char *path)
+basename(char *path)
{
char *fname;
@@ -110,11 +118,11 @@ basename (char *path)
}
static char*
-dirname (char *path)
+dirname(char *path)
{
char *fname;
- fname = basename (path);
+ fname = basename(path);
--fname;
*fname = '\0';
return path;
@@ -123,14 +131,14 @@ dirname (char *path)
/**************************************************************************
RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries
**************************************************************************/
-static long *rpc_add_credentials (long *p)
+static long *rpc_add_credentials(long *p)
{
int hl;
int hostnamelen;
char hostname[256];
- strcpy (hostname, "");
- hostnamelen=strlen (hostname);
+ strcpy(hostname, "");
+ hostnamelen = strlen(hostname);
/* Here's the executive summary on authentication requirements of the
* various NFS server implementations: Linux accepts both AUTH_NONE
@@ -148,10 +156,9 @@ static long *rpc_add_credentials (long *p)
*p++ = htonl(hl+20); /* auth length */
*p++ = htonl(0); /* stamp */
*p++ = htonl(hostnamelen); /* hostname string */
- if (hostnamelen & 3) {
+ if (hostnamelen & 3)
*(p + hostnamelen / 4) = 0; /* add zero padding */
- }
- memcpy (p, hostname, hostnamelen);
+ memcpy(p, hostname, hostnamelen);
p += hl / 4;
*p++ = 0; /* uid */
*p++ = 0; /* gid */
@@ -168,7 +175,7 @@ static long *rpc_add_credentials (long *p)
RPC_LOOKUP - Lookup RPC Port numbers
**************************************************************************/
static void
-rpc_req (int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
+rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
{
struct rpc_t pkt;
unsigned long id;
@@ -186,11 +193,12 @@ rpc_req (int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
p = (uint32_t *)&(pkt.u.call.data);
if (datalen)
- memcpy ((char *)p, (char *)data, datalen*sizeof(uint32_t));
+ memcpy((char *)p, (char *)data, datalen*sizeof(uint32_t));
pktlen = (char *)p + datalen*sizeof(uint32_t) - (char *)&pkt;
- memcpy ((char *)NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE, (char *)&pkt, pktlen);
+ memcpy((char *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE,
+ (char *)&pkt, pktlen);
if (rpc_prog == PROG_PORTMAP)
sport = SUNRPC_PORT;
@@ -199,14 +207,15 @@ rpc_req (int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
else
sport = NfsSrvNfsPort;
- NetSendUDPPacket (NetServerEther, NfsServerIP, sport, NfsOurPort, pktlen);
+ NetSendUDPPacket(NetServerEther, NfsServerIP, sport, NfsOurPort,
+ pktlen);
}
/**************************************************************************
RPC_LOOKUP - Lookup RPC Port numbers
**************************************************************************/
static void
-rpc_lookup_req (int prog, int ver)
+rpc_lookup_req(int prog, int ver)
{
uint32_t data[16];
@@ -217,56 +226,56 @@ rpc_lookup_req (int prog, int ver)
data[6] = htonl(17); /* IP_UDP */
data[7] = 0;
- rpc_req (PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
+ rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
}
/**************************************************************************
NFS_MOUNT - Mount an NFS Filesystem
**************************************************************************/
static void
-nfs_mount_req (char *path)
+nfs_mount_req(char *path)
{
uint32_t data[1024];
uint32_t *p;
int len;
int pathlen;
- pathlen = strlen (path);
+ pathlen = strlen(path);
p = &(data[0]);
p = (uint32_t *)rpc_add_credentials((long *)p);
*p++ = htonl(pathlen);
- if (pathlen & 3) *(p + pathlen / 4) = 0;
- memcpy (p, path, pathlen);
+ if (pathlen & 3)
+ *(p + pathlen / 4) = 0;
+ memcpy(p, path, pathlen);
p += (pathlen + 3) / 4;
len = (uint32_t *)p - (uint32_t *)&(data[0]);
- rpc_req (PROG_MOUNT, MOUNT_ADDENTRY, data, len);
+ rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, data, len);
}
/**************************************************************************
NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server
**************************************************************************/
static void
-nfs_umountall_req (void)
+nfs_umountall_req(void)
{
uint32_t data[1024];
uint32_t *p;
int len;
- if ((NfsSrvMountPort == -1) || (!fs_mounted)) {
+ if ((NfsSrvMountPort == -1) || (!fs_mounted))
/* Nothing mounted, nothing to umount */
return;
- }
p = &(data[0]);
- p = (uint32_t *)rpc_add_credentials ((long *)p);
+ p = (uint32_t *)rpc_add_credentials((long *)p);
len = (uint32_t *)p - (uint32_t *)&(data[0]);
- rpc_req (PROG_MOUNT, MOUNT_UMOUNTALL, data, len);
+ rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len);
}
/***************************************************************************
@@ -277,65 +286,66 @@ nfs_umountall_req (void)
* so that inside the nfs() function a recursion can be done.
**************************************************************************/
static void
-nfs_readlink_req (void)
+nfs_readlink_req(void)
{
uint32_t data[1024];
uint32_t *p;
int len;
p = &(data[0]);
- p = (uint32_t *)rpc_add_credentials ((long *)p);
+ p = (uint32_t *)rpc_add_credentials((long *)p);
- memcpy (p, filefh, NFS_FHSIZE);
+ memcpy(p, filefh, NFS_FHSIZE);
p += (NFS_FHSIZE / 4);
len = (uint32_t *)p - (uint32_t *)&(data[0]);
- rpc_req (PROG_NFS, NFS_READLINK, data, len);
+ rpc_req(PROG_NFS, NFS_READLINK, data, len);
}
/**************************************************************************
NFS_LOOKUP - Lookup Pathname
**************************************************************************/
static void
-nfs_lookup_req (char *fname)
+nfs_lookup_req(char *fname)
{
uint32_t data[1024];
uint32_t *p;
int len;
int fnamelen;
- fnamelen = strlen (fname);
+ fnamelen = strlen(fname);
p = &(data[0]);
- p = (uint32_t *)rpc_add_credentials ((long *)p);
+ p = (uint32_t *)rpc_add_credentials((long *)p);
- memcpy (p, dirfh, NFS_FHSIZE);
+ memcpy(p, dirfh, NFS_FHSIZE);
p += (NFS_FHSIZE / 4);
*p++ = htonl(fnamelen);
- if (fnamelen & 3) *(p + fnamelen / 4) = 0;
- memcpy (p, fname, fnamelen);
+ if (fnamelen & 3)
+ *(p + fnamelen / 4) = 0;
+ memcpy(p, fname, fnamelen);
p += (fnamelen + 3) / 4;
len = (uint32_t *)p - (uint32_t *)&(data[0]);
- rpc_req (PROG_NFS, NFS_LOOKUP, data, len);
+ rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
}
/**************************************************************************
NFS_READ - Read File on NFS Server
**************************************************************************/
static void
-nfs_read_req (int offset, int readlen)
+nfs_read_req(int offset, int readlen)
{
uint32_t data[1024];
uint32_t *p;
int len;
p = &(data[0]);
- p = (uint32_t *)rpc_add_credentials ((long *)p);
+ p = (uint32_t *)rpc_add_credentials((long *)p);
- memcpy (p, filefh, NFS_FHSIZE);
+ memcpy(p, filefh, NFS_FHSIZE);
p += (NFS_FHSIZE / 4);
*p++ = htonl(offset);
*p++ = htonl(readlen);
@@ -343,7 +353,7 @@ nfs_read_req (int offset, int readlen)
len = (uint32_t *)p - (uint32_t *)&(data[0]);
- rpc_req (PROG_NFS, NFS_READ, data, len);
+ rpc_req(PROG_NFS, NFS_READ, data, len);
}
/**************************************************************************
@@ -351,31 +361,31 @@ RPC request dispatcher
**************************************************************************/
static void
-NfsSend (void)
+NfsSend(void)
{
debug("%s\n", __func__);
switch (NfsState) {
case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
- rpc_lookup_req (PROG_MOUNT, 1);
+ rpc_lookup_req(PROG_MOUNT, 1);
break;
case STATE_PRCLOOKUP_PROG_NFS_REQ:
- rpc_lookup_req (PROG_NFS, 2);
+ rpc_lookup_req(PROG_NFS, 2);
break;
case STATE_MOUNT_REQ:
- nfs_mount_req (nfs_path);
+ nfs_mount_req(nfs_path);
break;
case STATE_UMOUNT_REQ:
- nfs_umountall_req ();
+ nfs_umountall_req();
break;
case STATE_LOOKUP_REQ:
- nfs_lookup_req (nfs_filename);
+ nfs_lookup_req(nfs_filename);
break;
case STATE_READ_REQ:
- nfs_read_req (nfs_offset, nfs_len);
+ nfs_read_req(nfs_offset, nfs_len);
break;
case STATE_READLINK_REQ:
- nfs_readlink_req ();
+ nfs_readlink_req();
break;
}
}
@@ -385,22 +395,23 @@ Handlers for the reply from server
**************************************************************************/
static int
-rpc_lookup_reply (int prog, uchar *pkt, unsigned len)
+rpc_lookup_reply(int prog, uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
- memcpy ((unsigned char *)&rpc_pkt, pkt, len);
+ memcpy((unsigned char *)&rpc_pkt, pkt, len);
debug("%s\n", __func__);
- if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
- return -1;
+ if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+ return -NFS_RPC_ERR;
+ else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+ return -NFS_RPC_DROP;
if (rpc_pkt.u.reply.rstatus ||
rpc_pkt.u.reply.verifier ||
- rpc_pkt.u.reply.astatus) {
+ rpc_pkt.u.reply.astatus)
return -1;
- }
switch (prog) {
case PROG_MOUNT:
@@ -415,148 +426,153 @@ rpc_lookup_reply (int prog, uchar *pkt, unsigned len)
}
static int
-nfs_mount_reply (uchar *pkt, unsigned len)
+nfs_mount_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
debug("%s\n", __func__);
- memcpy ((unsigned char *)&rpc_pkt, pkt, len);
+ memcpy((unsigned char *)&rpc_pkt, pkt, len);
- if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
- return -1;
+ if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+ return -NFS_RPC_ERR;
+ else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+ return -NFS_RPC_DROP;
if (rpc_pkt.u.reply.rstatus ||
rpc_pkt.u.reply.verifier ||
rpc_pkt.u.reply.astatus ||
- rpc_pkt.u.reply.data[0]) {
+ rpc_pkt.u.reply.data[0])
return -1;
- }
fs_mounted = 1;
- memcpy (dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+ memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
return 0;
}
static int
-nfs_umountall_reply (uchar *pkt, unsigned len)
+nfs_umountall_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
debug("%s\n", __func__);
- memcpy ((unsigned char *)&rpc_pkt, pkt, len);
+ memcpy((unsigned char *)&rpc_pkt, pkt, len);
- if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
- return -1;
+ if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+ return -NFS_RPC_ERR;
+ else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+ return -NFS_RPC_DROP;
if (rpc_pkt.u.reply.rstatus ||
rpc_pkt.u.reply.verifier ||
- rpc_pkt.u.reply.astatus) {
+ rpc_pkt.u.reply.astatus)
return -1;
- }
fs_mounted = 0;
- memset (dirfh, 0, sizeof(dirfh));
+ memset(dirfh, 0, sizeof(dirfh));
return 0;
}
static int
-nfs_lookup_reply (uchar *pkt, unsigned len)
+nfs_lookup_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
debug("%s\n", __func__);
- memcpy ((unsigned char *)&rpc_pkt, pkt, len);
+ memcpy((unsigned char *)&rpc_pkt, pkt, len);
- if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
- return -1;
+ if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+ return -NFS_RPC_ERR;
+ else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+ return -NFS_RPC_DROP;
if (rpc_pkt.u.reply.rstatus ||
rpc_pkt.u.reply.verifier ||
rpc_pkt.u.reply.astatus ||
- rpc_pkt.u.reply.data[0]) {
+ rpc_pkt.u.reply.data[0])
return -1;
- }
- memcpy (filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+ memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
return 0;
}
static int
-nfs_readlink_reply (uchar *pkt, unsigned len)
+nfs_readlink_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
int rlen;
debug("%s\n", __func__);
- memcpy ((unsigned char *)&rpc_pkt, pkt, len);
+ memcpy((unsigned char *)&rpc_pkt, pkt, len);
- if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
- return -1;
+ if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+ return -NFS_RPC_ERR;
+ else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+ return -NFS_RPC_DROP;
if (rpc_pkt.u.reply.rstatus ||
rpc_pkt.u.reply.verifier ||
rpc_pkt.u.reply.astatus ||
- rpc_pkt.u.reply.data[0]) {
+ rpc_pkt.u.reply.data[0])
return -1;
- }
- rlen = ntohl (rpc_pkt.u.reply.data[1]); /* new path length */
+ rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
int pathlen;
- strcat (nfs_path, "/");
+ strcat(nfs_path, "/");
pathlen = strlen(nfs_path);
- memcpy (nfs_path+pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen);
+ memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]),
+ rlen);
nfs_path[pathlen + rlen] = 0;
} else {
- memcpy (nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen);
+ memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen);
nfs_path[rlen] = 0;
}
return 0;
}
static int
-nfs_read_reply (uchar *pkt, unsigned len)
+nfs_read_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
int rlen;
debug("%s\n", __func__);
- memcpy ((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply));
+ memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply));
- if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
- return -1;
+ if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+ return -NFS_RPC_ERR;
+ else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+ return -NFS_RPC_DROP;
if (rpc_pkt.u.reply.rstatus ||
rpc_pkt.u.reply.verifier ||
rpc_pkt.u.reply.astatus ||
rpc_pkt.u.reply.data[0]) {
- if (rpc_pkt.u.reply.rstatus) {
+ if (rpc_pkt.u.reply.rstatus)
return -9999;
- }
- if (rpc_pkt.u.reply.astatus) {
+ if (rpc_pkt.u.reply.astatus)
return -9999;
- }
- return -ntohl(rpc_pkt.u.reply.data[0]);;
+ return -ntohl(rpc_pkt.u.reply.data[0]);
}
- if ((nfs_offset!=0) && !((nfs_offset) % (NFS_READ_SIZE/2*10*HASHES_PER_LINE))) {
- puts ("\n\t ");
- }
- if (!(nfs_offset % ((NFS_READ_SIZE/2)*10))) {
- putc ('#');
- }
+ if ((nfs_offset != 0) && !((nfs_offset) %
+ (NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE)))
+ puts("\n\t ");
+ if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10)))
+ putc('#');
rlen = ntohl(rpc_pkt.u.reply.data[18]);
- if ( store_block ((uchar *)pkt+sizeof(rpc_pkt.u.reply), nfs_offset, rlen) )
+ if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply),
+ nfs_offset, rlen))
return -9999;
return rlen;
@@ -567,105 +583,122 @@ Interfaces of U-BOOT
**************************************************************************/
static void
-NfsTimeout (void)
+NfsTimeout(void)
{
- if ( ++NfsTimeoutCount > NFS_RETRY_COUNT ) {
- puts ("\nRetry count exceeded; starting again\n");
- NetStartAgain ();
+ if (++NfsTimeoutCount > NFS_RETRY_COUNT) {
+ puts("\nRetry count exceeded; starting again\n");
+ NetStartAgain();
} else {
puts("T ");
- NetSetTimeout (NFS_TIMEOUT, NfsTimeout);
- NfsSend ();
+ NetSetTimeout(nfs_timeout + NFS_TIMEOUT * NfsTimeoutCount,
+ NfsTimeout);
+ NfsSend();
}
}
static void
-NfsHandler (uchar *pkt, unsigned dest, unsigned src, unsigned len)
+NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
{
int rlen;
+ int reply;
debug("%s\n", __func__);
- if (dest != NfsOurPort) return;
+ if (dest != NfsOurPort)
+ return;
switch (NfsState) {
case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
- rpc_lookup_reply (PROG_MOUNT, pkt, len);
+ if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP)
+ break;
NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ;
- NfsSend ();
+ NfsSend();
break;
case STATE_PRCLOOKUP_PROG_NFS_REQ:
- rpc_lookup_reply (PROG_NFS, pkt, len);
+ if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP)
+ break;
NfsState = STATE_MOUNT_REQ;
- NfsSend ();
+ NfsSend();
break;
case STATE_MOUNT_REQ:
- if (nfs_mount_reply(pkt, len)) {
- puts ("*** ERROR: Cannot mount\n");
+ reply = nfs_mount_reply(pkt, len);
+ if (reply == -NFS_RPC_DROP)
+ break;
+ else if (reply == -NFS_RPC_ERR) {
+ puts("*** ERROR: Cannot mount\n");
/* just to be sure... */
NfsState = STATE_UMOUNT_REQ;
- NfsSend ();
+ NfsSend();
} else {
NfsState = STATE_LOOKUP_REQ;
- NfsSend ();
+ NfsSend();
}
break;
case STATE_UMOUNT_REQ:
- if (nfs_umountall_reply(pkt, len)) {
- puts ("*** ERROR: Cannot umount\n");
- NetState = NETLOOP_FAIL;
+ reply = nfs_umountall_reply(pkt, len);
+ if (reply == -NFS_RPC_DROP)
+ break;
+ else if (reply == -NFS_RPC_ERR) {
+ puts("*** ERROR: Cannot umount\n");
+ net_set_state(NETLOOP_FAIL);
} else {
- puts ("\ndone\n");
- NetState = NfsDownloadState;
+ puts("\ndone\n");
+ net_set_state(nfs_download_state);
}
break;
case STATE_LOOKUP_REQ:
- if (nfs_lookup_reply(pkt, len)) {
- puts ("*** ERROR: File lookup fail\n");
+ reply = nfs_lookup_reply(pkt, len);
+ if (reply == -NFS_RPC_DROP)
+ break;
+ else if (reply == -NFS_RPC_ERR) {
+ puts("*** ERROR: File lookup fail\n");
NfsState = STATE_UMOUNT_REQ;
- NfsSend ();
+ NfsSend();
} else {
NfsState = STATE_READ_REQ;
nfs_offset = 0;
nfs_len = NFS_READ_SIZE;
- NfsSend ();
+ NfsSend();
}
break;
case STATE_READLINK_REQ:
- if (nfs_readlink_reply(pkt, len)) {
- puts ("*** ERROR: Symlink fail\n");
+ reply = nfs_readlink_reply(pkt, len);
+ if (reply == -NFS_RPC_DROP)
+ break;
+ else if (reply == -NFS_RPC_ERR) {
+ puts("*** ERROR: Symlink fail\n");
NfsState = STATE_UMOUNT_REQ;
- NfsSend ();
+ NfsSend();
} else {
debug("Symlink --> %s\n", nfs_path);
- nfs_filename = basename (nfs_path);
- nfs_path = dirname (nfs_path);
+ nfs_filename = basename(nfs_path);
+ nfs_path = dirname(nfs_path);
NfsState = STATE_MOUNT_REQ;
- NfsSend ();
+ NfsSend();
}
break;
case STATE_READ_REQ:
- rlen = nfs_read_reply (pkt, len);
- NetSetTimeout (NFS_TIMEOUT, NfsTimeout);
+ rlen = nfs_read_reply(pkt, len);
+ NetSetTimeout(nfs_timeout, NfsTimeout);
if (rlen > 0) {
nfs_offset += rlen;
- NfsSend ();
- }
- else if ((rlen == -NFSERR_ISDIR)||(rlen == -NFSERR_INVAL)) {
+ NfsSend();
+ } else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) {
/* symbolic link */
NfsState = STATE_READLINK_REQ;
- NfsSend ();
+ NfsSend();
} else {
- if ( ! rlen ) NfsDownloadState = NETLOOP_SUCCESS;
+ if (!rlen)
+ nfs_download_state = NETLOOP_SUCCESS;
NfsState = STATE_UMOUNT_REQ;
- NfsSend ();
+ NfsSend();
}
break;
}
@@ -673,50 +706,48 @@ NfsHandler (uchar *pkt, unsigned dest, unsigned src, unsigned len)
void
-NfsStart (void)
+NfsStart(void)
{
debug("%s\n", __func__);
- NfsDownloadState = NETLOOP_FAIL;
+ nfs_download_state = NETLOOP_FAIL;
NfsServerIP = NetServerIP;
nfs_path = (char *)nfs_path_buff;
if (nfs_path == NULL) {
- NetState = NETLOOP_FAIL;
- puts ("*** ERROR: Fail allocate memory\n");
+ net_set_state(NETLOOP_FAIL);
+ puts("*** ERROR: Fail allocate memory\n");
return;
}
if (BootFile[0] == '\0') {
- sprintf (default_filename, "/nfsroot/%02lX%02lX%02lX%02lX.img",
+ sprintf(default_filename, "/nfsroot/%02X%02X%02X%02X.img",
NetOurIP & 0xFF,
(NetOurIP >> 8) & 0xFF,
(NetOurIP >> 16) & 0xFF,
- (NetOurIP >> 24) & 0xFF );
- strcpy (nfs_path, default_filename);
+ (NetOurIP >> 24) & 0xFF);
+ strcpy(nfs_path, default_filename);
- printf ("*** Warning: no boot file name; using '%s'\n",
+ printf("*** Warning: no boot file name; using '%s'\n",
nfs_path);
} else {
- char *p=BootFile;
+ char *p = BootFile;
- p = strchr (p, ':');
+ p = strchr(p, ':');
if (p != NULL) {
- NfsServerIP = string_to_ip (BootFile);
+ NfsServerIP = string_to_ip(BootFile);
++p;
- strcpy (nfs_path, p);
+ strcpy(nfs_path, p);
} else {
- strcpy (nfs_path, BootFile);
+ strcpy(nfs_path, BootFile);
}
}
- nfs_filename = basename (nfs_path);
- nfs_path = dirname (nfs_path);
+ nfs_filename = basename(nfs_path);
+ nfs_path = dirname(nfs_path);
-#if defined(CONFIG_NET_MULTI)
- printf ("Using %s device\n", eth_get_name());
-#endif
+ printf("Using %s device\n", eth_get_name());
printf("File transfer via NFS from server %pI4"
"; our IP address is %pI4", &NfsServerIP, &NetOurIP);
@@ -727,19 +758,20 @@ NfsStart (void)
IPaddr_t ServerNet = NetServerIP & NetOurSubnetMask;
if (OurNet != ServerNet)
- printf("; sending through gateway %pI4", &NetOurGatewayIP);
+ printf("; sending through gateway %pI4",
+ &NetOurGatewayIP);
}
- printf ("\nFilename '%s/%s'.", nfs_path, nfs_filename);
+ printf("\nFilename '%s/%s'.", nfs_path, nfs_filename);
if (NetBootFileSize) {
- printf (" Size is 0x%x Bytes = ", NetBootFileSize<<9);
- print_size (NetBootFileSize<<9, "");
+ printf(" Size is 0x%x Bytes = ", NetBootFileSize<<9);
+ print_size(NetBootFileSize<<9, "");
}
- printf ("\nLoad address: 0x%lx\n"
+ printf("\nLoad address: 0x%lx\n"
"Loading: *\b", load_addr);
- NetSetTimeout (NFS_TIMEOUT, NfsTimeout);
- NetSetHandler (NfsHandler);
+ NetSetTimeout(nfs_timeout, NfsTimeout);
+ net_set_udp_handler(NfsHandler);
NfsTimeoutCount = 0;
NfsState = STATE_PRCLOOKUP_PROG_MOUNT_REQ;
@@ -749,7 +781,7 @@ NfsStart (void)
NfsOurPort = 1000;
/* zero out server ether in case the server ip has changed */
- memset (NetServerEther, 0, 6);
+ memset(NetServerEther, 0, 6);
- NfsSend ();
+ NfsSend();
}
diff --git a/net/nfs.h b/net/nfs.h
index de8a0c64c0..53451dbd17 100644
--- a/net/nfs.h
+++ b/net/nfs.h
@@ -1,10 +1,7 @@
/*
* (C) Masami Komiya <mkomiya@sonare.it> 2004
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __NFS_H__
@@ -72,7 +69,7 @@ struct rpc_t {
} reply;
} u;
};
-extern void NfsStart (void); /* Begin NFS */
+extern void NfsStart(void); /* Begin NFS */
/**********************************************************************/
diff --git a/net/ping.c b/net/ping.c
new file mode 100644
index 0000000000..0710b9228d
--- /dev/null
+++ b/net/ping.c
@@ -0,0 +1,115 @@
+/*
+ * Copied from Linux Monitor (LiMon) - Networking.
+ *
+ * Copyright 1994 - 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000 Roland Borde
+ * Copyright 2000 Paolo Scaffardi
+ * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
+ */
+
+#include "ping.h"
+#include "arp.h"
+
+static ushort PingSeqNo;
+
+/* The ip address to ping */
+IPaddr_t NetPingIP;
+
+static void set_icmp_header(uchar *pkt, IPaddr_t dest)
+{
+ /*
+ * Construct an IP and ICMP header.
+ */
+ struct ip_hdr *ip = (struct ip_hdr *)pkt;
+ struct icmp_hdr *icmp = (struct icmp_hdr *)(pkt + IP_HDR_SIZE);
+
+ net_set_ip_header(pkt, dest, NetOurIP);
+
+ ip->ip_len = htons(IP_ICMP_HDR_SIZE);
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE >> 1);
+
+ icmp->type = ICMP_ECHO_REQUEST;
+ icmp->code = 0;
+ icmp->checksum = 0;
+ icmp->un.echo.id = 0;
+ icmp->un.echo.sequence = htons(PingSeqNo++);
+ icmp->checksum = ~NetCksum((uchar *)icmp, ICMP_HDR_SIZE >> 1);
+}
+
+static int ping_send(void)
+{
+ uchar *pkt;
+ int eth_hdr_size;
+
+ /* XXX always send arp request */
+
+ debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &NetPingIP);
+
+ NetArpWaitPacketIP = NetPingIP;
+
+ eth_hdr_size = NetSetEther(NetTxPacket, NetEtherNullAddr, PROT_IP);
+ pkt = (uchar *)NetTxPacket + eth_hdr_size;
+
+ set_icmp_header(pkt, NetPingIP);
+
+ /* size of the waiting packet */
+ NetArpWaitTxPacketSize = eth_hdr_size + IP_ICMP_HDR_SIZE;
+
+ /* and do the ARP request */
+ NetArpWaitTry = 1;
+ NetArpWaitTimerStart = get_timer(0);
+ ArpRequest();
+ return 1; /* waiting */
+}
+
+static void ping_timeout(void)
+{
+ eth_halt();
+ net_set_state(NETLOOP_FAIL); /* we did not get the reply */
+}
+
+void ping_start(void)
+{
+ printf("Using %s device\n", eth_get_name());
+ NetSetTimeout(10000UL, ping_timeout);
+
+ ping_send();
+}
+
+void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
+{
+ struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
+ IPaddr_t src_ip;
+ int eth_hdr_size;
+
+ switch (icmph->type) {
+ case ICMP_ECHO_REPLY:
+ src_ip = NetReadIP((void *)&ip->ip_src);
+ if (src_ip == NetPingIP)
+ net_set_state(NETLOOP_SUCCESS);
+ return;
+ case ICMP_ECHO_REQUEST:
+ eth_hdr_size = net_update_ether(et, et->et_src, PROT_IP);
+
+ debug_cond(DEBUG_DEV_PKT, "Got ICMP ECHO REQUEST, return "
+ "%d bytes\n", eth_hdr_size + len);
+
+ ip->ip_sum = 0;
+ ip->ip_off = 0;
+ NetCopyIP((void *)&ip->ip_dst, &ip->ip_src);
+ NetCopyIP((void *)&ip->ip_src, &NetOurIP);
+ ip->ip_sum = ~NetCksum((uchar *)ip,
+ IP_HDR_SIZE >> 1);
+
+ icmph->type = ICMP_ECHO_REPLY;
+ icmph->checksum = 0;
+ icmph->checksum = ~NetCksum((uchar *)icmph,
+ (len - IP_HDR_SIZE) >> 1);
+ NetSendPacket((uchar *)et, eth_hdr_size + len);
+ return;
+/* default:
+ return;*/
+ }
+}
diff --git a/net/ping.h b/net/ping.h
new file mode 100644
index 0000000000..8c71be4fdf
--- /dev/null
+++ b/net/ping.h
@@ -0,0 +1,31 @@
+/*
+ * Copied from Linux Monitor (LiMon) - Networking.
+ *
+ * Copyright 1994 - 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000 Roland Borde
+ * Copyright 2000 Paolo Scaffardi
+ * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
+ */
+
+#ifndef __PING_H__
+#define __PING_H__
+
+#include <common.h>
+#include <net.h>
+
+/*
+ * Initialize ping (beginning of netloop)
+ */
+void ping_start(void);
+
+/*
+ * Deal with the receipt of a ping packet
+ *
+ * @param et Ethernet header in packet
+ * @param ip IP header in the same packet
+ * @param len Packet length
+ */
+void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len);
+
+#endif /* __PING_H__ */
diff --git a/net/rarp.c b/net/rarp.c
index 9444c03645..a8e085126d 100644
--- a/net/rarp.c
+++ b/net/rarp.c
@@ -2,23 +2,7 @@
* (C) Copyright 2000-2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
@@ -29,88 +13,88 @@
#include "rarp.h"
#include "tftp.h"
-#define TIMEOUT 5000UL /* Milliseconds before trying BOOTP again */
+#define TIMEOUT 5000UL /* Milliseconds before trying BOOTP again */
#ifndef CONFIG_NET_RETRY_COUNT
-# define TIMEOUT_COUNT 5 /* # of timeouts before giving up */
+#define TIMEOUT_COUNT 5 /* # of timeouts before giving up */
#else
-# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
+#define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
#endif
-
-int RarpTry;
+int RarpTry;
/*
* Handle a RARP received packet.
*/
-static void
-RarpHandler(uchar * dummi0, unsigned dummi1, unsigned dummi2, unsigned dummi3)
+void rarp_receive(struct ip_udp_hdr *ip, unsigned len)
{
- char *s;
- debug("Got good RARP\n");
- if ((s = getenv("autoload")) != NULL) {
- if (*s == 'n') {
- /*
- * Just use RARP to configure system;
- * Do not use TFTP/NFS to to load the bootfile.
- */
- NetState = NETLOOP_SUCCESS;
- return;
-#if defined(CONFIG_CMD_NFS)
- } else if ((s != NULL) && !strcmp(s, "NFS")) {
- NfsStart();
- return;
-#endif
- }
+ struct arp_hdr *arp;
+
+ debug_cond(DEBUG_NET_PKT, "Got RARP\n");
+ arp = (struct arp_hdr *)ip;
+ if (len < ARP_HDR_SIZE) {
+ printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
+ return;
+ }
+
+ if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
+ (ntohs(arp->ar_hrd) != ARP_ETHER) ||
+ (ntohs(arp->ar_pro) != PROT_IP) ||
+ (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
+
+ puts("invalid RARP header\n");
+ } else {
+ NetCopyIP(&NetOurIP, &arp->ar_data[16]);
+ if (NetServerIP == 0)
+ NetCopyIP(&NetServerIP, &arp->ar_data[6]);
+ memcpy(NetServerEther, &arp->ar_data[0], 6);
+ debug_cond(DEBUG_DEV_PKT, "Got good RARP\n");
+ net_auto_load();
}
- TftpStart ();
}
/*
* Timeout on BOOTP request.
*/
-static void
-RarpTimeout(void)
+static void RarpTimeout(void)
{
if (RarpTry >= TIMEOUT_COUNT) {
- puts ("\nRetry count exceeded; starting again\n");
- NetStartAgain ();
+ puts("\nRetry count exceeded; starting again\n");
+ NetStartAgain();
} else {
- NetSetTimeout (TIMEOUT, RarpTimeout);
- RarpRequest ();
+ NetSetTimeout(TIMEOUT, RarpTimeout);
+ RarpRequest();
}
}
-void
-RarpRequest (void)
+void RarpRequest(void)
{
- int i;
- volatile uchar *pkt;
- ARP_t * rarp;
+ uchar *pkt;
+ struct arp_hdr *rarp;
+ int eth_hdr_size;
printf("RARP broadcast %d\n", ++RarpTry);
pkt = NetTxPacket;
- pkt += NetSetEther(pkt, NetBcastAddr, PROT_RARP);
+ eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_RARP);
+ pkt += eth_hdr_size;
- rarp = (ARP_t *)pkt;
+ rarp = (struct arp_hdr *)pkt;
- rarp->ar_hrd = htons (ARP_ETHER);
- rarp->ar_pro = htons (PROT_IP);
+ rarp->ar_hrd = htons(ARP_ETHER);
+ rarp->ar_pro = htons(PROT_IP);
rarp->ar_hln = 6;
rarp->ar_pln = 4;
- rarp->ar_op = htons (RARPOP_REQUEST);
- memcpy (&rarp->ar_data[0], NetOurEther, 6); /* source ET addr */
- memcpy (&rarp->ar_data[6], &NetOurIP, 4); /* source IP addr */
- memcpy (&rarp->ar_data[10], NetOurEther, 6); /* dest ET addr = source ET addr ??*/
- /* dest. IP addr set to broadcast */
- for (i = 0; i <= 3; i++) {
- rarp->ar_data[16 + i] = 0xff;
- }
+ rarp->ar_op = htons(RARPOP_REQUEST);
+ memcpy(&rarp->ar_data[0], NetOurEther, 6); /* source ET addr */
+ memcpy(&rarp->ar_data[6], &NetOurIP, 4); /* source IP addr */
+ /* dest ET addr = source ET addr ??*/
+ memcpy(&rarp->ar_data[10], NetOurEther, 6);
+ /* dest IP addr set to broadcast */
+ memset(&rarp->ar_data[16], 0xff, 4);
- NetSendPacket(NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
+ NetSendPacket(NetTxPacket, eth_hdr_size + ARP_HDR_SIZE);
NetSetTimeout(TIMEOUT, RarpTimeout);
- NetSetHandler(RarpHandler);
}
diff --git a/net/rarp.h b/net/rarp.h
index 0c16d46668..93e18899c3 100644
--- a/net/rarp.h
+++ b/net/rarp.h
@@ -2,43 +2,28 @@
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
+#if defined(CONFIG_CMD_RARP)
#ifndef __RARP_H__
#define __RARP_H__
-#ifndef __NET_H__
#include <net.h>
-#endif /* __NET_H__ */
-
/**********************************************************************/
/*
* Global functions and variables.
*/
-extern int RarpTry;
+extern int RarpTry;
-extern void RarpRequest (void); /* Send a RARP request */
+/* Process the receipt of a RARP packet */
+extern void rarp_receive(struct ip_udp_hdr *ip, unsigned len);
+extern void RarpRequest(void); /* Send a RARP request */
/**********************************************************************/
#endif /* __RARP_H__ */
+#endif
diff --git a/net/sntp.c b/net/sntp.c
index 76c10ecd3b..5de19526e6 100644
--- a/net/sntp.c
+++ b/net/sntp.c
@@ -17,7 +17,7 @@
static int SntpOurPort;
static void
-SntpSend (void)
+SntpSend(void)
{
struct sntp_pkt_t pkt;
int pktlen = SNTP_PACKET_LEN;
@@ -25,30 +25,33 @@ SntpSend (void)
debug("%s\n", __func__);
- memset (&pkt, 0, sizeof(pkt));
+ memset(&pkt, 0, sizeof(pkt));
pkt.li = NTP_LI_NOLEAP;
pkt.vn = NTP_VERSION;
pkt.mode = NTP_MODE_CLIENT;
- memcpy ((char *)NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE, (char *)&pkt, pktlen);
+ memcpy((char *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE,
+ (char *)&pkt, pktlen);
SntpOurPort = 10000 + (get_timer(0) % 4096);
sport = NTP_SERVICE_PORT;
- NetSendUDPPacket (NetServerEther, NetNtpServerIP, sport, SntpOurPort, pktlen);
+ NetSendUDPPacket(NetServerEther, NetNtpServerIP, sport, SntpOurPort,
+ pktlen);
}
static void
-SntpTimeout (void)
+SntpTimeout(void)
{
- puts ("Timeout\n");
- NetState = NETLOOP_FAIL;
+ puts("Timeout\n");
+ net_set_state(NETLOOP_FAIL);
return;
}
static void
-SntpHandler (uchar *pkt, unsigned dest, unsigned src, unsigned len)
+SntpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+ unsigned len)
{
struct sntp_pkt_t *rpktp = (struct sntp_pkt_t *)pkt;
struct rtc_time tm;
@@ -56,33 +59,34 @@ SntpHandler (uchar *pkt, unsigned dest, unsigned src, unsigned len)
debug("%s\n", __func__);
- if (dest != SntpOurPort) return;
+ if (dest != SntpOurPort)
+ return;
/*
* As the RTC's used in U-Boot sepport second resolution only
* we simply ignore the sub-second field.
*/
- memcpy (&seconds, &rpktp->transmit_timestamp, sizeof(ulong));
+ memcpy(&seconds, &rpktp->transmit_timestamp, sizeof(ulong));
to_tm(ntohl(seconds) - 2208988800UL + NetTimeOffset, &tm);
#if defined(CONFIG_CMD_DATE)
- rtc_set (&tm);
+ rtc_set(&tm);
#endif
- printf ("Date: %4d-%02d-%02d Time: %2d:%02d:%02d\n",
+ printf("Date: %4d-%02d-%02d Time: %2d:%02d:%02d\n",
tm.tm_year, tm.tm_mon, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
- NetState = NETLOOP_SUCCESS;
+ net_set_state(NETLOOP_SUCCESS);
}
void
-SntpStart (void)
+SntpStart(void)
{
debug("%s\n", __func__);
- NetSetTimeout (SNTP_TIMEOUT, SntpTimeout);
- NetSetHandler(SntpHandler);
- memset (NetServerEther, 0, 6);
+ NetSetTimeout(SNTP_TIMEOUT, SntpTimeout);
+ net_set_udp_handler(SntpHandler);
+ memset(NetServerEther, 0, sizeof(NetServerEther));
- SntpSend ();
+ SntpSend();
}
diff --git a/net/sntp.h b/net/sntp.h
index 8a097bfa38..bf5bf0bb01 100644
--- a/net/sntp.h
+++ b/net/sntp.h
@@ -1,10 +1,7 @@
/*
* (C) Masami Komiya <mkomiya@sonare.it> 2005
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __SNTP_H__
@@ -56,6 +53,6 @@ struct sntp_pkt_t {
unsigned long long transmit_timestamp;
};
-extern void SntpStart (void); /* Begin SNTP */
+extern void SntpStart(void); /* Begin SNTP */
#endif /* __SNTP_H__ */
diff --git a/net/tftp.c b/net/tftp.c
index fbea4e06c6..6d333d559c 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -1,7 +1,9 @@
/*
- * Copyright 1994, 1995, 2000 Neil Russell.
- * (See License)
- * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ * Copyright 1994, 1995, 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ * Copyright 2011 Comelit Group SpA,
+ * Luca Ceresoli <luca.ceresoli@comelit.it>
*/
#include <common.h>
@@ -9,25 +11,22 @@
#include <net.h>
#include "tftp.h"
#include "bootp.h"
-
-#if defined(CONFIG_S5P6450)
-DECLARE_GLOBAL_DATA_PTR;
-#endif
-
-#define WELL_KNOWN_PORT 69 /* Well known TFTP port # */
-#ifndef CONFIG_TFTP_TIMEOUT
-#define TIMEOUT 5000UL /* Millisecs to timeout for lost pkt */
-#else
-#define TIMEOUT CONFIG_TFTP_TIMEOUT
+#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
+#include <flash.h>
#endif
+/* Well known TFTP port # */
+#define WELL_KNOWN_PORT 69
+/* Millisecs to timeout for lost pkt */
+#define TIMEOUT 5000UL
#ifndef CONFIG_NET_RETRY_COUNT
-# define TIMEOUT_COUNT 10 /* # of timeouts before giving up */
+/* # of timeouts before giving up */
+# define TIMEOUT_COUNT 10
#else
# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2)
#endif
- /* (for checking the image size) */
-#define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */
+/* Number of "loading" hashes per line (for checking the image size) */
+#define HASHES_PER_LINE 65
/*
* TFTP operations.
@@ -41,6 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
static ulong TftpTimeoutMSecs = TIMEOUT;
static int TftpTimeoutCountMax = TIMEOUT_COUNT;
+static ulong time_start; /* Record time we started tftp */
/*
* These globals govern the timeout behavior when attempting a connection to a
@@ -64,28 +64,46 @@ enum {
TFTP_ERR_FILE_ALREADY_EXISTS = 6,
};
-static IPaddr_t TftpServerIP;
-static int TftpServerPort; /* The UDP port at their end */
-static int TftpOurPort; /* The UDP port at our end */
+static IPaddr_t TftpRemoteIP;
+/* The UDP port at their end */
+static int TftpRemotePort;
+/* The UDP port at our end */
+static int TftpOurPort;
static int TftpTimeoutCount;
-static ulong TftpBlock; /* packet sequence number */
-static ulong TftpLastBlock; /* last packet sequence number received */
-static ulong TftpBlockWrap; /* count of sequence number wraparounds */
-static ulong TftpBlockWrapOffset; /* memory offset due to wrapping */
+/* packet sequence number */
+static ulong TftpBlock;
+/* last packet sequence number received */
+static ulong TftpLastBlock;
+/* count of sequence number wraparounds */
+static ulong TftpBlockWrap;
+/* memory offset due to wrapping */
+static ulong TftpBlockWrapOffset;
static int TftpState;
#ifdef CONFIG_TFTP_TSIZE
-static int TftpTsize; /* The file size reported by the server */
-static short TftpNumchars; /* The number of hashes we printed */
+/* The file size reported by the server */
+static int TftpTsize;
+/* The number of hashes we printed */
+static short TftpNumchars;
+#endif
+#ifdef CONFIG_CMD_TFTPPUT
+static int TftpWriting; /* 1 if writing, else 0 */
+static int TftpFinalBlock; /* 1 if we have sent the last block */
+#else
+#define TftpWriting 0
#endif
-#define STATE_RRQ 1
+#define STATE_SEND_RRQ 1
#define STATE_DATA 2
#define STATE_TOO_LARGE 3
#define STATE_BAD_MAGIC 4
#define STATE_OACK 5
+#define STATE_RECV_WRQ 6
+#define STATE_SEND_WRQ 7
-#define TFTP_BLOCK_SIZE 512 /* default TFTP block size */
-#define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) /* sequence number is 16 bit */
+/* default TFTP block size */
+#define TFTP_BLOCK_SIZE 512
+/* sequence number is 16 bit */
+#define TFTP_SEQUENCE_SIZE ((ulong)(1<<16))
#define DEFAULT_NAME_LEN (8 + 4 + 1)
static char default_filename[DEFAULT_NAME_LEN];
@@ -98,10 +116,6 @@ static char default_filename[DEFAULT_NAME_LEN];
static char tftp_filename[MAX_LEN];
-#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
-extern flash_info_t flash_info[];
-#endif
-
/* 512 is poor choice for ethernet, MTU is typically 1500.
* Minus eth.hdrs thats 1468. Can get 2x better throughput with
* almost-MTU block sizes. At least try... fall back to 512 if need be.
@@ -113,43 +127,44 @@ extern flash_info_t flash_info[];
#define TFTP_MTU_BLOCKSIZE 1468
#endif
-static unsigned short TftpBlkSize=TFTP_BLOCK_SIZE;
-static unsigned short TftpBlkSizeOption=TFTP_MTU_BLOCKSIZE;
+static unsigned short TftpBlkSize = TFTP_BLOCK_SIZE;
+static unsigned short TftpBlkSizeOption = TFTP_MTU_BLOCKSIZE;
#ifdef CONFIG_MCAST_TFTP
#include <malloc.h>
#define MTFTP_BITMAPSIZE 0x1000
static unsigned *Bitmap;
-static int PrevBitmapHole,Mapsize=MTFTP_BITMAPSIZE;
-static uchar ProhibitMcast=0, MasterClient=0;
-static uchar Multicast=0;
-extern IPaddr_t Mcast_addr;
+static int PrevBitmapHole, Mapsize = MTFTP_BITMAPSIZE;
+static uchar ProhibitMcast, MasterClient;
+static uchar Multicast;
static int Mcast_port;
static ulong TftpEndingBlock; /* can get 'last' block before done..*/
-static void parse_multicast_oack(char *pkt,int len);
+static void parse_multicast_oack(char *pkt, int len);
static void
mcast_cleanup(void)
{
- if (Mcast_addr) eth_mcast_join(Mcast_addr, 0);
- if (Bitmap) free(Bitmap);
- Bitmap=NULL;
+ if (Mcast_addr)
+ eth_mcast_join(Mcast_addr, 0);
+ if (Bitmap)
+ free(Bitmap);
+ Bitmap = NULL;
Mcast_addr = Multicast = Mcast_port = 0;
TftpEndingBlock = -1;
}
#endif /* CONFIG_MCAST_TFTP */
-static __inline__ void
-store_block (unsigned block, uchar * src, unsigned len)
+static inline void
+store_block(int block, uchar *src, unsigned len)
{
ulong offset = block * TftpBlkSize + TftpBlockWrapOffset;
ulong newsize = offset + len;
#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
int i, rc = 0;
- for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; i++) {
+ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
/* start address in flash? */
if (flash_info[i].flash_id == FLASH_UNKNOWN)
continue;
@@ -160,14 +175,13 @@ store_block (unsigned block, uchar * src, unsigned len)
}
if (rc) { /* Flash is destination for this packet */
- rc = flash_write ((char *)src, (ulong)(load_addr+offset), len);
+ rc = flash_write((char *)src, (ulong)(load_addr+offset), len);
if (rc) {
- flash_perror (rc);
- NetState = NETLOOP_FAIL;
+ flash_perror(rc);
+ net_set_state(NETLOOP_FAIL);
return;
}
- }
- else
+ } else
#endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */
{
(void)memcpy((void *)(load_addr + offset), src, len);
@@ -181,18 +195,128 @@ store_block (unsigned block, uchar * src, unsigned len)
NetBootFileXferSize = newsize;
}
-static void TftpSend (void);
-static void TftpTimeout (void);
+/* Clear our state ready for a new transfer */
+static void new_transfer(void)
+{
+ TftpLastBlock = 0;
+ TftpBlockWrap = 0;
+ TftpBlockWrapOffset = 0;
+#ifdef CONFIG_CMD_TFTPPUT
+ TftpFinalBlock = 0;
+#endif
+}
+
+#ifdef CONFIG_CMD_TFTPPUT
+/**
+ * Load the next block from memory to be sent over tftp.
+ *
+ * @param block Block number to send
+ * @param dst Destination buffer for data
+ * @param len Number of bytes in block (this one and every other)
+ * @return number of bytes loaded
+ */
+static int load_block(unsigned block, uchar *dst, unsigned len)
+{
+ /* We may want to get the final block from the previous set */
+ ulong offset = ((int)block - 1) * len + TftpBlockWrapOffset;
+ ulong tosend = len;
+
+ tosend = min(NetBootFileXferSize - offset, tosend);
+ (void)memcpy(dst, (void *)(save_addr + offset), tosend);
+ debug("%s: block=%d, offset=%ld, len=%d, tosend=%ld\n", __func__,
+ block, offset, len, tosend);
+ return tosend;
+}
+#endif
+
+static void TftpSend(void);
+static void TftpTimeout(void);
/**********************************************************************/
+static void show_block_marker(void)
+{
+#ifdef CONFIG_TFTP_TSIZE
+ if (TftpTsize) {
+ ulong pos = TftpBlock * TftpBlkSize + TftpBlockWrapOffset;
+
+ while (TftpNumchars < pos * 50 / TftpTsize) {
+ putc('#');
+ TftpNumchars++;
+ }
+ } else
+#endif
+ {
+ if (((TftpBlock - 1) % 10) == 0)
+ putc('#');
+ else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0)
+ puts("\n\t ");
+ }
+}
+
+/**
+ * restart the current transfer due to an error
+ *
+ * @param msg Message to print for user
+ */
+static void restart(const char *msg)
+{
+ printf("\n%s; starting again\n", msg);
+#ifdef CONFIG_MCAST_TFTP
+ mcast_cleanup();
+#endif
+ NetStartAgain();
+}
+
+/*
+ * Check if the block number has wrapped, and update progress
+ *
+ * TODO: The egregious use of global variables in this file should be tidied.
+ */
+static void update_block_number(void)
+{
+ /*
+ * RFC1350 specifies that the first data packet will
+ * have sequence number 1. If we receive a sequence
+ * number of 0 this means that there was a wrap
+ * around of the (16 bit) counter.
+ */
+ if (TftpBlock == 0) {
+ TftpBlockWrap++;
+ TftpBlockWrapOffset += TftpBlkSize * TFTP_SEQUENCE_SIZE;
+ TftpTimeoutCount = 0; /* we've done well, reset thhe timeout */
+ } else {
+ show_block_marker();
+ }
+}
+
+/* The TFTP get or put is complete */
+static void tftp_complete(void)
+{
+#ifdef CONFIG_TFTP_TSIZE
+ /* Print hash marks for the last packet received */
+ while (TftpTsize && TftpNumchars < 49) {
+ putc('#');
+ TftpNumchars++;
+ }
+#endif
+ time_start = get_timer(time_start);
+ if (time_start > 0) {
+ puts("\n\t "); /* Line up with "Loading: " */
+ print_size(NetBootFileXferSize /
+ time_start * 1000, "/s");
+ }
+ puts("\ndone\n");
+ net_set_state(NETLOOP_SUCCESS);
+}
+
static void
-TftpSend (void)
+TftpSend(void)
{
- volatile uchar * pkt;
- volatile uchar * xp;
- int len = 0;
- volatile ushort *s;
+ uchar *pkt;
+ uchar *xp;
+ int len = 0;
+ ushort *s;
#ifdef CONFIG_MCAST_TFTP
/* Multicast TFTP.. non-MasterClients do not ACK data. */
@@ -205,39 +329,46 @@ TftpSend (void)
* We will always be sending some sort of packet, so
* cobble together the packet headers now.
*/
- pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
+ pkt = NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
switch (TftpState) {
-
- case STATE_RRQ:
+ case STATE_SEND_RRQ:
+ case STATE_SEND_WRQ:
xp = pkt;
s = (ushort *)pkt;
+#ifdef CONFIG_CMD_TFTPPUT
+ *s++ = htons(TftpState == STATE_SEND_RRQ ? TFTP_RRQ :
+ TFTP_WRQ);
+#else
*s++ = htons(TFTP_RRQ);
+#endif
pkt = (uchar *)s;
- strcpy ((char *)pkt, tftp_filename);
+ strcpy((char *)pkt, tftp_filename);
pkt += strlen(tftp_filename) + 1;
- strcpy ((char *)pkt, "octet");
+ strcpy((char *)pkt, "octet");
pkt += 5 /*strlen("octet")*/ + 1;
- strcpy ((char *)pkt, "timeout");
+ strcpy((char *)pkt, "timeout");
pkt += 7 /*strlen("timeout")*/ + 1;
sprintf((char *)pkt, "%lu", TftpTimeoutMSecs / 1000);
debug("send option \"timeout %s\"\n", (char *)pkt);
pkt += strlen((char *)pkt) + 1;
#ifdef CONFIG_TFTP_TSIZE
- memcpy((char *)pkt, "tsize\0000\0", 8);
- pkt += 8;
+ pkt += sprintf((char *)pkt, "tsize%c%lu%c",
+ 0, NetBootFileXferSize, 0);
#endif
/* try for more effic. blk size */
- pkt += sprintf((char *)pkt,"blksize%c%d%c",
- 0,TftpBlkSizeOption,0);
+ pkt += sprintf((char *)pkt, "blksize%c%d%c",
+ 0, TftpBlkSizeOption, 0);
#ifdef CONFIG_MCAST_TFTP
/* Check all preconditions before even trying the option */
- if (!ProhibitMcast
- && (Bitmap=malloc(Mapsize))
- && eth_get_dev()->mcast) {
- free(Bitmap);
- Bitmap=NULL;
- pkt += sprintf((char *)pkt,"multicast%c%c",0,0);
+ if (!ProhibitMcast) {
+ Bitmap = malloc(Mapsize);
+ if (Bitmap && eth_get_dev()->mcast) {
+ free(Bitmap);
+ Bitmap = NULL;
+ pkt += sprintf((char *)pkt, "multicast%c%c",
+ 0, 0);
+ }
}
#endif /* CONFIG_MCAST_TFTP */
len = pkt - xp;
@@ -247,15 +378,28 @@ TftpSend (void)
#ifdef CONFIG_MCAST_TFTP
/* My turn! Start at where I need blocks I missed.*/
if (Multicast)
- TftpBlock=ext2_find_next_zero_bit(Bitmap,(Mapsize*8),0);
+ TftpBlock = ext2_find_next_zero_bit(Bitmap,
+ (Mapsize*8), 0);
/*..falling..*/
#endif
+
+ case STATE_RECV_WRQ:
case STATE_DATA:
xp = pkt;
s = (ushort *)pkt;
- *s++ = htons(TFTP_ACK);
- *s++ = htons(TftpBlock);
- pkt = (uchar *)s;
+ s[0] = htons(TFTP_ACK);
+ s[1] = htons(TftpBlock);
+ pkt = (uchar *)(s + 2);
+#ifdef CONFIG_CMD_TFTPPUT
+ if (TftpWriting) {
+ int toload = TftpBlkSize;
+ int loaded = load_block(TftpBlock, pkt, toload);
+
+ s[0] = htons(TFTP_DATA);
+ pkt += loaded;
+ TftpFinalBlock = (loaded < toload);
+ }
+#endif
len = pkt - xp;
break;
@@ -263,9 +407,10 @@ TftpSend (void)
xp = pkt;
s = (ushort *)pkt;
*s++ = htons(TFTP_ERROR);
- *s++ = htons(3);
+ *s++ = htons(3);
+
pkt = (uchar *)s;
- strcpy ((char *)pkt, "File too large");
+ strcpy((char *)pkt, "File too large");
pkt += 14 /*strlen("File too large")*/ + 1;
len = pkt - xp;
break;
@@ -276,21 +421,33 @@ TftpSend (void)
*s++ = htons(TFTP_ERROR);
*s++ = htons(2);
pkt = (uchar *)s;
- strcpy ((char *)pkt, "File has bad magic");
+ strcpy((char *)pkt, "File has bad magic");
pkt += 18 /*strlen("File has bad magic")*/ + 1;
len = pkt - xp;
break;
}
- NetSendUDPPacket(NetServerEther, TftpServerIP, TftpServerPort, TftpOurPort, len);
+ NetSendUDPPacket(NetServerEther, TftpRemoteIP, TftpRemotePort,
+ TftpOurPort, len);
}
+#ifdef CONFIG_CMD_TFTPPUT
+static void icmp_handler(unsigned type, unsigned code, unsigned dest,
+ IPaddr_t sip, unsigned src, uchar *pkt, unsigned len)
+{
+ if (type == ICMP_NOT_REACH && code == ICMP_NOT_REACH_PORT) {
+ /* Oh dear the other end has gone away */
+ restart("TFTP server died");
+ }
+}
+#endif
static void
-TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+ unsigned len)
{
- ushort proto;
- ushort *s;
+ __be16 proto;
+ __be16 *s;
int i;
if (dest != TftpOurPort) {
@@ -298,106 +455,120 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
if (Multicast
&& (!Mcast_port || (dest != Mcast_port)))
#endif
- return;
+ return;
}
- if (TftpState != STATE_RRQ && src != TftpServerPort) {
+ if (TftpState != STATE_SEND_RRQ && src != TftpRemotePort &&
+ TftpState != STATE_RECV_WRQ && TftpState != STATE_SEND_WRQ)
return;
- }
- if (len < 2) {
+ if (len < 2)
return;
- }
len -= 2;
/* warning: don't use increment (++) in ntohs() macros!! */
- s = (ushort *)pkt;
+ s = (__be16 *)pkt;
proto = *s++;
pkt = (uchar *)s;
switch (ntohs(proto)) {
case TFTP_RRQ:
- case TFTP_WRQ:
+ break;
+
case TFTP_ACK:
+#ifdef CONFIG_CMD_TFTPPUT
+ if (TftpWriting) {
+ if (TftpFinalBlock) {
+ tftp_complete();
+ } else {
+ /*
+ * Move to the next block. We want our block
+ * count to wrap just like the other end!
+ */
+ int block = ntohs(*s);
+ int ack_ok = (TftpBlock == block);
+
+ TftpBlock = (unsigned short)(block + 1);
+ update_block_number();
+ if (ack_ok)
+ TftpSend(); /* Send next data block */
+ }
+ }
+#endif
break;
+
default:
break;
+#ifdef CONFIG_CMD_TFTPSRV
+ case TFTP_WRQ:
+ debug("Got WRQ\n");
+ TftpRemoteIP = sip;
+ TftpRemotePort = src;
+ TftpOurPort = 1024 + (get_timer(0) % 3072);
+ new_transfer();
+ TftpSend(); /* Send ACK(0) */
+ break;
+#endif
+
case TFTP_OACK:
debug("Got OACK: %s %s\n",
pkt,
pkt + strlen((char *)pkt) + 1);
TftpState = STATE_OACK;
- TftpServerPort = src;
+ TftpRemotePort = src;
/*
* Check for 'blksize' option.
* Careful: "i" is signed, "len" is unsigned, thus
* something like "len-8" may give a *huge* number
*/
- for (i=0; i+8<len; i++) {
- if (strcmp ((char*)pkt+i,"blksize") == 0) {
+ for (i = 0; i+8 < len; i++) {
+ if (strcmp((char *)pkt+i, "blksize") == 0) {
TftpBlkSize = (unsigned short)
- simple_strtoul((char*)pkt+i+8,NULL,10);
+ simple_strtoul((char *)pkt+i+8, NULL,
+ 10);
debug("Blocksize ack: %s, %d\n",
- (char*)pkt+i+8,TftpBlkSize);
+ (char *)pkt+i+8, TftpBlkSize);
}
#ifdef CONFIG_TFTP_TSIZE
- if (strcmp ((char*)pkt+i,"tsize") == 0) {
- TftpTsize = simple_strtoul((char*)pkt+i+6,NULL,10);
+ if (strcmp((char *)pkt+i, "tsize") == 0) {
+ TftpTsize = simple_strtoul((char *)pkt+i+6,
+ NULL, 10);
debug("size = %s, %d\n",
- (char*)pkt+i+6, TftpTsize);
+ (char *)pkt+i+6, TftpTsize);
}
#endif
}
#ifdef CONFIG_MCAST_TFTP
- parse_multicast_oack((char *)pkt,len-1);
+ parse_multicast_oack((char *)pkt, len-1);
if ((Multicast) && (!MasterClient))
TftpState = STATE_DATA; /* passive.. */
else
#endif
- TftpSend (); /* Send ACK */
+#ifdef CONFIG_CMD_TFTPPUT
+ if (TftpWriting) {
+ /* Get ready to send the first block */
+ TftpState = STATE_DATA;
+ TftpBlock++;
+ }
+#endif
+ TftpSend(); /* Send ACK or first data block */
break;
case TFTP_DATA:
if (len < 2)
return;
len -= 2;
- TftpBlock = ntohs(*(ushort *)pkt);
+ TftpBlock = ntohs(*(__be16 *)pkt);
- /*
- * RFC1350 specifies that the first data packet will
- * have sequence number 1. If we receive a sequence
- * number of 0 this means that there was a wrap
- * around of the (16 bit) counter.
- */
- if (TftpBlock == 0) {
- TftpBlockWrap++;
- TftpBlockWrapOffset += TftpBlkSize * TFTP_SEQUENCE_SIZE;
- printf ("\n\t %lu MB received\n\t ", TftpBlockWrapOffset>>20);
- }
-#ifdef CONFIG_TFTP_TSIZE
- else if (TftpTsize) {
- while (TftpNumchars < NetBootFileXferSize * 50 / TftpTsize) {
- putc('#');
- TftpNumchars++;
- }
- }
-#endif
- else {
- if (((TftpBlock - 1) % 10) == 0) {
- putc ('#');
- } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
- puts ("\n\t ");
- }
- }
+ update_block_number();
- if (TftpState == STATE_RRQ)
+ if (TftpState == STATE_SEND_RRQ)
debug("Server did not acknowledge timeout option!\n");
- if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
+ if (TftpState == STATE_SEND_RRQ || TftpState == STATE_OACK ||
+ TftpState == STATE_RECV_WRQ) {
/* first block received */
TftpState = STATE_DATA;
- TftpServerPort = src;
- TftpLastBlock = 0;
- TftpBlockWrap = 0;
- TftpBlockWrapOffset = 0;
+ TftpRemotePort = src;
+ new_transfer();
#ifdef CONFIG_MCAST_TFTP
if (Multicast) { /* start!=1 common if mcast */
@@ -405,11 +576,11 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
} else
#endif
if (TftpBlock != 1) { /* Assertion */
- printf ("\nTFTP error: "
- "First block is not block 1 (%ld)\n"
- "Starting again\n\n",
+ printf("\nTFTP error: "
+ "First block is not block 1 (%ld)\n"
+ "Starting again\n\n",
TftpBlock);
- NetStartAgain ();
+ NetStartAgain();
break;
}
}
@@ -423,13 +594,13 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
TftpLastBlock = TftpBlock;
TftpTimeoutCountMax = TIMEOUT_COUNT;
- NetSetTimeout (TftpTimeoutMSecs, TftpTimeout);
+ NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
- store_block (TftpBlock - 1, pkt + 2, len);
+ store_block(TftpBlock - 1, pkt + 2, len);
/*
- * Acknoledge the block just received, which will prompt
- * the server for the next one.
+ * Acknowledge the block just received, which will prompt
+ * the remote for the next one.
*/
#ifdef CONFIG_MCAST_TFTP
/* if I am the MasterClient, actively calculate what my next
@@ -445,56 +616,42 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
(Mapsize*8),
PrevBitmapHole);
if (TftpBlock > ((Mapsize*8) - 1)) {
- printf ("tftpfile too big\n");
+ printf("tftpfile too big\n");
/* try to double it and retry */
- Mapsize<<=1;
+ Mapsize <<= 1;
mcast_cleanup();
- NetStartAgain ();
+ NetStartAgain();
return;
}
TftpLastBlock = TftpBlock;
}
}
#endif
- TftpSend ();
+ TftpSend();
#ifdef CONFIG_MCAST_TFTP
if (Multicast) {
if (MasterClient && (TftpBlock >= TftpEndingBlock)) {
- puts ("\nMulticast tftp done\n");
+ puts("\nMulticast tftp done\n");
mcast_cleanup();
- NetState = NETLOOP_SUCCESS;
- }
- }
- else
-#endif
- if (len < TftpBlkSize) {
- /*
- * We received the whole thing. Try to
- * run it.
- */
-#ifdef CONFIG_TFTP_TSIZE
- /* Print out the hash marks for the last packet received */
- while (TftpTsize && TftpNumchars < 49) {
- putc('#');
- TftpNumchars++;
+ net_set_state(NETLOOP_SUCCESS);
}
+ } else
#endif
- puts ("\ndone\n");
- NetState = NETLOOP_SUCCESS;
- }
+ if (len < TftpBlkSize)
+ tftp_complete();
break;
case TFTP_ERROR:
- printf ("\nTFTP error: '%s' (%d)\n",
- pkt + 2, ntohs(*(ushort *)pkt));
+ printf("\nTFTP error: '%s' (%d)\n",
+ pkt + 2, ntohs(*(__be16 *)pkt));
- switch (ntohs(*(ushort *)pkt)) {
+ switch (ntohs(*(__be16 *)pkt)) {
case TFTP_ERR_FILE_NOT_FOUND:
case TFTP_ERR_ACCESS_DENIED:
puts("Not retrying...\n");
eth_halt();
- NetState = NETLOOP_FAIL;
+ net_set_state(NETLOOP_FAIL);
break;
case TFTP_ERR_UNDEFINED:
case TFTP_ERR_DISK_FULL:
@@ -515,24 +672,20 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
static void
-TftpTimeout (void)
+TftpTimeout(void)
{
if (++TftpTimeoutCount > TftpTimeoutCountMax) {
- puts ("\nRetry count exceeded; starting again\n");
-#ifdef CONFIG_MCAST_TFTP
- mcast_cleanup();
-#endif
- NetStartAgain ();
+ restart("Retry count exceeded");
} else {
- puts ("T ");
- NetSetTimeout (TftpTimeoutMSecs, TftpTimeout);
- TftpSend ();
+ puts("T ");
+ NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
+ if (TftpState != STATE_RECV_WRQ)
+ TftpSend();
}
}
-void
-TftpStart (void)
+void TftpStart(enum proto_t protocol)
{
char *ep; /* Environment pointer */
@@ -540,10 +693,12 @@ TftpStart (void)
* Allow the user to choose TFTP blocksize and timeout.
* TFTP protocol has a minimal timeout of 1 second.
*/
- if ((ep = getenv("tftpblocksize")) != NULL)
+ ep = getenv("tftpblocksize");
+ if (ep != NULL)
TftpBlkSizeOption = simple_strtol(ep, NULL, 10);
- if ((ep = getenv("tftptimeout")) != NULL)
+ ep = getenv("tftptimeout");
+ if (ep != NULL)
TftpTimeoutMSecs = simple_strtol(ep, NULL, 10);
if (TftpTimeoutMSecs < 1000) {
@@ -556,79 +711,97 @@ TftpStart (void)
debug("TFTP blocksize = %i, timeout = %ld ms\n",
TftpBlkSizeOption, TftpTimeoutMSecs);
- TftpServerIP = NetServerIP;
+ TftpRemoteIP = NetServerIP;
if (BootFile[0] == '\0') {
- sprintf(default_filename, "%02lX%02lX%02lX%02lX.img",
+ sprintf(default_filename, "%02X%02X%02X%02X.img",
NetOurIP & 0xFF,
(NetOurIP >> 8) & 0xFF,
(NetOurIP >> 16) & 0xFF,
- (NetOurIP >> 24) & 0xFF );
+ (NetOurIP >> 24) & 0xFF);
strncpy(tftp_filename, default_filename, MAX_LEN);
tftp_filename[MAX_LEN-1] = 0;
- printf ("*** Warning: no boot file name; using '%s'\n",
+ printf("*** Warning: no boot file name; using '%s'\n",
tftp_filename);
} else {
- char *p = strchr (BootFile, ':');
+ char *p = strchr(BootFile, ':');
if (p == NULL) {
strncpy(tftp_filename, BootFile, MAX_LEN);
tftp_filename[MAX_LEN-1] = 0;
} else {
- TftpServerIP = string_to_ip (BootFile);
+ TftpRemoteIP = string_to_ip(BootFile);
strncpy(tftp_filename, p + 1, MAX_LEN);
tftp_filename[MAX_LEN-1] = 0;
}
}
-#if defined(CONFIG_NET_MULTI)
- printf ("Using %s device\n", eth_get_name());
+ printf("Using %s device\n", eth_get_name());
+ printf("TFTP %s server %pI4; our IP address is %pI4",
+#ifdef CONFIG_CMD_TFTPPUT
+ protocol == TFTPPUT ? "to" : "from",
+#else
+ "from",
#endif
- printf("TFTP from server %pI4"
- "; our IP address is %pI4", &TftpServerIP, &NetOurIP);
+ &TftpRemoteIP, &NetOurIP);
/* Check if we need to send across this subnet */
if (NetOurGatewayIP && NetOurSubnetMask) {
- IPaddr_t OurNet = NetOurIP & NetOurSubnetMask;
- IPaddr_t ServerNet = TftpServerIP & NetOurSubnetMask;
+ IPaddr_t OurNet = NetOurIP & NetOurSubnetMask;
+ IPaddr_t RemoteNet = TftpRemoteIP & NetOurSubnetMask;
- if (OurNet != ServerNet)
- printf("; sending through gateway %pI4", &NetOurGatewayIP);
+ if (OurNet != RemoteNet)
+ printf("; sending through gateway %pI4",
+ &NetOurGatewayIP);
}
- putc ('\n');
+ putc('\n');
- printf ("Filename '%s'.", tftp_filename);
+ printf("Filename '%s'.", tftp_filename);
if (NetBootFileSize) {
- printf (" Size is 0x%x Bytes = ", NetBootFileSize<<9);
- print_size (NetBootFileSize<<9, "");
+ printf(" Size is 0x%x Bytes = ", NetBootFileSize<<9);
+ print_size(NetBootFileSize<<9, "");
}
- putc ('\n');
-
- printf ("Load address: 0x%lx\n", load_addr);
-
- puts ("Loading: *\b");
+ putc('\n');
+#ifdef CONFIG_CMD_TFTPPUT
+ TftpWriting = (protocol == TFTPPUT);
+ if (TftpWriting) {
+ printf("Save address: 0x%lx\n", save_addr);
+ printf("Save size: 0x%lx\n", save_size);
+ NetBootFileXferSize = save_size;
+ puts("Saving: *\b");
+ TftpState = STATE_SEND_WRQ;
+ new_transfer();
+ } else
+#endif
+ {
+ printf("Load address: 0x%lx\n", load_addr);
+ puts("Loading: *\b");
+ TftpState = STATE_SEND_RRQ;
+ }
+ time_start = get_timer(0);
TftpTimeoutCountMax = TftpRRQTimeoutCountMax;
- NetSetTimeout (TftpTimeoutMSecs, TftpTimeout);
- NetSetHandler (TftpHandler);
-
- TftpServerPort = WELL_KNOWN_PORT;
+ NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
+ net_set_udp_handler(TftpHandler);
+#ifdef CONFIG_CMD_TFTPPUT
+ net_set_icmp_handler(icmp_handler);
+#endif
+ TftpRemotePort = WELL_KNOWN_PORT;
TftpTimeoutCount = 0;
- TftpState = STATE_RRQ;
/* Use a pseudo-random port unless a specific port is set */
TftpOurPort = 1024 + (get_timer(0) % 3072);
#ifdef CONFIG_TFTP_PORT
- if ((ep = getenv("tftpdstp")) != NULL) {
- TftpServerPort = simple_strtol(ep, NULL, 10);
- }
- if ((ep = getenv("tftpsrcp")) != NULL) {
- TftpOurPort= simple_strtol(ep, NULL, 10);
- }
+ ep = getenv("tftpdstp");
+ if (ep != NULL)
+ TftpRemotePort = simple_strtol(ep, NULL, 10);
+ ep = getenv("tftpsrcp");
+ if (ep != NULL)
+ TftpOurPort = simple_strtol(ep, NULL, 10);
#endif
TftpBlock = 0;
@@ -644,8 +817,40 @@ TftpStart (void)
TftpNumchars = 0;
#endif
- TftpSend ();
+ TftpSend();
+}
+
+#ifdef CONFIG_CMD_TFTPSRV
+void
+TftpStartServer(void)
+{
+ tftp_filename[0] = 0;
+
+ printf("Using %s device\n", eth_get_name());
+ printf("Listening for TFTP transfer on %pI4\n", &NetOurIP);
+ printf("Load address: 0x%lx\n", load_addr);
+
+ puts("Loading: *\b");
+
+ TftpTimeoutCountMax = TIMEOUT_COUNT;
+ TftpTimeoutCount = 0;
+ TftpTimeoutMSecs = TIMEOUT;
+ NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
+
+ /* Revert TftpBlkSize to dflt */
+ TftpBlkSize = TFTP_BLOCK_SIZE;
+ TftpBlock = 0;
+ TftpOurPort = WELL_KNOWN_PORT;
+
+#ifdef CONFIG_TFTP_TSIZE
+ TftpTsize = 0;
+ TftpNumchars = 0;
+#endif
+
+ TftpState = STATE_RECV_WRQ;
+ net_set_udp_handler(TftpHandler);
}
+#endif /* CONFIG_CMD_TFTPSRV */
#ifdef CONFIG_MCAST_TFTP
/* Credits: atftp project.
@@ -665,23 +870,23 @@ TftpStart (void)
*/
static void parse_multicast_oack(char *pkt, int len)
{
- int i;
- IPaddr_t addr;
- char *mc_adr, *port, *mc;
+ int i;
+ IPaddr_t addr;
+ char *mc_adr, *port, *mc;
- mc_adr=port=mc=NULL;
+ mc_adr = port = mc = NULL;
/* march along looking for 'multicast\0', which has to start at least
* 14 bytes back from the end.
*/
- for (i=0;i<len-14;i++)
- if (strcmp (pkt+i,"multicast") == 0)
+ for (i = 0; i < len-14; i++)
+ if (strcmp(pkt+i, "multicast") == 0)
break;
if (i >= (len-14)) /* non-Multicast OACK, ign. */
return;
- i+=10; /* strlen multicast */
+ i += 10; /* strlen multicast */
mc_adr = pkt+i;
- for (;i<len;i++) {
+ for (; i < len; i++) {
if (*(pkt+i) == ',') {
*(pkt+i) = '\0';
if (port) {
@@ -692,29 +897,31 @@ static void parse_multicast_oack(char *pkt, int len)
}
}
}
- if (!port || !mc_adr || !mc ) return;
+ if (!port || !mc_adr || !mc)
+ return;
if (Multicast && MasterClient) {
- printf ("I got a OACK as master Client, WRONG!\n");
+ printf("I got a OACK as master Client, WRONG!\n");
return;
}
/* ..I now accept packets destined for this MCAST addr, port */
if (!Multicast) {
if (Bitmap) {
- printf ("Internal failure! no mcast.\n");
+ printf("Internal failure! no mcast.\n");
free(Bitmap);
- Bitmap=NULL;
- ProhibitMcast=1;
+ Bitmap = NULL;
+ ProhibitMcast = 1;
return ;
}
/* I malloc instead of pre-declare; so that if the file ends
* up being too big for this bitmap I can retry
*/
- if (!(Bitmap = malloc (Mapsize))) {
- printf ("No Bitmap, no multicast. Sorry.\n");
- ProhibitMcast=1;
+ Bitmap = malloc(Mapsize);
+ if (!Bitmap) {
+ printf("No Bitmap, no multicast. Sorry.\n");
+ ProhibitMcast = 1;
return;
}
- memset (Bitmap,0,Mapsize);
+ memset(Bitmap, 0, Mapsize);
PrevBitmapHole = 0;
Multicast = 1;
}
@@ -722,16 +929,17 @@ static void parse_multicast_oack(char *pkt, int len)
if (Mcast_addr != addr) {
if (Mcast_addr)
eth_mcast_join(Mcast_addr, 0);
- if (eth_mcast_join(Mcast_addr=addr, 1)) {
- printf ("Fail to set mcast, revert to TFTP\n");
- ProhibitMcast=1;
+ Mcast_addr = addr;
+ if (eth_mcast_join(Mcast_addr, 1)) {
+ printf("Fail to set mcast, revert to TFTP\n");
+ ProhibitMcast = 1;
mcast_cleanup();
NetStartAgain();
}
}
- MasterClient = (unsigned char)simple_strtoul((char *)mc,NULL,10);
- Mcast_port = (unsigned short)simple_strtoul(port,NULL,10);
- printf ("Multicast: %s:%d [%d]\n", mc_adr, Mcast_port, MasterClient);
+ MasterClient = (unsigned char)simple_strtoul((char *)mc, NULL, 10);
+ Mcast_port = (unsigned short)simple_strtoul(port, NULL, 10);
+ printf("Multicast: %s:%d [%d]\n", mc_adr, Mcast_port, MasterClient);
return;
}
diff --git a/net/tftp.h b/net/tftp.h
index e3dfb2628a..2b686e3ca6 100644
--- a/net/tftp.h
+++ b/net/tftp.h
@@ -2,6 +2,8 @@
* LiMon - BOOTP/TFTP.
*
* Copyright 1994, 1995, 2000 Neil Russell.
+ * Copyright 2011 Comelit Group SpA
+ * Luca Ceresoli <luca.ceresoli@comelit.it>
* (See License)
*/
@@ -14,7 +16,14 @@
*/
/* tftp.c */
-extern void TftpStart (void); /* Begin TFTP get */
+void TftpStart(enum proto_t protocol); /* Begin TFTP get/put */
+
+#ifdef CONFIG_CMD_TFTPSRV
+extern void TftpStartServer(void); /* Wait for incoming TFTP put */
+#endif
+
+extern ulong TftpRRQTimeoutMSecs;
+extern int TftpRRQTimeoutCountMax;
/**********************************************************************/