summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/ui/ui_netcmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/ui/ui_netcmds.c')
-rw-r--r--cfe/cfe/ui/ui_netcmds.c710
1 files changed, 710 insertions, 0 deletions
diff --git a/cfe/cfe/ui/ui_netcmds.c b/cfe/cfe/ui/ui_netcmds.c
new file mode 100644
index 0000000..891e127
--- /dev/null
+++ b/cfe/cfe/ui/ui_netcmds.c
@@ -0,0 +1,710 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Network commands File: ui_netcmds.c
+ *
+ * Network user interface
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_console.h"
+#include "cfe_devfuncs.h"
+#include "cfe_timer.h"
+#include "cfe_ioctl.h"
+
+#include "cfe_error.h"
+
+#include "env_subr.h"
+#include "ui_command.h"
+#include "cfe.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "net_api.h"
+
+#include "cfe_fileops.h"
+
+#include "bsp_config.h"
+
+#define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0)
+#define isdigit(d) (((d) >= '0') && ((d) <= '9'))
+
+int ui_init_netcmds(void);
+
+#if CFG_NETWORK
+static int ui_cmd_ifconfig(ui_cmdline_t *cmd,int argc,char *argv[]);
+static int ui_cmd_arp(ui_cmdline_t *cmd,int argc,char *argv[]);
+static int ui_cmd_ping(ui_cmdline_t *cmd,int argc,char *argv[]);
+#if CFG_TCP
+extern int ui_init_tcpcmds(void);
+#endif
+#endif
+
+typedef struct netparam_s {
+ const char *str;
+ int num;
+} netparam_t;
+
+const static netparam_t loopbacktypes[] = {
+ {"off",ETHER_LOOPBACK_OFF},
+ {"internal",ETHER_LOOPBACK_INT},
+ {"external",ETHER_LOOPBACK_EXT},
+ {0,NULL}};
+
+const static netparam_t speedtypes[] = {
+ {"auto",ETHER_SPEED_AUTO},
+ {"10hdx",ETHER_SPEED_10HDX},
+ {"10fdx",ETHER_SPEED_10FDX},
+ {"100hdx",ETHER_SPEED_100HDX},
+ {"100fdx",ETHER_SPEED_100FDX},
+ {"1000hdx",ETHER_SPEED_1000HDX},
+ {"1000fdx",ETHER_SPEED_1000FDX},
+ {0,NULL}};
+
+
+int ui_init_netcmds(void)
+{
+#if CFG_NETWORK
+ cmd_addcmd("ifconfig",
+ ui_cmd_ifconfig,
+ NULL,
+ "Configure the Ethernet interface",
+ "ifconfig device [options..]\n\n"
+ "Activates and configures the specified Ethernet interface and sets its\n"
+ "IP address, netmask, and other parameters. The -auto switch can be used\n"
+ "to set this information via DHCP.",
+ "-auto;Configure interface automatically via DHCP|"
+ "-off;Deactivate the specified interface|"
+ "-addr=*;Specifies the IP address of the interface|"
+ "-mask=*;Specifies the subnet mask for the interface|"
+ "-gw=*;Specifies the gateway address for the interface|"
+ "-dns=*;Specifies the name server address for the interface|"
+ "-domain=*;Specifies the default domain for name service queries|"
+ "-speed=*;Sets the interface speed (auto,10fdx,10hdx,\n100fdx,\n"
+ "100hdx,1000fdx,1000hdx)|"
+ "-loopback=*;Sets the loopback mode (off,internal,external) "
+ "External\nloopback causes the phy to be placed in loopback mode|"
+ "-hwaddr=*;Sets the hardware address (overrides environment)");
+
+ cmd_addcmd("arp",
+ ui_cmd_arp,
+ NULL,
+ "Display or modify the ARP Table",
+ "arp [-d] [ip-address] [dest-address]\n\n"
+ "Without any parameters, the arp command will display the contents of the\n"
+ "arp table. With two parameters, arp can be used to add permanent arp\n"
+ "entries to the table (permanent arp entries do not time out)",
+ "-d;Delete the specified ARP entry. If specified, ip-address\n"
+ "may be * to delete all entries.");
+
+ cmd_addcmd("ping",
+ ui_cmd_ping,
+ NULL,
+ "Ping a remote IP host.",
+ "ping [-t] remote-host\n\n"
+ "This command sends an ICMP ECHO message to a remote host and waits for \n"
+ "a reply. The network interface must be configured and operational for\n"
+ "this command to work. If the interface is configured for loopback mode\n"
+ "the packet will be sent through the network interface, so this command\n"
+ "can be used for a simple network test.",
+ "-t;Ping forever, or until the ENTER key is struck|"
+ "-x;Exit immediately on first error (use with -f or -t)|"
+ "-f;Flood ping (use carefully!) - ping as fast as possible|"
+ "-s=*;Specify the number of ICMP data bytes|"
+ "-c=*;Specify number of packets to echo|"
+ "-A;don't abort even if key is pressed|"
+ "-E;Require all packets sent to be returned, for successful return status");
+
+#if CFG_TCP
+ /* Foxconn add start by Cliff Wang, 03/23/2010 */
+ //ui_init_tcpcmds();
+ /* Foxconn add end by Cliff Wang, 03/23/2010 */
+#endif
+
+
+#endif
+
+ return 0;
+}
+
+
+#if CFG_NETWORK
+static int parsexdigit(char str)
+{
+ int digit;
+
+ if ((str >= '0') && (str <= '9')) digit = str - '0';
+ else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10;
+ else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10;
+ else return -1;
+
+ return digit;
+}
+
+
+static int parsehwaddr(char *str,uint8_t *hwaddr)
+{
+ int digit1,digit2;
+ int idx = 6;
+
+ while (*str && (idx > 0)) {
+ digit1 = parsexdigit(*str);
+ if (digit1 < 0) return -1;
+ str++;
+ if (!*str) return -1;
+
+ if ((*str == ':') || (*str == '-')) {
+ digit2 = digit1;
+ digit1 = 0;
+ }
+ else {
+ digit2 = parsexdigit(*str);
+ if (digit2 < 0) return -1;
+ str++;
+ }
+
+ *hwaddr++ = (digit1 << 4) | digit2;
+ idx--;
+
+ if (*str == '-') str++;
+ if (*str == ':') str++;
+ }
+ return 0;
+}
+
+
+
+static int ui_ifdown(void)
+{
+ char *devname;
+
+ devname = (char *) net_getparam(NET_DEVNAME);
+ if (devname) {
+ xprintf("Device %s has been deactivated.\n",devname);
+ net_uninit();
+ net_setnetvars();
+ }
+
+ return 0;
+}
+
+static void ui_showifconfig(void)
+{
+ char *devname;
+ uint8_t *addr;
+
+ devname = (char *) net_getparam(NET_DEVNAME);
+ if (devname == NULL) {
+ xprintf("Network interface has not been configured\n");
+ return;
+ }
+
+ xprintf("Device %s: ",devname);
+
+ addr = net_getparam(NET_HWADDR);
+ if (addr) xprintf(" hwaddr %a",addr);
+
+ addr = net_getparam(NET_IPADDR);
+ if (addr) {
+ if (ip_addriszero(addr)) xprintf(", ipaddr not set");
+ else xprintf(", ipaddr %I",addr);
+ }
+
+ addr = net_getparam(NET_NETMASK);
+ if (addr) {
+ if (ip_addriszero(addr)) xprintf(", mask not set");
+ else xprintf(", mask %I",addr);
+ }
+
+ xprintf("\n");
+ xprintf(" ");
+
+ addr = net_getparam(NET_GATEWAY);
+ if (addr) {
+ if (ip_addriszero(addr)) xprintf("gateway not set");
+ else xprintf("gateway %I",addr);
+ }
+
+ addr = net_getparam(NET_NAMESERVER);
+ if (addr) {
+ if (ip_addriszero(addr)) xprintf(", nameserver not set");
+ else xprintf(", nameserver %I",addr);
+ }
+
+ addr = net_getparam(NET_DOMAIN);
+ if (addr) {
+ xprintf(", domain %s",addr);
+ }
+
+ xprintf("\n");
+}
+
+/* Foxconn add start by Cliff Wang, 03/23/2010 */
+#if 0
+static int ui_ifconfig_auto(ui_cmdline_t *cmd,char *devname)
+{
+ int err;
+ dhcpreply_t *reply = NULL;
+ char *x;
+ uint8_t hwaddr[6];
+
+ net_uninit();
+
+ err = net_init(devname);
+ if (err < 0) {
+ xprintf("Could not activate device %s: %s\n",
+ devname,cfe_errortext(err));
+ return err;
+ }
+
+ if (cmd_sw_value(cmd,"-hwaddr",&x)) {
+ if (parsehwaddr(x,hwaddr) != 0) {
+ xprintf("Invalid hardware address: %s\n",x);
+ net_uninit();
+ return CFE_ERR_INV_PARAM;
+ }
+ else {
+ net_setparam(NET_HWADDR,hwaddr);
+ }
+ }
+
+ err = dhcp_bootrequest(&reply);
+
+ if (err < 0) {
+ xprintf("DHCP registration failed on device %s\n",devname);
+ net_uninit();
+ return CFE_ERR_NETDOWN;
+ }
+
+ net_setparam(NET_IPADDR,reply->dr_ipaddr);
+ net_setparam(NET_NETMASK,reply->dr_netmask);
+ net_setparam(NET_GATEWAY,reply->dr_gateway);
+ net_setparam(NET_NAMESERVER,reply->dr_nameserver);
+ net_setparam(NET_DOMAIN,reply->dr_domainname);
+
+ dhcp_set_envvars(reply);
+
+ if (reply) dhcp_free_reply(reply);
+
+ ui_showifconfig();
+ net_setnetvars();
+ return 0;
+}
+#endif
+/* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+static int ui_ifconfig_getsw(ui_cmdline_t *cmd,char *swname,char *descr,uint8_t *addr)
+{
+ char *x;
+
+ x = NULL;
+
+ if (cmd_sw_value(cmd,swname,&x) == 0) return 0;
+
+ if ((x == NULL) || (parseipaddr(x,addr) < 0)) {
+ xprintf("Invalid %s: %s\n",descr,x ? x : "(none)");
+ return -1;
+ }
+
+ return 1;
+}
+
+static int ui_ifconfig_lookup(char *name,char *val,const netparam_t *list)
+{
+ const netparam_t *p = list;
+
+ while (p->str) {
+ if (strcmp(p->str,val) == 0) return p->num;
+ p++;
+ }
+
+ xprintf("Invalid parameter for %s: Valid options are: ");
+
+ p = list;
+ while (p->str) {
+ xprintf("%s ",p->str);
+ p++;
+ }
+
+ xprintf("\n");
+ return -1;
+}
+
+
+#define FLG_IPADDR 1
+#define FLG_NETMASK 2
+#define FLG_GATEWAY 4
+#define FLG_NAMESERVER 8
+#define FLG_DOMAIN 16
+#define FLG_LOOPBACK 32
+#define FLG_SPEED 64
+#define FLG_HWADDR 128
+
+static int ui_cmd_ifconfig(ui_cmdline_t *cmd,int argc,char *argv[])
+{
+ char *devname;
+ int flags = 0;
+ uint8_t ipaddr[IP_ADDR_LEN];
+ uint8_t netmask[IP_ADDR_LEN];
+ uint8_t gateway[IP_ADDR_LEN];
+ uint8_t nameserver[IP_ADDR_LEN];
+ uint8_t hwaddr[6];
+ int speed = ETHER_SPEED_AUTO;
+ int loopback = ETHER_LOOPBACK_OFF;
+ char *domain = NULL;
+ int res;
+ char *x;
+
+ if (argc < 1) {
+ ui_showifconfig();
+ return 0;
+ }
+
+ devname = cmd_getarg(cmd,0);
+
+ if (cmd_sw_isset(cmd,"-off")) {
+ return ui_ifdown();
+ }
+
+ /* Foxconn add start by Cliff Wang, 03/23/2010 */
+#if 0
+ if (cmd_sw_isset(cmd,"-auto")) {
+ return ui_ifconfig_auto(cmd,devname);
+ }
+#endif
+ /* Foxconn add end by Cliff Wang, 03/23/2010 */
+
+ res = ui_ifconfig_getsw(cmd,"-addr","interface IP address",ipaddr);
+ if (res < 0) return CFE_ERR_INV_PARAM;
+ if (res > 0) {
+ flags |= FLG_IPADDR;
+ }
+
+ res = ui_ifconfig_getsw(cmd,"-mask","netmask",netmask);
+ if (res < 0) return CFE_ERR_INV_PARAM;
+ if (res > 0) {
+ flags |= FLG_NETMASK;
+ }
+
+ res = ui_ifconfig_getsw(cmd,"-gw","gateway IP address",gateway);
+ if (res < 0) return CFE_ERR_INV_PARAM;
+ if (res > 0) {
+ flags |= FLG_GATEWAY;
+ }
+
+ res = ui_ifconfig_getsw(cmd,"-dns","name server IP address",nameserver);
+ if (res < 0) return CFE_ERR_INV_PARAM;
+ if (res > 0) {
+ flags |= FLG_NAMESERVER;
+ }
+
+ if (cmd_sw_value(cmd,"-domain",&domain)) {
+ if (domain) flags |= FLG_DOMAIN;
+ }
+
+ if (cmd_sw_value(cmd,"-speed",&x)) {
+ speed = ui_ifconfig_lookup("-speed",x,speedtypes);
+ if (speed >= 0) flags |= FLG_SPEED;
+ else return CFE_ERR_INV_PARAM;
+ }
+
+ if (cmd_sw_value(cmd,"-loopback",&x)) {
+ loopback = ui_ifconfig_lookup("-loopback",x,loopbacktypes);
+ if (loopback >= 0) flags |= FLG_LOOPBACK;
+ else return CFE_ERR_INV_PARAM;
+ }
+
+ if (cmd_sw_value(cmd,"-hwaddr",&x)) {
+ if (parsehwaddr(x,hwaddr) != 0) {
+ xprintf("Invalid hardware address: %s\n",x);
+ return CFE_ERR_INV_PARAM;
+ }
+ else {
+ flags |= FLG_HWADDR;
+ }
+ }
+
+ /*
+ * If the network is running and the device name is
+ * different, uninit the net first.
+ */
+
+ x = (char *) net_getparam(NET_DEVNAME);
+
+ if ((x != NULL) && (strcmp(x,devname) != 0)) {
+ net_uninit();
+ }
+
+ /*
+ * Okay, initialize the network if it is not already on. If it
+ * is OFF, the "net_devname" parameter will be NULL.
+ */
+
+ if (x == NULL) {
+ res = net_init(devname); /* turn interface on */
+ if (res < 0) {
+ ui_showerror(res,"Could not activate network interface '%s'",devname);
+ return res;
+ }
+ }
+
+ /*
+ * Set the parameters
+ */
+
+ if (flags & FLG_HWADDR) net_setparam(NET_HWADDR,hwaddr);
+ if (flags & FLG_IPADDR) net_setparam(NET_IPADDR,ipaddr);
+ if (flags & FLG_NETMASK) net_setparam(NET_NETMASK,netmask);
+ if (flags & FLG_GATEWAY) net_setparam(NET_GATEWAY,gateway);
+ if (flags & FLG_NAMESERVER) net_setparam(NET_NAMESERVER,nameserver);
+ /* Foxconn add start by Cliff Wang, 03/23/2010 */
+ if (flags & FLG_DOMAIN) net_setparam(NET_DOMAIN,(uint8_t *) domain);
+ /* Foxconn add end by Cliff Wang, 03/23/2010 */
+ if (flags & FLG_SPEED) net_setparam(NET_SPEED,(uint8_t *) &speed);
+ if (flags & FLG_LOOPBACK) net_setparam(NET_LOOPBACK,(uint8_t *) &loopback);
+
+ ui_showifconfig();
+ net_setnetvars();
+
+ return 0;
+}
+
+
+static int ui_cmd_arp(ui_cmdline_t *cmd,int argc,char *argv[])
+{
+ int idx;
+ uint8_t ipaddr[IP_ADDR_LEN];
+ uint8_t hwaddr[ENET_ADDR_LEN];
+ char *x;
+ int once = 0;
+
+ if (cmd_sw_isset(cmd,"-d")) {
+ if ((x = cmd_getarg(cmd,0)) == NULL) {
+ return ui_showusage(cmd);
+ }
+
+ if (strcmp(x,"*") == 0) {
+ while (arp_enumerate(0,ipaddr,hwaddr) >= 0) {
+ arp_delete(ipaddr);
+ }
+ }
+ else {
+ if (parseipaddr(x,ipaddr) < 0) {
+ xprintf("Invalid IP address: %s\n",x);
+ return CFE_ERR_INV_PARAM;
+ }
+ arp_delete(ipaddr);
+ }
+ return 0;
+ }
+
+ /*
+ * Get the IP address. If NULL, display the table.
+ */
+
+ x = cmd_getarg(cmd,0);
+ if (x == NULL) {
+ idx = 0;
+ while (arp_enumerate(idx,ipaddr,hwaddr) >= 0) {
+ if (once == 0) {
+ xprintf("Hardware Address IP Address\n");
+ xprintf("----------------- ---------------\n");
+ once = 1;
+ }
+ xprintf("%a %I\n",hwaddr,ipaddr);
+ idx++;
+ }
+ if (idx == 0) xprintf("No ARP entries.\n");
+ return 0;
+ }
+
+ if (parseipaddr(x,ipaddr) < 0) {
+ xprintf("Invalid IP address: %s\n",x);
+ return CFE_ERR_INV_PARAM;
+ }
+
+ /*
+ * Get the hardware address.
+ */
+
+ x = cmd_getarg(cmd,1);
+ if (x == NULL) {
+ return ui_showusage(cmd);
+ }
+
+ if (parsehwaddr(x,hwaddr) < 0) {
+ xprintf("Invalid hardware address: %s\n",x);
+ return CFE_ERR_INV_PARAM;
+ }
+
+ arp_add(ipaddr,hwaddr);
+
+ return 0;
+}
+
+#define IP_HDR_LENGTH 20
+#define ICMP_HDR_LENGTH 8
+#define PING_HDR_LENGTH (IP_HDR_LENGTH+ICMP_HDR_LENGTH)
+#define MAX_PKT_LENGTH 1500
+
+static int ui_cmd_ping(ui_cmdline_t *cmd,int argc,char *argv[])
+{
+ char *host;
+ uint8_t hostaddr[IP_ADDR_LEN];
+ int res;
+ int seq = 0;
+ int forever = 0;
+ int count = 1;
+ int ttlcount = 1;
+ int countreturned = 0;
+ int size = 56;
+ int flood = 0;
+ int retval = 0;
+ int exitonerror = 0;
+ int needexact = 0;
+ int noabort = 0;
+ char *x;
+
+ host = cmd_getarg(cmd,0);
+ if (!host) return -1;
+
+ if (cmd_sw_isset(cmd,"-t")) {
+ forever = 1;
+ }
+
+ /* Per traditional Unix usage, the size argument to ping is
+ the number of ICMP data bytes. The frame on the wire will also
+ include the ethernet, IP and ICMP headers (14, 20, and
+ 8 bytes respectively) and ethernet trailer (CRC, 4 bytes). */
+ if (cmd_sw_value(cmd,"-s",&x)) {
+ size = atoi(x);
+ if (size < 0)
+ size = 0;
+ if (size > MAX_PKT_LENGTH - PING_HDR_LENGTH)
+ size = MAX_PKT_LENGTH - PING_HDR_LENGTH;
+ }
+
+ if (cmd_sw_isset(cmd,"-f")) {
+ flood = 1;
+ forever = 1;
+ }
+
+ if (cmd_sw_isset(cmd,"-x")) {
+ exitonerror = 1;
+ }
+
+ if (cmd_sw_value(cmd,"-c",&x)) {
+ count = atoi(x);
+ ttlcount = count;
+ forever = 0;
+ }
+
+ if (cmd_sw_isset(cmd,"-A")) {
+ noabort = 1;
+ }
+
+ if (cmd_sw_isset(cmd,"-E")) {
+ needexact = 1;
+ }
+
+ if (isdigit(*host)) {
+ if (parseipaddr(host,hostaddr) < 0) {
+ xprintf("Invalid IP address: %s\n",host);
+ return -1;
+ }
+ }
+ else {
+ res = dns_lookup(host,hostaddr);
+ if (res < 0) {
+ return ui_showerror(res,"Could not resolve IP address of host %s",host);
+ }
+ }
+
+ if (forever) xprintf("Press ENTER to stop pinging\n");
+
+ do {
+ res = icmp_ping(hostaddr,seq,size);
+
+ if (res < 0) {
+ xprintf("Could not transmit echo request\n");
+ retval = CFE_ERR_IOERR;
+ break;
+ }
+ else if (res == 0) {
+ xprintf("%s (%I) is not responding (seq=%d)\n",host,hostaddr,seq);
+ retval = CFE_ERR_TIMEOUT;
+ if (exitonerror) break;
+ }
+ else {
+ countreturned++;
+ if (!flood || ((seq % 10000) == 0)) {
+ if (forever || (ttlcount > 1)) {
+ xprintf("%s (%I) is alive (seq=%d)\n",host,hostaddr,seq);
+ }
+ else xprintf("%s (%I) is alive\n",host,hostaddr);
+ }
+ }
+
+ if ((forever || (count > 1)) && !flood) {
+ if (res > 0) cfe_sleep(CFE_HZ);
+ }
+
+ seq++;
+ count--;
+
+ } while ((forever || (count > 0)) && (noabort || !console_status()));
+
+ xprintf("%s (%I): %d packets sent, %d received\n",host,hostaddr,
+ ttlcount-count,countreturned);
+ return (needexact ? (countreturned != ttlcount) : (countreturned == 0));
+}
+
+#endif