* - name of bootfile
* Next step: ARP
*
- * LINK_LOCAL:
+ * LINKLOCAL:
*
* Prerequisites: - own ethernet address
* We want: - own IP address
#include <image.h>
#include <log.h>
#include <net.h>
-#include <net/fastboot.h>
+#include <net6.h>
+#include <ndisc.h>
+#include <net/fastboot_udp.h>
+#include <net/fastboot_tcp.h>
#include <net/tftp.h>
+#include <net/ncsi.h>
#if defined(CONFIG_CMD_PCAP)
#include <net/pcap.h>
#endif
#endif
#include <watchdog.h>
#include <linux/compiler.h>
+#include <test/test.h>
+#include <net/tcp.h>
+#include <net/wget.h>
#include "arp.h"
#include "bootp.h"
#include "cdp.h"
#if defined(CONFIG_CMD_WOL)
#include "wol.h"
#endif
+#include "dhcpv6.h"
+#include "net_rand.h"
/** BOOTP EXTENTIONS **/
/* Our 2nd DNS IP address */
struct in_addr net_dns_server2;
#endif
+/* Indicates whether the pxe path prefix / config file was specified in dhcp option */
+char *pxelinux_configfile;
/** END OF BOOTP EXTENTIONS **/
if (s != NULL && strcmp(s, "NFS") == 0) {
if (net_check_prereq(NFS)) {
/* We aren't expecting to get a serverip, so just accept the assigned IP */
-#ifdef CONFIG_BOOTP_SERVERIP
- net_set_state(NETLOOP_SUCCESS);
-#else
- printf("Cannot autoload with NFS\n");
- net_set_state(NETLOOP_FAIL);
-#endif
+ if (IS_ENABLED(CONFIG_BOOTP_SERVERIP)) {
+ net_set_state(NETLOOP_SUCCESS);
+ } else {
+ printf("Cannot autoload with NFS\n");
+ net_set_state(NETLOOP_FAIL);
+ }
return;
}
/*
}
if (net_check_prereq(TFTPGET)) {
/* We aren't expecting to get a serverip, so just accept the assigned IP */
-#ifdef CONFIG_BOOTP_SERVERIP
- net_set_state(NETLOOP_SUCCESS);
-#else
- printf("Cannot autoload with TFTPGET\n");
- net_set_state(NETLOOP_FAIL);
-#endif
+ if (IS_ENABLED(CONFIG_BOOTP_SERVERIP)) {
+ net_set_state(NETLOOP_SUCCESS);
+ } else {
+ printf("Cannot autoload with TFTPGET\n");
+ net_set_state(NETLOOP_FAIL);
+ }
return;
}
tftp_start(TFTPGET);
static int net_init_loop(void)
{
- if (eth_get_dev())
+ static bool first_call = true;
+
+ if (eth_get_dev()) {
memcpy(net_ethaddr, eth_get_ethaddr(), 6);
+
+ if (IS_ENABLED(CONFIG_IPV6)) {
+ ip6_make_lladdr(&net_link_local_ip6, net_ethaddr);
+ if (!memcmp(&net_ip6, &net_null_addr_ip6,
+ sizeof(struct in6_addr)))
+ memcpy(&net_ip6, &net_link_local_ip6,
+ sizeof(struct in6_addr));
+ }
+ }
else
/*
* Not ideal, but there's no way to get the actual error, and I
*/
return -ENONET;
+ if (IS_ENABLED(CONFIG_IPV6_ROUTER_DISCOVERY))
+ if (first_call && use_ip6) {
+ first_call = false;
+ srand_mac(); /* This is for rand used in ip6_send_rs. */
+ net_loop(RS);
+ }
return 0;
}
(i + 1) * PKTSIZE_ALIGN;
}
arp_init();
+ ndisc_init();
net_clear_handlers();
/* Only need to setup buffer pointers once. */
first_call = 0;
+ if (IS_ENABLED(CONFIG_PROT_TCP))
+ tcp_set_tcp_state(TCP_CLOSED);
}
return net_init_loop();
net_try_count = 1;
debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
+#ifdef CONFIG_PHY_NCSI
+ if (phy_interface_is_ncsi() && protocol != NCSI && !ncsi_active()) {
+ printf("%s: configuring NCSI first\n", __func__);
+ if (net_loop(NCSI) < 0)
+ return ret;
+ eth_init_state_only();
+ goto restart;
+ }
+#endif
+
bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
net_init();
if (eth_is_on_demand_init()) {
} else {
eth_init_state_only();
}
+
restart:
#ifdef CONFIG_USB_KEYBOARD
net_busy_flag = 0;
debug_cond(DEBUG_INT_STATE, "--- net_loop Init\n");
net_init_loop();
+ if (!test_eth_enabled())
+ return 0;
+
switch (net_check_prereq(protocol)) {
case 1:
/* network not configured */
tftp_start_server();
break;
#endif
-#ifdef CONFIG_UDP_FUNCTION_FASTBOOT
- case FASTBOOT:
- fastboot_start_server();
+#if defined(CONFIG_UDP_FUNCTION_FASTBOOT)
+ case FASTBOOT_UDP:
+ fastboot_udp_start_server();
+ break;
+#endif
+#if defined(CONFIG_TCP_FUNCTION_FASTBOOT)
+ case FASTBOOT_TCP:
+ fastboot_tcp_start_server();
break;
#endif
#if defined(CONFIG_CMD_DHCP)
dhcp_request(); /* Basically same as BOOTP */
break;
#endif
+ case DHCP6:
+ if (IS_ENABLED(CONFIG_CMD_DHCP6))
+ dhcp6_start();
+ break;
#if defined(CONFIG_CMD_BOOTP)
case BOOTP:
bootp_reset();
ping_start();
break;
#endif
+#if defined(CONFIG_CMD_PING6)
+ case PING6:
+ ping6_start();
+ break;
+#endif
#if defined(CONFIG_CMD_NFS) && !defined(CONFIG_SPL_BUILD)
case NFS:
nfs_start();
break;
#endif
+#if defined(CONFIG_CMD_WGET)
+ case WGET:
+ wget_start();
+ break;
+#endif
#if defined(CONFIG_CMD_CDP)
case CDP:
cdp_start();
wol_start();
break;
#endif
+#if defined(CONFIG_PHY_NCSI)
+ case NCSI:
+ ncsi_probe_packages();
+ break;
+#endif
+ case RS:
+ if (IS_ENABLED(CONFIG_IPV6_ROUTER_DISCOVERY))
+ ip6_send_rs();
+ break;
default:
break;
}
* someone sets `net_state' to a state that terminates.
*/
for (;;) {
- WATCHDOG_RESET();
+ schedule();
if (arp_timeout_check() > 0)
time_start = get_timer(0);
+ if (IS_ENABLED(CONFIG_IPV6)) {
+ if (use_ip6 && (ndisc_timeout_check() > 0))
+ time_start = get_timer(0);
+ }
+
/*
* Check the ethernet for a new packet. The ethernet
* receive routine will process it.
x = time_handler;
time_handler = (thand_f *)0;
(*x)();
- }
+ } else if (IS_ENABLED(CONFIG_IPV6_ROUTER_DISCOVERY))
+ if (time_handler && protocol == RS)
+ if (!ip6_is_unspecified_addr(&net_gateway6) &&
+ net_prefix_length != 0) {
+ net_set_state(NETLOOP_SUCCESS);
+ net_set_timeout_handler(0, NULL);
+ }
if (net_state == NETLOOP_FAIL)
ret = net_start_again();
env_set_hex("filesize", net_boot_file_size);
env_set_hex("fileaddr", image_load_addr);
}
- if (protocol != NETCONS)
+ if (protocol != NETCONS && protocol != NCSI)
eth_halt();
else
eth_halt_state_only();
IPPROTO_UDP, 0, 0, 0);
}
+#if defined(CONFIG_PROT_TCP)
+int net_send_tcp_packet(int payload_len, int dport, int sport, u8 action,
+ u32 tcp_seq_num, u32 tcp_ack_num)
+{
+ return net_send_ip_packet(net_server_ethaddr, net_server_ip, dport,
+ sport, payload_len, IPPROTO_TCP, action,
+ tcp_seq_num, tcp_ack_num);
+}
+#endif
+
int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
int payload_len, int proto, u8 action, u32 tcp_seq_num,
u32 tcp_ack_num)
payload_len);
pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE;
break;
+#if defined(CONFIG_PROT_TCP)
+ case IPPROTO_TCP:
+ pkt_hdr_size = eth_hdr_size
+ + tcp_set_tcp_header(pkt + eth_hdr_size, dport, sport,
+ payload_len, action, tcp_seq_num,
+ tcp_ack_num);
+ break;
+#endif
default:
return -EINVAL;
}
int offset8, start, len, done = 0;
u16 ip_off = ntohs(ip->ip_off);
+ /*
+ * Calling code already rejected <, but we don't have to deal
+ * with an IP fragment with no payload.
+ */
+ if (ntohs(ip->ip_len) <= IP_HDR_SIZE)
+ return NULL;
+
/* payload starts after IP header, this fragment is in there */
payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
offset8 = (ip_off & IP_OFFS);
start = offset8 * 8;
len = ntohs(ip->ip_len) - IP_HDR_SIZE;
+ /* All but last fragment must have a multiple-of-8 payload. */
+ if ((len & 7) && (ip_off & IP_FLAGS_MFRAG))
+ return NULL;
+
if (start + len > IP_MAXUDP) /* fragment extends too far */
return NULL;
}
/*
- * There is some overlap: fix the hole list. This code doesn't
- * deal with a fragment that overlaps with two different holes
- * (thus being a superset of a previously-received fragment).
+ * There is some overlap: fix the hole list. This code deals
+ * with a fragment that overlaps with two different holes
+ * (thus being a superset of a previously-received fragment)
+ * by only using the part of the fragment that fits in the
+ * first hole.
*/
+ if (h->last_byte < start + len)
+ len = h->last_byte - start;
if ((h >= thisfrag) && (h->last_byte <= start + len)) {
/* complete overlap with hole: remove hole */
if (!done)
return NULL;
- localip->ip_len = htons(total_len);
*lenp = total_len + IP_HDR_SIZE;
+ localip->ip_len = htons(*lenp);
return localip;
}
rarp_receive(ip, len);
break;
#endif
+#if IS_ENABLED(CONFIG_IPV6)
+ case PROT_IP6:
+ net_ip6_handler(et, (struct ip6_hdr *)ip, len);
+ break;
+#endif
case PROT_IP:
debug_cond(DEBUG_NET_PKT, "Got IP\n");
/* Before we start poking the header, make sure it is there */
- if (len < IP_UDP_HDR_SIZE) {
+ if (len < IP_HDR_SIZE) {
debug("len bad %d < %lu\n", len,
- (ulong)IP_UDP_HDR_SIZE);
+ (ulong)IP_HDR_SIZE);
return;
}
/* Check the packet length */
return;
}
len = ntohs(ip->ip_len);
+ if (len < IP_HDR_SIZE) {
+ debug("bad ip->ip_len %d < %d\n", len, (int)IP_HDR_SIZE);
+ return;
+ }
debug_cond(DEBUG_NET_PKT, "len=%d, v=%02x\n",
len, ip->ip_hl_v & 0xff);
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 (!ip_checksum_ok((uchar *)ip, IP_HDR_SIZE)) {
if (ip->ip_p == IPPROTO_ICMP) {
receive_icmp(ip, len, src_ip, et);
return;
+#if defined(CONFIG_PROT_TCP)
+ } else if (ip->ip_p == IPPROTO_TCP) {
+ debug_cond(DEBUG_DEV_PKT,
+ "TCP PH (to=%pI4, from=%pI4, len=%d)\n",
+ &dst_ip, &src_ip, len);
+
+ rxhand_tcp_f((union tcp_build_pkt *)ip, len);
+ return;
+#endif
} else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
return;
}
- if (ntohs(ip->udp_len) < UDP_HDR_SIZE || ntohs(ip->udp_len) > ntohs(ip->ip_len))
+ if (ntohs(ip->udp_len) < UDP_HDR_SIZE || ntohs(ip->udp_len) > len - IP_HDR_SIZE)
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) {
+ if (IS_ENABLED(CONFIG_UDP_CHECKSUM) && ip->udp_xsum != 0) {
ulong xsum;
u8 *sumptr;
ushort sumlen;
return;
}
}
-#endif
#if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_SPL_BUILD)
nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE,
wol_receive(ip, len);
break;
#endif
+#ifdef CONFIG_PHY_NCSI
+ case PROT_NCSI:
+ ncsi_receive(et, ip, len);
+ break;
+#endif
}
}
}
goto common;
#endif
+#if defined(CONFIG_CMD_PING6)
+ case PING6:
+ if (ip6_is_unspecified_addr(&net_ping_ip6)) {
+ puts("*** ERROR: ping address not given\n");
+ return 1;
+ }
+ goto common;
+#endif
#if defined(CONFIG_CMD_DNS)
case DNS:
if (net_dns_server.s_addr == 0) {
/* Fall through */
case TFTPGET:
case TFTPPUT:
- if (net_server_ip.s_addr == 0 && !is_serverip_in_cmd()) {
+ if (IS_ENABLED(CONFIG_IPV6) && use_ip6) {
+ if (!memcmp(&net_server_ip6, &net_null_addr_ip6,
+ sizeof(struct in6_addr)) &&
+ !strchr(net_boot_file_name, '[')) {
+ puts("*** ERROR: `serverip6' not set\n");
+ return 1;
+ }
+ } else if (net_server_ip.s_addr == 0 && !is_serverip_in_cmd()) {
puts("*** ERROR: `serverip' not set\n");
return 1;
}
/* Fall through */
case NETCONS:
- case FASTBOOT:
+ case FASTBOOT_UDP:
+ case FASTBOOT_TCP:
case TFTPSRV:
- if (net_ip.s_addr == 0) {
+ if (IS_ENABLED(CONFIG_IPV6) && use_ip6) {
+ if (!memcmp(&net_link_local_ip6, &net_null_addr_ip6,
+ sizeof(struct in6_addr))) {
+ puts("*** ERROR: `ip6addr` not set\n");
+ return 1;
+ }
+ } else if (net_ip.s_addr == 0) {
puts("*** ERROR: `ipaddr' not set\n");
return 1;
}
#ifdef CONFIG_CMD_RARP
case RARP:
#endif
+#ifdef CONFIG_PHY_NCSI
+ case NCSI:
+#endif
case BOOTP:
case CDP:
case DHCP:
int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len)
{
char *colon;
+ struct in_addr ip;
+ ip.s_addr = 0;
if (net_boot_file_name[0] == '\0')
return 0;
colon = strchr(net_boot_file_name, ':');
if (colon) {
- if (ipaddr)
- *ipaddr = string_to_ip(net_boot_file_name);
+ ip = string_to_ip(net_boot_file_name);
+ if (ipaddr && ip.s_addr)
+ *ipaddr = ip;
+ }
+ if (ip.s_addr) {
strncpy(filename, colon + 1, max_len);
} else {
strncpy(filename, net_boot_file_name, max_len);