3
0
Fork 0
xnode/xnode-base/XnodeBaseNetwork.cpp
2022-11-13 01:46:38 +01:00

626 lines
19 KiB
C++

#include <XnodeBaseNetwork.h>
const char pmNetworkChipBoot[] PROGMEM = "Init eth0";
const char pmNetworkChipError[] PROGMEM = "ERR: No chip";
const char pmNetworkLinkError[] PROGMEM = "ERR: No link";
const char pmNetworkStaticBoot[] PROGMEM = "Static IP";
const char pmNetworkDhcpBoot[] PROGMEM = "Request dhcp";
const char pmNetworkDhcpDone[] PROGMEM = "dhcp done";
const char pmNetworkDhcpError[] PROGMEM = "ERR: dhcp failed";
const char pmNetworkDnsLookup[] PROGMEM = "Lookup dns";
const char pmNetworkResultError[] PROGMEM = "# Invalid result:0x";
const char pmNetworkResultPing[] PROGMEM = "Server replied";
const char pmNetworkUsePrefix[] PROGMEM = "eth0_";
const char pmNetworkConfigInfo[] PROGMEM = "net_info";
const char pmNetworkConfigInfoEth0[] PROGMEM = "net_info_eth0";
const char pmNetworkConfigMac[] PROGMEM = "net_mac";
const char pmNetworkConfigIp[] PROGMEM = "net_ip";
const char pmNetworkConfigMask[] PROGMEM = "net_mask";
const char pmNetworkConfigGate[] PROGMEM = "net_gate";
const char pmNetworkConfigDns[] PROGMEM = "net_dns";
const char pmNetworkConfigKey[] PROGMEM = "net_key";
const char pmNetworkConfigId[] PROGMEM = "net_id";
const char pmNetworkServerHost[] PROGMEM = "net_srv_host";
const char pmNetworkServerIp[] PROGMEM = "net_srv_ip";
const char pmNetworkServerLookup[] PROGMEM = "net_srv_lup";
const char pmNetworkServer[] PROGMEM = NET_XNODE_HOST;
const char pmNetworkUrlPost[] PROGMEM = NET_URL_POST;
const char pmNetworkUrlParaPostType[] PROGMEM = NET_URL_PARA_POST_TYPE;
const char pmNetworkUrlParaReqCnt[] PROGMEM = NET_URL_PARA_REQ_CNT;
const char pmNetworkUrlParaNetId[] PROGMEM = NET_URL_PARA_NET_ID;
const char pmNetworkUrlParaNodeData[] PROGMEM = NET_URL_PARA_NODE_DATA;
const char pmNetworkUrlParaNodeNumber[] PROGMEM = NET_URL_PARA_NODE_NUMBER;
const char pmNetworkInfoTXOpen[] PROGMEM = "net_tx_open";
const char pmNetworkInfoTX[] PROGMEM = "net_tx";
const char pmNetworkInfoRX[] PROGMEM = "net_rx";
const char pmNetworkPing[] PROGMEM = "net_ping";
unsigned long net_ping_boot_timer = ZERO;
unsigned long net_ping_host_timer = ZERO;
unsigned long net_dhcp_retry_timer = ZERO;
unsigned long net_dns_lookup_timer = ZERO;
uint8_t net_status_eth = ZERO;
uint8_t net_status_ip = ZERO;
uint8_t net_status_dns = ZERO;
uint8_t net_status_data = ZERO;
uint8_t net_status_ping = ZERO;
uint8_t net_status_reply = ZERO;
uint8_t net_tx_open = ZERO;
unsigned long net_tx = ZERO;
unsigned long net_rx = ZERO;
char line_buf[128];
#define ETH_BUFFER_SIZE 450
byte Ethernet::buffer[ETH_BUFFER_SIZE];
Stash stash;
byte stashStart;
byte stashSession;
XnodeBaseNetwork XBNetwork;
void XnodeBaseNetwork::begin() {
XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_ON);
setupChip();
setupIp();
XSerial.printCommentLineP(pmNetworkDnsLookup);
XSerial.executeCommandP(pmNetworkServerLookup);
XSerial.executeCommandP(pmNetworkConfigInfo);
XSerial.executeCommandP(pmNetworkConfigInfoEth0);
unsigned long time = millis();
net_dhcp_retry_timer = time + (unsigned long) NET_DHCP_RETRY_TIME;
net_dns_lookup_timer = time + (unsigned long) NET_DNS_LOOKUP_TIME;
net_ping_boot_timer = time + (unsigned long) NET_PING_BOOT_TIME;
net_ping_host_timer = time + (unsigned long) NET_PING_HOST_TIME;
XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_OFF);
}
void XnodeBaseNetwork::loop() {
if (net_status_eth != ZERO) {
return; // no chip
}
loopAutoSetup(); // auto dhcp and dns refresh
if (net_status_ip != ZERO || net_status_dns != ZERO) {
return; // no ip or dns
}
ether.packetLoop(ether.packetReceive());
loopDataRX(); // rx first so that on tx-req packetLoop is runned first before RX code.
loopDataTX();
loopPingBoot();
loopPingHost();
}
// prev version needed about ~32 requests before network is working, now it works direct but we keep ping.
void XnodeBaseNetwork::loopPingBoot() {
if (net_status_ping == ONE) {
return;
}
unsigned long time = millis();
if (time < net_ping_boot_timer) {
return; // wait
}
net_ping_boot_timer = time + (unsigned long) NET_PING_BOOT_TIME;
if (net_status_reply == ZERO) {
line_buf[ZERO] = ZERO;
sendPing(); // keep sending ping requests.
return;
}
if (net_status_ping == ZERO) {
XSerial.print(CHAR_NEWLINE);// new line bacause the dot progress bar
XSerial.printCommentLineP(pmNetworkResultPing); // let user know network is up.
XSerial.printPromt();
net_tx_open = ZERO; // reset open request counter
}
net_status_ping = ONE+ONE; // print once
if (XBHardware.config.net_key.u8[ZERO] == ZERO) {
sendInit(); // send init request.
net_ping_boot_timer += (unsigned long) NET_PING_BOOT_TIME; // add extra wait time
return;
}
net_status_ping = ONE; // never run this function again.
}
void XnodeBaseNetwork::loopPingHost() {
if (millis() < net_ping_host_timer) {
return; // wait
}
sendPing();
net_ping_host_timer = millis() + (unsigned long) NET_PING_HOST_TIME;
}
void XnodeBaseNetwork::xxteaEncrypt(unsigned long v[2]) {
unsigned int i;
unsigned long v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
for (i=0; i < XXTEA_NUM_ROUNDS; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]);
}
v[0]=v0; v[1]=v1;
}
void XnodeBaseNetwork::xxteaDecrypt(unsigned long v[2]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*XXTEA_NUM_ROUNDS;
for (i=0; i < XXTEA_NUM_ROUNDS; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
int XnodeBaseNetwork::parseReplyData(word off) {
memset(line_buf, NULL, sizeof(line_buf));
if (off != 0) {
uint16_t pos = off;
int line_pos = 0;
// Skip over header until data part is found
while (Ethernet::buffer[pos]) {
if (Ethernet::buffer[pos - 1] == '\n' && Ethernet::buffer[pos] == '\r') {
break;
}
pos++;
}
pos += 2;
while (Ethernet::buffer[pos]) {
if (line_pos < 49) {
line_buf[line_pos] = Ethernet::buffer[pos];
line_pos++;
} else {
break;
}
pos++;
}
line_buf[line_pos] = '\0';
return line_pos;
}
return 0;
}
void XnodeBaseNetwork::sendStart(char postType) {
if (stashSession != ZERO) {
int maxWait = 100;
while (stashSession != ZERO) {
loop();
maxWait--;
if (maxWait == ZERO) {
break;
}
}
#ifdef DEBUG_NETWORK
if (stashSession != ZERO) {
Serial.println(F("#D kill prev tcp req"));
}
#endif
//return; // data is already sending (TODO: move ??)
}
stashStart = stash.create();
stash.print(XUtil.UNPSTR(pmNetworkUrlParaPostType));
stash.print(postType);
stash.print(XUtil.UNPSTR(pmNetworkUrlParaReqCnt));
stash.print(net_tx++);
stash.print(XUtil.UNPSTR(pmNetworkUrlParaNetId));
for (byte i = ZERO; i < NET_BYTE_NET_ID_SIZE; ++i) {
byte data = XBHardware.config.net_id[i];
if (data<0xF) {
stash.print(ZERO); // extra zero to have fixed length hex string
}
stash.print(data, HEX);
}
}
void XnodeBaseNetwork::sendPing() {
sendStart(NET_URL_PT_PING);
net_status_data = NET_URL_PT_PING;
}
void XnodeBaseNetwork::sendInit() {
#ifdef DEBUG_NETWORK
Serial.println(F("#D req init"));
#endif
sendStart(NET_URL_PT_INIT);
net_status_data = NET_URL_PT_INIT;
}
NetKey x_data;
void XnodeBaseNetwork::sendNodeData(byte senderId, char* data) {
sendStart(NET_URL_PT_DATA);
stash.print(XUtil.UNPSTR(pmNetworkUrlParaNodeNumber));
stash.print((int) senderId);
stash.print(XUtil.UNPSTR(pmNetworkUrlParaNodeData));
char* dstring = data;
while (*dstring != 0) {
char value = *dstring;
dstring++;
stash.print(value);
}
/*
byte i = 0;
char* dstring = data;
while (*dstring != 0) {
x_data.u8[i] = *dstring;
dstring++;
i++;
if (i==8) {
i = 0;
xxteaEncrypt(x_data.u32);
for (byte i = 0; i < 8; ++i) {
char value = x_data.u8[i];
if (value == 0) {
stash.print('00');
continue;
}
if (value <= 0xF) {
stash.print('0');
}
stash.print(value,HEX);
}
}
}
while(i < 8) {
x_data.u8[i] = 0;
i++;
}
xxteaEncrypt(x_data.u32);
for (byte i = 0; i < 8; ++i) {
char value = x_data.u8[i];
if (value == 0) {
stash.print('00');
continue;
}
if (value <= 0xF) {
stash.print('0');
}
stash.print(value,HEX);
}
*/
net_status_data = NET_URL_PT_DATA;
}
void XnodeBaseNetwork::loopDataTX() {
if (net_status_data == ZERO) {
return; // no data to send
}
if (!ether.isLinkUp()) {
if (net_status_ip == ZERO) {
XSerial.printCommentLineP(pmNetworkLinkError);
}
net_status_ip = ONE;
return; // link down; request new ip when link gets up.
}
XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_ON);
#ifdef DEBUG_NETWORK
Serial.print(F("#D sendHttp pt="));
Serial.print((char)net_status_data);
Serial.print(F(" size="));
Serial.println((char)stash.size(),DEC);
#endif
stash.save();
Stash::prepare(PSTR("POST http://$F/$F HTTP/1.1" "\r\n"
"Host: $F" "\r\n"
"Cache-Control: no-cache" "\r\n"
"Content-type: application/x-www-form-urlencoded;\r\n"
"Accept: application/xhtml+xml" "\r\n"
"Content-Length: $D" "\r\n"
"\r\n"
"$H"), pmNetworkServer, pmNetworkUrlPost, pmNetworkServer, stash.size(), stashStart);
net_tx_open++;
net_status_data = ZERO;
stashSession = ether.tcpSend(); // releases also stash buf
//stash.release();
}
void XnodeBaseNetwork::loopDataRX() {
if (stashSession == ZERO) {
return; // no reply to search for
}
const char* msgStart = ether.tcpReply(stashSession);
if (msgStart == ZERO) {
#ifdef DEBUG_NETWORK
Serial.println(F("#D wait tcpReply"));
#endif
delay(100);
return; // no reply yet
}
net_rx++;
stashSession = ZERO;
parseReplyData((int) *msgStart);
handleServerResult();
XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_OFF);
}
void XnodeBaseNetwork::handleServerResult() {
if (line_buf[ZERO] != NET_URL_RESULT_OK) {
XSerial.printCharP(pmNetworkResultError);
Serial.print(line_buf[ZERO], HEX); // TODO: check
#ifdef DEBUG_NETWORK
Serial.print(CHAR_SPACE);
for (int i=0;i<10;i++) {
if (line_buf[i] != ZERO) {
Serial.print(line_buf[i]);
}
}
#endif
XSerial.print(CHAR_NEWLINE);
return;
}
net_tx_open--; // valid result
net_status_reply = ONE; // we have reply
if (line_buf[ONE] == ZERO) {
return; // Only X returns so nop.
}
if (line_buf[ONE] == NET_URL_PT_INIT) {
XSystem.executeCommand(line_buf + ONE + ONE,true); // skip Xi chars
loop(); // Else we miss most of the time the second init request.
loop(); // an other extra to be sure we done miss the second request.
sendInit(); // request next init command
return;
}
if (line_buf[ONE] == NET_URL_RESULT_OK) {
XSystem.executeCommand(line_buf + ONE + ONE,true); // skip XX chars
loop();
loop();
sendNodeData(RF_BASE_NODE_ID,XSystem.replyBuffer); // send reply as
}
}
bool XnodeBaseNetwork::isUp() {
return ZERO == (net_status_eth + net_status_ip + net_status_dns);
}
void XnodeBaseNetwork::loopAutoSetup() {
unsigned long time = millis();
// auto dhcp
if (net_status_ip == ONE) {
if (time < net_dhcp_retry_timer) {
return; // wait
}
net_dhcp_retry_timer = millis() + (unsigned long) NET_DHCP_RETRY_TIME;
setupIp();
if (net_status_ip == ONE) {
return; // failed dhcp
}
net_status_dns = ONE; // when link plugs in later
net_dns_lookup_timer = ONE; // then do direct dns lookup
}
// auto dns
if (net_status_dns == ONE) {
if (time < net_dns_lookup_timer) {
return; // wait
}
net_dns_lookup_timer = time + (unsigned long) NET_DNS_LOOKUP_TIME;
XSerial.executeCommandP(pmNetworkServerLookup);
}
// auto dns refresh
if (net_status_dns == ZERO && time > net_dns_lookup_timer) {
net_status_dns = ONE;
}
}
// FIXME: without chip it takes 3 watchdog reboots before no chip result ?? (prev lib version)
void XnodeBaseNetwork::setupChip() {
XSerial.printCommentLineP(pmNetworkChipBoot);
if (ether.begin(sizeof Ethernet::buffer, XBHardware.config.net_mac, HW_PIN_SPI_ETH0_CS) == ZERO) {
XSerial.printCommentLineP(pmNetworkChipError);
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_BLINK);
net_status_eth = ONE;
return;
}
ether.disableBroadcast();
ether.disableMulticast();
delay(100); // needed for link isLinkUp to return valid value.
}
void XnodeBaseNetwork::setupIp() {
net_status_ip = ZERO;
if (net_status_eth != ZERO) {
return; // no chip
}
if (!ether.isLinkUp()) {
net_status_ip = ONE; // do again
XSerial.printCommentLineP(pmNetworkLinkError);
return;
}
// Setup static if ip is given.
if (XBHardware.config.net_ip[ZERO] != ZERO) {
XSerial.printCommentLineP(pmNetworkStaticBoot);
ether.staticSetup(XBHardware.config.net_ip, XBHardware.config.net_gate, XBHardware.config.net_dns);
ether.copyIp(ether.netmask, XBHardware.config.net_mask);
return;
}
XSerial.printCommentLineP(pmNetworkDhcpBoot);
wdt_disable();
if (!ether.dhcpSetup()) {
net_status_ip = ONE; // do again
XSerial.printCommentLineP(pmNetworkDhcpError);
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_ON); // TODO: fix led blinking on timer int.
} else {
XSerial.printCommentLineP(pmNetworkDhcpDone);
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_OFF); // set led off after recovery
}
wdt_enable(WDT_TIMEOUT); // no link or no dhcp will take long timeout ~30s
#ifdef DEBUG_NET_GATE
if (net_status_ip == ZERO) {
byte debug_gate[NET_BYTE_IP_SIZE] = DEBUG_NET_GATE; // transparent http proxy network config.
ether.copyIp(ether.gwip, debug_gate);
Serial.println(F("#D Used debug gate ip"));
}
#endif
}
void XnodeBaseNetwork::cmdDnsLookup() {
net_status_dns = ZERO;
if (net_status_eth != ZERO) {
return; // no chip
}
if (net_status_ip != ZERO) {
net_status_dns = ONE;
return; // no ip
}
#ifdef DEBUG_NET_HISIP
byte debug_hisip[NET_BYTE_IP_SIZE] = DEBUG_NET_HISIP;
ether.copyIp(ether.hisip, debug_hisip);
Serial.println(F("#D Used debug dns ip"));
return;
#endif
wdt_disable();
if (!ether.dnsLookup(pmNetworkServer)) {
net_status_dns = ONE;
XSystem.buildReplyPValue(pmNetworkServerLookup,ZERO);
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_BLINK);
} else {
XSystem.buildReplyPValue(pmNetworkServerLookup,ONE);
XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_OFF);
}
wdt_enable (WDT_TIMEOUT);
}
void XnodeBaseNetwork::cmdInfoEth0() {
// Print currently used config
XSystem.buildReplyCharP(pmNetworkUsePrefix);
XSystem.buildReplyPValueIP(pmNetworkConfigIp, ether.myip);
XSystem.buildReplyCharP(pmNetworkUsePrefix);
XSystem.buildReplyPValueIP(pmNetworkConfigMask, ether.netmask);
XSystem.buildReplyCharP(pmNetworkUsePrefix);
XSystem.buildReplyPValueIP(pmNetworkConfigGate, ether.gwip);
XSystem.buildReplyCharP(pmNetworkUsePrefix);
XSystem.buildReplyPValueIP(pmNetworkConfigDns, ether.dnsip);
XSystem.buildReplyCharP(pmNetworkUsePrefix);
XSystem.buildReplyPValueByteA(pmNetworkConfigMac,ether.mymac, NET_BYTE_MAC_SIZE);
}
void XnodeBaseNetwork::cmdInfo() {
// Print server value and lookup
XSystem.buildReplyPValueP(pmNetworkServerHost,pmNetworkServer);
XSystem.buildReplyPValueIP(pmNetworkServerIp, ether.hisip);
// Print config
XSystem.buildReplyPValueByteA(pmNetworkConfigMac,XBHardware.config.net_mac, NET_BYTE_MAC_SIZE);
XSystem.buildReplyPValueIP(pmNetworkConfigIp, XBHardware.config.net_ip);
XSystem.buildReplyPValueIP(pmNetworkConfigMask, XBHardware.config.net_mask);
XSystem.buildReplyPValueIP(pmNetworkConfigGate, XBHardware.config.net_gate);
XSystem.buildReplyPValueIP(pmNetworkConfigDns, XBHardware.config.net_dns);
XSystem.buildReplyPValueByteA(pmNetworkConfigKey,XBHardware.config.net_key.u8, NET_BYTE_NET_KEY_SIZE);
XSystem.buildReplyPValueByteA(pmNetworkConfigId,XBHardware.config.net_id, NET_BYTE_NET_ID_SIZE);
XSystem.buildReplyPValue(pmNetworkInfoTXOpen, (int) net_tx_open);
XSystem.buildReplyPValue(pmNetworkInfoTX, net_tx);
XSystem.buildReplyPValue(pmNetworkInfoRX, net_rx);
}
void XnodeBaseNetwork::parseCommandIp(const char* pmName, char** args, byte* ip_conf) {
ether.parseIp(ip_conf, args[ZERO]);
XSystem.buildReplyPValueIP(pmName, ip_conf);
XSystem.configSave(); // auto save on change
}
void XnodeBaseNetwork::systemModuleCommandList() {
XSystem.buildReplyCommandListP(pmNetworkConfigInfo);
XSystem.buildReplyCommandListP(pmNetworkConfigInfoEth0);
XSystem.buildReplyCommandListP(pmNetworkConfigMac);
XSystem.buildReplyCommandListP(pmNetworkConfigIp);
XSystem.buildReplyCommandListP(pmNetworkConfigMask);
XSystem.buildReplyCommandListP(pmNetworkConfigGate);
XSystem.buildReplyCommandListP(pmNetworkConfigDns);
XSystem.buildReplyCommandListP(pmNetworkPing);
XSystem.buildReplyCommandListP(pmNetworkServerLookup);
#ifdef DEBUG_NETWORK
XSystem.buildReplyCommandListP(pmNetworkConfigId); // keep secret that these cmd work
XSystem.buildReplyCommandListP(pmNetworkConfigKey); // for init over network with this.
#endif
}
bool XnodeBaseNetwork::systemModuleCommandExecute(char* cmd, char** args) {
if (XUtil.strcmpP(cmd, pmNetworkConfigInfo) == ZERO) {
cmdInfo();
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkConfigInfoEth0) == ZERO) {
cmdInfoEth0();
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkConfigId) == ZERO) {
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
return true;
}
XUtil.charsToByteA(args[ZERO],XBHardware.config.net_id, NET_BYTE_NET_ID_SIZE);
XSystem.buildReplyPValueByteA(pmNetworkConfigId,XBHardware.config.net_id,NET_BYTE_NET_ID_SIZE);
XSystem.configSave();
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkConfigKey) == ZERO) {
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
return true;
}
XUtil.charsToByteA(args[ZERO],XBHardware.config.net_key.u8, NET_BYTE_NET_KEY_SIZE);
XSystem.buildReplyPValueByteA(pmNetworkConfigKey,XBHardware.config.net_key.u8,NET_BYTE_NET_KEY_SIZE);
XSystem.configSave();
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkConfigMac) == ZERO) {
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
return true;
}
XUtil.charsToByteA(args[ZERO],XBHardware.config.net_mac, NET_BYTE_MAC_SIZE);
XSystem.buildReplyPValueByteA(pmNetworkConfigMac,XBHardware.config.net_mac, NET_BYTE_MAC_SIZE);
XSystem.configSave();
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkConfigIp) == ZERO) {
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
return true;
}
parseCommandIp(pmNetworkConfigIp, args, XBHardware.config.net_ip);
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkConfigMask) == ZERO) {
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
return true;
}
parseCommandIp(pmNetworkConfigMask, args, XBHardware.config.net_mask);
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkConfigGate) == ZERO) {
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
return true;
}
parseCommandIp(pmNetworkConfigGate, args, XBHardware.config.net_gate);
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkConfigDns) == ZERO) {
if (XSystem.buildReplyCommandArgumentError(cmd, args)) {
return true;
}
parseCommandIp(pmNetworkConfigDns, args, XBHardware.config.net_dns);
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkPing) == ZERO) {
sendPing();
return true;
} else if (XUtil.strcmpP(cmd, pmNetworkServerLookup) == ZERO) {
cmdDnsLookup();
return true;
}
return false;
}