int net_start_again(void) { char *nretry; int retry_forever = 0; unsigned long retrycnt = 0; int ret; nretry = getenv("netretry"); if (nretry) { if (!strcmp(nretry, "yes")) retry_forever = 1; else if (!strcmp(nretry, "no")) retrycnt = 0; else if (!strcmp(nretry, "once")) retrycnt = 1; else retrycnt = simple_strtoul(nretry, NULL, 0); } else { retrycnt = 0; retry_forever = 0; } if ((!retry_forever) && (net_try_count >= retrycnt)) { eth_halt(); net_set_state(NETLOOP_FAIL); /* * We don't provide a way for the protocol to return an error, * but this is almost always the reason. */ return -ETIMEDOUT; } net_try_count++; eth_halt(); #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!net_restarted); #endif ret = eth_init(); if (net_restart_wrap) { net_restart_wrap = 0; if (net_dev_exists) { net_set_timeout_handler(10000UL, start_again_timeout_handler); net_set_udp_handler(NULL); } else { net_set_state(NETLOOP_FAIL); } } else { net_set_state(NETLOOP_RESTART); } return ret; }
void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) { struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src; struct in_addr src_ip; int eth_hdr_size; switch (icmph->type) { case ICMP_ECHO_REPLY: src_ip = net_read_ip((void *)&ip->ip_src); if (src_ip.s_addr == net_ping_ip.s_addr) 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; net_copy_ip((void *)&ip->ip_dst, &ip->ip_src); net_copy_ip((void *)&ip->ip_src, &net_ip); ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE); icmph->type = ICMP_ECHO_REPLY; icmph->checksum = 0; icmph->checksum = compute_ip_checksum(icmph, len - IP_HDR_SIZE); net_send_packet((uchar *)et, eth_hdr_size + len); return; /* default: return;*/ } }
void NfsStart(void) { debug("%s\n", __func__); nfs_download_state = NETLOOP_FAIL; NfsServerIP = NetServerIP; nfs_path = (char *)nfs_path_buff; if (nfs_path == NULL) { net_set_state(NETLOOP_FAIL); puts("*** ERROR: Fail allocate memory\n"); return; } if (BootFile[0] == '\0') { 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); printf("*** Warning: no boot file name; using '%s'\n", nfs_path); } else {
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;*/ } }
void NetStartAgain(void) { char *nretry; int retry_forever = 0; unsigned long retrycnt = 0; nretry = getenv("netretry"); if (nretry) { if (!strcmp(nretry, "yes")) retry_forever = 1; else if (!strcmp(nretry, "no")) retrycnt = 0; else if (!strcmp(nretry, "once")) retrycnt = 1; else retrycnt = simple_strtoul(nretry, NULL, 0); } else retry_forever = 1; if ((!retry_forever) && (NetTryCount >= retrycnt)) { eth_halt(); net_set_state(NETLOOP_FAIL); return; } NetTryCount++; eth_halt(); #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) eth_try_another(!NetRestarted); #endif eth_init(gd->bd); if (NetRestartWrap) { NetRestartWrap = 0; if (NetDevExists) { NetSetTimeout(10000UL, startAgainTimeout); net_set_udp_handler(NULL); } else { net_set_state(NETLOOP_FAIL); } } else { net_set_state(NETLOOP_RESTART); } }
void register_net_interface(net_interface_t *interface) { interface->rx_total = 0; interface->tx_total = 0; interface->ip_data = 0; uint32_t flags; spin_lock_irqsave(&interface_lock, &flags); list_add(&interface->list, &interfaces); spin_unlock_irqstore(&interface_lock, flags); net_set_state(interface, IF_DOWN); }
/* * Timeout on BOOTP/DHCP request. */ static void BootpTimeout(void) { if (BootpTry >= TIMEOUT_COUNT) { #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(); } }
/* 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); }
/* * Timeout on BOOTP/DHCP request. */ static void bootp_timeout_handler(void) { ulong time_taken = get_timer(bootp_start); if (time_taken >= TIMEOUT_MS) { #ifdef CONFIG_BOOTP_MAY_FAIL puts("\nRetry time exceeded\n"); net_set_state(NETLOOP_FAIL); #else puts("\nRetry time exceeded; starting again\n"); net_start_again(); #endif } else { bootp_timeout *= 2; if (bootp_timeout > 2000) bootp_timeout = 2000; net_set_timeout_handler(bootp_timeout, bootp_timeout_handler); bootp_request(); } }
/* * Timeout on BOOTP/DHCP request. */ static void BootpTimeout(void) { ulong time_taken = get_timer(bootp_start); if (time_taken >= TIMEOUT_MS) { #ifdef CONFIG_BOOTP_MAY_FAIL puts("\nRetry time exceeded\n"); net_set_state(NETLOOP_FAIL); #else puts("\nRetry time exceeded; starting again\n"); NetStartAgain(); #endif } else { bootp_timeout *= 2; if (bootp_timeout > 2000) bootp_timeout = 2000; NetSetTimeout(bootp_timeout, BootpTimeout); BootpRequest(); } }
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++) { /* start address in flash? */ if (flash_info[i].flash_id == FLASH_UNKNOWN) continue; if (load_addr + offset >= flash_info[i].start[0]) { rc = 1; break; } } if (rc) { /* Flash is destination for this packet */ rc = flash_write((char *)src, (ulong)(load_addr+offset), len); if (rc) { flash_perror(rc); net_set_state(NETLOOP_FAIL); return; } } else #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ { (void)memcpy((void *)(load_addr + offset), src, len); } #ifdef CONFIG_MCAST_TFTP if (Multicast) ext2_set_bit(block, Bitmap); #endif if (NetBootFileXferSize < newsize) NetBootFileXferSize = newsize; }
/* * Check if autoload is enabled. If so, use either NFS or TFTP to download * the boot file. */ void net_auto_load(void) { #if defined(CONFIG_CMD_NFS) const char *s = getenv("autoload"); if (s != NULL && strcmp(s, "NFS") == 0) { /* * Use NFS to load the bootfile. */ nfs_start(); 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; } tftp_start(TFTPGET); }
void link_local_start(void) { ip = getenv_IPaddr("llipaddr"); if (ip != 0 && (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(); }
int arp_timeout_check(void) { ulong t; if (!net_arp_wait_packet_ip.s_addr) return 0; t = get_timer(0); /* check for arp timeout */ if ((t - arp_wait_timer_start) > ARP_TIMEOUT) { arp_wait_try++; if (arp_wait_try >= ARP_TIMEOUT_COUNT) { puts("\nARP Retry count exceeded; starting again\n"); arp_wait_try = 0; net_set_state(NETLOOP_FAIL); } else { arp_wait_timer_start = t; arp_request(); } } return 1; }
static void bootme_handler(uchar *pkt, unsigned dest_port, IPaddr_t src_ip, unsigned src_port, unsigned len) { uchar *eth_pkt = pkt; unsigned eth_len = len; static char cursor = '|'; enum bootme_state last_state = BOOTME_INIT; #if 1 debug("received packet of len %d from %pI4:%d to port %d\n", len, &src_ip, src_port, dest_port); ce_dump_block(pkt, len); #endif if (!bootme_packet_handler) { printf("No packet handler set for BOOTME protocol; dropping packet\n"); return; } if (dest_port != bootme_src_port || !len) return; /* not for us */ printf("%c\x08", cursor); cursor = next_cursor(cursor); if (is_broadcast(bootme_ip)) { bootme_ip = src_ip; } else if (src_ip != bootme_ip) { debug("src_ip %pI4 does not match destination IP %pI4\n", &src_ip, &bootme_ip); return; /* not from our server */ } last_state = bootme_state; bootme_dst_port = src_port; debug("bootme_dst_port set to %d\n", bootme_dst_port); if (bootme_state == BOOTME_INIT) { bootme_src_port = EDBG_SVC_PORT; debug("%s: bootme_src_port set to %d\n", __func__, bootme_src_port); } bootme_state = bootme_packet_handler(eth_pkt, eth_len); debug("bootme_packet_handler() returned %d\n", bootme_state); if (bootme_state != last_state) debug("bootme_state: %d -> %d\n", last_state, bootme_state); switch (bootme_state) { case BOOTME_INIT: break; case BOOTME_DOWNLOAD: if (last_state != BOOTME_INIT) NetBootFileXferSize += len - 4; /* fallthru */ case BOOTME_DEBUG: if (last_state == BOOTME_INIT) { bootme_timeout = 3 * 1000; } NetSetTimeout(bootme_timeout, bootme_timeout_handler); break; case BOOTME_DONE: net_set_state(NETLOOP_SUCCESS); bootme_packet_handler = NULL; break; case BOOTME_ERROR: net_set_state(NETLOOP_FAIL); bootme_packet_handler = NULL; } }
static void bootme_wait_arp_handler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) { net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */ }
static void nc_wait_arp_handler(uchar *pkt, unsigned dest, struct in_addr sip, unsigned src, unsigned len) { net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */ }
static void start_again_timeout_handler(void) { net_set_state(NETLOOP_RESTART); }
int net_loop(enum proto_t protocol) { int ret = -EINVAL; net_restarted = 0; net_dev_exists = 0; net_try_count = 1; debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n"); bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start"); net_init(); if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); eth_set_current(); ret = eth_init(); if (ret < 0) { eth_halt(); return ret; } } else { eth_init_state_only(); } restart: #ifdef CONFIG_USB_KEYBOARD net_busy_flag = 0; #endif 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. */ debug_cond(DEBUG_INT_STATE, "--- net_loop Init\n"); net_init_loop(); switch (net_check_prereq(protocol)) { case 1: /* network not configured */ eth_halt(); return -ENODEV; case 2: /* network device not configured */ break; case 0: net_dev_exists = 1; net_boot_file_size = 0; switch (protocol) { case TFTPGET: #ifdef CONFIG_CMD_TFTPPUT case TFTPPUT: #endif /* always use ARP to get server ethernet address */ tftp_start(protocol); break; #ifdef CONFIG_CMD_TFTPSRV case TFTPSRV: tftp_start_server(); break; #endif #if defined(CONFIG_CMD_DHCP) case DHCP: bootp_reset(); net_ip.s_addr = 0; dhcp_request(); /* Basically same as BOOTP */ break; #endif case BOOTP: bootp_reset(); net_ip.s_addr = 0; bootp_request(); break; #if defined(CONFIG_CMD_RARP) case RARP: rarp_try = 0; net_ip.s_addr = 0; rarp_request(); break; #endif #if defined(CONFIG_CMD_PING) case PING: ping_start(); break; #endif #if defined(CONFIG_CMD_NFS) case NFS: nfs_start(); break; #endif #if defined(CONFIG_CMD_CDP) case CDP: cdp_start(); break; #endif #if defined(CONFIG_NETCONSOLE) && !(CONFIG_SPL_BUILD) case NETCONS: nc_start(); break; #endif #if defined(CONFIG_CMD_SNTP) case SNTP: sntp_start(); break; #endif #if defined(CONFIG_CMD_DNS) case DNS: dns_start(); break; #endif #if defined(CONFIG_CMD_LINK_LOCAL) case LINKLOCAL: link_local_start(); break; #endif default: break; } 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) /* * 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); #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 `net_state' to a state that terminates. */ for (;;) { WATCHDOG_RESET(); #ifdef CONFIG_SHOW_ACTIVITY show_activity(1); #endif if (arp_timeout_check() > 0) time_start = get_timer(0); /* * Check the ethernet for a new packet. The ethernet * receive routine will process it. * Most drivers return the most recent packet size, but not * errors that may have happened. */ eth_rx(); /* * Abort if ctrl-c was pressed. */ if (ctrlc()) { /* cancel any ARP that may not have completed */ net_arp_wait_packet_ip.s_addr = 0; net_cleanup_loop(); eth_halt(); /* 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, "--- net_loop Abort!\n"); ret = -EINTR; goto done; } /* * Check for a timeout, and run the timeout handler * if we have one. */ if (time_handler && ((get_timer(0) - time_start) > time_delta)) { 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) /* * 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); #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */ #endif /* CONFIG_MII, ... */ debug_cond(DEBUG_INT_STATE, "--- net_loop timeout\n"); x = time_handler; time_handler = (thand_f *)0; (*x)(); } if (net_state == NETLOOP_FAIL) ret = net_start_again(); switch (net_state) { case NETLOOP_RESTART: net_restarted = 1; goto restart; case NETLOOP_SUCCESS: net_cleanup_loop(); if (net_boot_file_size > 0) { printf("Bytes transferred = %d (%x hex)\n", net_boot_file_size, net_boot_file_size); setenv_hex("filesize", net_boot_file_size); setenv_hex("fileaddr", load_addr); } if (protocol != NETCONS) eth_halt(); else eth_halt_state_only(); eth_set_last_protocol(protocol); ret = net_boot_file_size; debug_cond(DEBUG_INT_STATE, "--- net_loop Success!\n"); goto done; case NETLOOP_FAIL: net_cleanup_loop(); /* Invalidate the last protocol */ eth_set_last_protocol(BOOTP); debug_cond(DEBUG_INT_STATE, "--- net_loop 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; }
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(); eth_set_current(); if (eth_init(bd) < 0) { eth_halt(); return -1; } } else eth_init_state_only(bd); restart: #ifdef CONFIG_USB_KEYBOARD net_busy_flag = 0; #endif 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. */ debug_cond(DEBUG_INT_STATE, "--- NetLoop Init\n"); NetInitLoop(); switch (net_check_prereq(protocol)) { case 1: /* network not configured */ eth_halt(); return -1; case 2: /* network device not configured */ break; case 0: NetDevExists = 1; NetBootFileXferSize = 0; switch (protocol) { case TFTPGET: #ifdef CONFIG_CMD_TFTPPUT case TFTPPUT: #endif /* always use ARP to get server ethernet address */ TftpStart(protocol); break; #ifdef CONFIG_CMD_TFTPSRV case TFTPSRV: TftpStartServer(); break; #endif #if defined(CONFIG_CMD_DHCP) case DHCP: BootpReset(); NetOurIP = 0; DhcpRequest(); /* Basically same as BOOTP */ break; #endif case BOOTP: BootpReset(); NetOurIP = 0; BootpRequest(); break; #if defined(CONFIG_CMD_RARP) case RARP: RarpTry = 0; NetOurIP = 0; RarpRequest(); break; #endif #if defined(CONFIG_CMD_PING) case PING: ping_start(); break; #endif #if defined(CONFIG_CMD_NFS) case NFS: NfsStart(); break; #endif #if defined(CONFIG_CMD_CDP) case CDP: CDPStart(); break; #endif #if defined (CONFIG_NETCONSOLE) && !(CONFIG_SPL_BUILD) case NETCONS: NcStart(); break; #endif #if defined(CONFIG_CMD_SNTP) case SNTP: SntpStart(); break; #endif #if defined(CONFIG_CMD_DNS) case DNS: DnsStart(); break; #endif #if defined(CONFIG_CMD_LINK_LOCAL) case LINKLOCAL: link_local_start(); break; #endif default: break; } 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) /* * 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); #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 `net_state' to a state that terminates. */ for (;;) { WATCHDOG_RESET(); #ifdef CONFIG_SHOW_ACTIVITY show_activity(1); #endif /* * Check the ethernet for a new packet. The ethernet * receive routine will process it. */ eth_rx(); /* * Abort if ctrl-c was pressed. */ if (ctrlc()) { /* cancel any ARP that may not have completed */ NetArpWaitPacketIP = 0; net_cleanup_loop(); eth_halt(); /* 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(); /* * Check for a timeout, and run the timeout handler * if we have one. */ if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) { 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) /* * 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); } #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 (net_state) { case NETLOOP_RESTART: NetRestarted = 1; goto restart; case NETLOOP_SUCCESS: net_cleanup_loop(); if (NetBootFileXferSize > 0) { printf("Bytes transferred = %ld (%lx hex)\n", NetBootFileXferSize, NetBootFileXferSize); setenv_hex("filesize", NetBootFileXferSize); setenv_hex("fileaddr", load_addr); } 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: 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; }
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(); }
static void nc_timeout_handler(void) { net_set_state(NETLOOP_SUCCESS); }
static void ping_timeout_handler(void) { eth_halt(); net_set_state(NETLOOP_FAIL); /* we did not get the reply */ }
static void dns_handler(uchar *pkt, unsigned dest, struct in_addr sip, unsigned src, unsigned len) { struct header *header; const unsigned char *p, *e, *s; u16 type, i; int found, stop, dlen; char ip_str[22]; struct in_addr ip_addr; debug("%s\n", __func__); if (dest != dns_our_port) return; for (i = 0; i < len; i += 4) 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 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: host not found\n"); net_set_state(NETLOOP_SUCCESS); return; } /* Skip host name */ s = &header->data[0]; e = pkt + len; for (p = s; p < e && *p != '\0'; p++) continue; /* We sent query class 1, query type 1 */ 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; } /* Go to the first answer section */ p += 5; /* Loop through the answers, we want A type answer */ for (found = stop = 0; !stop && &p[12] < e; ) { /* Skip possible name in CNAME answer */ if (*p != 0xc0) { while (*p && &p[12] < e) p++; p--; } debug("Name (Offset in header): %d\n", p[1]); 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"); dlen = get_unaligned_be16(p+10); debug("dlen = %d\n", dlen); p += 12 + dlen; } else if (type == DNS_A_RECORD) { debug("Found A-record\n"); found = 1; stop = 1; } else { debug("Unknown type\n"); stop = 1; } } if (found && &p[12] < e) { dlen = get_unaligned_be16(p+10); p += 12; memcpy(&ip_addr, p, 4); if (p + dlen <= e) { ip_to_string(ip_addr, ip_str); printf("%s\n", ip_str); if (net_dns_env_var) env_set(net_dns_env_var, ip_str); } else { puts("server responded with invalid IP number\n"); } } net_set_state(NETLOOP_SUCCESS); }
static void bootme_timeout_handler(void) { net_set_state(NETLOOP_SUCCESS); bootme_timed_out++; }
static void nc_handler(uchar *pkt, unsigned dest, struct in_addr sip, unsigned src, unsigned len) { if (input_size) net_set_state(NETLOOP_SUCCESS); /* got input - quit net loop */ }
static void dns_timeout_handler(void) { puts("Timeout\n"); net_set_state(NETLOOP_FAIL); }
static void startAgainTimeout(void) { net_set_state(NETLOOP_RESTART); }
static void TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) { __be16 proto; __be16 *s; int i; if (dest != TftpOurPort) { #ifdef CONFIG_MCAST_TFTP if (Multicast && (!Mcast_port || (dest != Mcast_port))) #endif return; } if (TftpState != STATE_SEND_RRQ && src != TftpRemotePort && TftpState != STATE_RECV_WRQ && TftpState != STATE_SEND_WRQ) return; if (len < 2) return; len -= 2; /* warning: don't use increment (++) in ntohs() macros!! */ s = (__be16 *)pkt; proto = *s++; pkt = (uchar *)s; switch (ntohs(proto)) { case TFTP_RRQ: 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; 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) { TftpBlkSize = (unsigned short) simple_strtoul((char *)pkt+i+8, NULL, 10); debug("Blocksize ack: %s, %d\n", (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); debug("size = %s, %d\n", (char *)pkt+i+6, TftpTsize); } #endif } #ifdef CONFIG_MCAST_TFTP parse_multicast_oack((char *)pkt, len-1); if ((Multicast) && (!MasterClient)) TftpState = STATE_DATA; /* passive.. */ else #endif #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(*(__be16 *)pkt); update_block_number(); if (TftpState == STATE_SEND_RRQ) debug("Server did not acknowledge timeout option!\n"); if (TftpState == STATE_SEND_RRQ || TftpState == STATE_OACK || TftpState == STATE_RECV_WRQ) { /* first block received */ TftpState = STATE_DATA; TftpRemotePort = src; new_transfer(); #ifdef CONFIG_MCAST_TFTP if (Multicast) { /* start!=1 common if mcast */ TftpLastBlock = TftpBlock - 1; } else #endif if (TftpBlock != 1) { /* Assertion */ printf("\nTFTP error: " "First block is not block 1 (%ld)\n" "Starting again\n\n", TftpBlock); NetStartAgain(); break; } } if (TftpBlock == TftpLastBlock) { /* * Same block again; ignore it. */ break; } TftpLastBlock = TftpBlock; TftpTimeoutCountMax = TIMEOUT_COUNT; NetSetTimeout(TftpTimeoutMSecs, TftpTimeout); store_block(TftpBlock - 1, pkt + 2, len); /* * 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 * needed block is; else I'm passive; not ACKING */ if (Multicast) { if (len < TftpBlkSize) { TftpEndingBlock = TftpBlock; } else if (MasterClient) { TftpBlock = PrevBitmapHole = ext2_find_next_zero_bit( Bitmap, (Mapsize*8), PrevBitmapHole); if (TftpBlock > ((Mapsize*8) - 1)) { printf("tftpfile too big\n"); /* try to double it and retry */ Mapsize <<= 1; mcast_cleanup(); NetStartAgain(); return; } TftpLastBlock = TftpBlock; } } #endif TftpSend(); #ifdef CONFIG_MCAST_TFTP if (Multicast) { if (MasterClient && (TftpBlock >= TftpEndingBlock)) { puts("\nMulticast tftp done\n"); mcast_cleanup(); net_set_state(NETLOOP_SUCCESS); } } else #endif if (len < TftpBlkSize) tftp_complete(); break; case TFTP_ERROR: printf("\nTFTP error: '%s' (%d)\n", pkt + 2, ntohs(*(__be16 *)pkt)); switch (ntohs(*(__be16 *)pkt)) { case TFTP_ERR_FILE_NOT_FOUND: case TFTP_ERR_ACCESS_DENIED: puts("Not retrying...\n"); eth_halt(); net_set_state(NETLOOP_FAIL); break; case TFTP_ERR_UNDEFINED: case TFTP_ERR_DISK_FULL: case TFTP_ERR_UNEXPECTED_OPCODE: case TFTP_ERR_UNKNOWN_TRANSFER_ID: case TFTP_ERR_FILE_ALREADY_EXISTS: default: puts("Starting again\n\n"); #ifdef CONFIG_MCAST_TFTP mcast_cleanup(); #endif NetStartAgain(); break; } break; } }
static void NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) { int rlen; debug("%s\n", __func__); if (dest != NfsOurPort) return; switch (NfsState) { case STATE_PRCLOOKUP_PROG_MOUNT_REQ: rpc_lookup_reply(PROG_MOUNT, pkt, len); NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ; NfsSend(); break; case STATE_PRCLOOKUP_PROG_NFS_REQ: rpc_lookup_reply(PROG_NFS, pkt, len); NfsState = STATE_MOUNT_REQ; NfsSend(); break; case STATE_MOUNT_REQ: if (nfs_mount_reply(pkt, len)) { puts("*** ERROR: Cannot mount\n"); /* just to be sure... */ NfsState = STATE_UMOUNT_REQ; NfsSend(); } else { NfsState = STATE_LOOKUP_REQ; NfsSend(); } break; case STATE_UMOUNT_REQ: if (nfs_umountall_reply(pkt, len)) { puts("*** ERROR: Cannot umount\n"); net_set_state(NETLOOP_FAIL); } else { 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"); NfsState = STATE_UMOUNT_REQ; NfsSend(); } else { NfsState = STATE_READ_REQ; nfs_offset = 0; nfs_len = NFS_READ_SIZE; NfsSend(); } break; case STATE_READLINK_REQ: if (nfs_readlink_reply(pkt, len)) { puts("*** ERROR: Symlink fail\n"); NfsState = STATE_UMOUNT_REQ; NfsSend(); } else { debug("Symlink --> %s\n", nfs_path); nfs_filename = basename(nfs_path); nfs_path = dirname(nfs_path); NfsState = STATE_MOUNT_REQ; NfsSend(); } break; case STATE_READ_REQ: 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)) { /* symbolic link */ NfsState = STATE_READLINK_REQ; NfsSend(); } else { if (!rlen) nfs_download_state = NETLOOP_SUCCESS; NfsState = STATE_UMOUNT_REQ; NfsSend(); } break; } }