Exemplo n.º 1
0
U16 tnet_process_cmd (U8 *cmd, U8 *buf, U16 buflen, U32 *pvar) {
  /* This is a Telnet Client callback function to make a formatted output   */
  /* for 'stdout'. It returns the number of bytes written to the out buffer.*/
  /* Hi-bit of return value (len is or-ed with 0x8000) is a disconnect flag.*/
  /* Bit 14 (len is or-ed with 0x4000) is a repeat flag for the Tnet client.*/
  /* If this bit is set to 1, the system will call the 'tnet_process_cmd()' */
  /* again with parameter 'pvar' pointing to a 4-byte buffer. This buffer   */
  /* can be used for storing different status variables for this function.  */
  /* It is set to 0 by Telnet server on first call and is not altered by    */
  /* Telnet server for repeated calls. This function should NEVER write     */
  /* more than 'buflen' bytes to the buffer.                                */
  /* Parameters:                                                            */
  /*   cmd    - telnet received command string                              */
  /*   buf    - Telnet transmit buffer                                      */
  /*   buflen - length of this buffer (500-1400 bytes - depends on MSS)     */
  /*   pvar   - pointer to local storage buffer used for repeated loops     */
  /*            This is a U32 variable - size is 4 bytes. Value is:         */
  /*            - on 1st call = 0                                           */
  /*            - 2nd call    = as set by this function on first call       */
  U16 len = 0;

  /* Simple Command line parser */
  len = strlen ((const char *)cmd);
  
  if (tnet_ccmp (cmd, "RESET") == __TRUE) {
    /* 'RESET' command received */
	sys_Reset();
    return (len);
  }

  if (tnet_ccmp (cmd, "SPIF") == __TRUE) {
  	extern int dbg_SpifInfo(uint8_t *pBuf);
    return dbg_SpifInfo(buf);
  }

  if (tnet_ccmp (cmd, "BYE") == __TRUE) {
    /* 'BYE' command, send message and disconnect */
    len = str_copy (buf, "\r\nDisconnect...\r\n");
    /* Hi bit of return value is a disconnect flag */
    return (len | 0x8000);
  }

  if (tnet_ccmp (cmd, "TCPSTAT") == __TRUE) {
    /* Display a TCP status similar to that in HTTP_Demo example. */
    /* Here the local storage '*pvar' is initialized to 0 by Telnet Server.    */
    MYBUF(pvar)->id = 1;
    len = str_copy (buf, CLS);
    return (len | 0x4000);
  }

  /* Unknown command, display message */
  len = str_copy  (buf, "\r\n==> Unknown Command: ");
  len += str_copy (buf+len, cmd);
  return (len);
}
U16 cgi_func (U8 *env, U8 *buf, U16 buflen, U32 *pcgi) {
  /* This function is called by HTTP server script interpreter to make a    */
  /* formated output for 'stdout'. It returns the number of bytes written   */
  /* to the output buffer. Hi-bit of return value (len is or-ed with 0x8000)*/
  /* is a repeat flag for the system script interpreter. If this bit is set */
  /* to 1, the system will call the 'cgi_func()' again for the same script  */
  /* line with parameter 'pcgi' pointing to a 4-byte buffer. This buffer    */
  /* can be used for storing different status variables for this function.  */
  /* It is set to 0 by HTTP Server on first call and is not altered by      */
  /* HTTP server for repeated calls. This function should NEVER write more  */
  /* than 'buflen' bytes to the buffer.                                     */
  /* Parameters:                                                            */
  /*   env    - environment variable string                                 */
  /*   buf    - HTTP transmit buffer                                        */
  /*   buflen - length of this buffer (500-1400 bytes - depends on MSS)     */
  /*   pcgi   - pointer to session local buffer used for repeated loops     */
  /*            This is a U32 variable - size is 4 bytes. Value is:         */
  /*            - on 1st call = 0                                           */
  /*            - 2nd call    = as set by this function on first call       */
  TCP_INFO *tsoc;
  U32 len = 0;
  U8 id, *lang;
  static U32 adv;

  switch (env[0]) {
    /* Analyze the environment string. It is the script 'c' line starting */
    /* at position 2. What you write to the script file is returned here. */
    case 'a' :
      /* Network parameters - file 'network.cgi' */
      switch (env[2]) {
        case 'i':
          /* Write the local IP address. The format string is included */
          /* in environment string of the script line.                 */
          len = sprintf((char *)buf,(const char *)&env[4],LocM.IpAdr[0],
                        LocM.IpAdr[1],LocM.IpAdr[2],LocM.IpAdr[3]);
          break;
        case 'm':
          /* Write local Net mask. */
          len = sprintf((char *)buf,(const char *)&env[4],LocM.NetMask[0],
                        LocM.NetMask[1],LocM.NetMask[2],LocM.NetMask[3]);
          break;
        case 'g':
          /* Write default gateway address. */
          len = sprintf((char *)buf,(const char *)&env[4],LocM.DefGW[0],
                        LocM.DefGW[1],LocM.DefGW[2],LocM.DefGW[3]);
          break;
        case 'p':
          /* Write primary DNS server address. */
          len = sprintf((char *)buf,(const char *)&env[4],LocM.PriDNS[0],
                        LocM.PriDNS[1],LocM.PriDNS[2],LocM.PriDNS[3]);
          break;
        case 's':
          /* Write secondary DNS server address. */
          len = sprintf((char *)buf,(const char *)&env[4],LocM.SecDNS[0],
                        LocM.SecDNS[1],LocM.SecDNS[2],LocM.SecDNS[3]);
          break;
      }
      break;

    case 'b':
      /* LED control - file 'led.cgi' */
      if (env[2] == 'c') {
        /* Select Control */
        len = sprintf((char *)buf,(const char *)&env[4],LEDrun ? "" : "selected",
                                                        LEDrun ? "selected" : "");
        break;
      }
      /* LED CheckBoxes */
      id = env[2] - '0';
      if (id > 7) {
        id = 0;
      }
      id = 1 << id;
      len = sprintf((char *)buf,(const char *)&env[4],(P2 & id) ? "checked" : "");
      break;

    case 'c':
      /* TCP status - file 'tcp.cgi' */
      while ((len + 150) < buflen) {
        tsoc = &tcp_socket[MYBUF(pcgi)->xcnt];
        MYBUF(pcgi)->xcnt++;
        /* 'sprintf' format string is defined here. */
        len += sprintf((char *)(buf+len),"<tr align=\"center\">");
        if (tsoc->State <= TCP_STATE_CLOSED) {
          len += sprintf ((char *)(buf+len),
                          "<td>%d</td><td>%s</td><td>-</td><td>-</td>"
                          "<td>-</td><td>-</td></tr>\r\n",
                          MYBUF(pcgi)->xcnt,state[tsoc->State]);
        }
        else if (tsoc->State == TCP_STATE_LISTEN) {
          len += sprintf ((char *)(buf+len),
                          "<td>%d</td><td>%s</td><td>-</td><td>-</td>"
                          "<td>%d</td><td>-</td></tr>\r\n",
                          MYBUF(pcgi)->xcnt,state[tsoc->State],tsoc->LocPort);
        }
        else {
          len += sprintf ((char *)(buf+len),
                          "<td>%d</td><td>%s</td><td>%d.%d.%d.%d</td>"
                          "<td>%d</td><td>%d</td><td>%d</td></tr>\r\n",
                          MYBUF(pcgi)->xcnt,state[tsoc->State],
                          tsoc->RemIpAdr[0],tsoc->RemIpAdr[1],
                          tsoc->RemIpAdr[2],tsoc->RemIpAdr[3],
                          tsoc->RemPort,tsoc->LocPort,tsoc->AliveTimer);
        }
        /* Repeat for all TCP Sockets. */
        if (MYBUF(pcgi)->xcnt == tcp_NumSocks) {
          break;
        }
      }
      if (MYBUF(pcgi)->xcnt < tcp_NumSocks) {
        /* Hi bit is a repeat flag. */
        len |= 0x8000;
      }
      break;

    case 'd':
      /* System password - file 'system.cgi' */
      switch (env[2]) {
        case '1':
          len = sprintf((char *)buf,(const char *)&env[4],
                        http_EnAuth ? "Enabled" : "Disabled");
          break;
        case '2':
          len = sprintf((char *)buf,(const char *)&env[4],http_auth_passw);
          break;
      }
      break;

    case 'e':
      /* Browser Language - file 'language.cgi' */
      lang = http_get_lang();
      if (strcmp ((const char *)lang, "en") == 0) {
        lang = "English";
      }
      else if (strcmp ((const char *)lang, "en-us") == 0) {
        lang = "English USA";
      }
      else if (strcmp ((const char *)lang, "en-gb") == 0) {
        lang = "English GB";
      }
      else if (strcmp ((const char *)lang, "de") == 0) {
        lang = "German";
      }
      else if (strcmp ((const char *)lang, "de-ch") == 0) {
        lang = "German CH";
      }
      else if (strcmp ((const char *)lang, "de-at") == 0) {
        lang = "German AT";
      }
      else if (strcmp ((const char *)lang, "fr") == 0) {
        lang = "French";
      }
      else if (strcmp ((const char *)lang, "sl") == 0) {
        lang = "Slovene";
      }
      else {
        lang = "Unknown";
      }
      len = sprintf((char *)buf,(const char *)&env[2],lang,http_get_lang());
      break;

    case 'f':
      /* LCD Module control - file 'lcd.cgi' */
      switch (env[2]) {
        case '1':
          len = sprintf((char *)buf,(const char *)&env[4],lcd_text[0]);
          break;
        case '2':
          len = sprintf((char *)buf,(const char *)&env[4],lcd_text[1]);
          break;
      }
      break;

    case 'g':
      /* AD Input - file 'ad.cgi' */
      switch (env[2]) {
        case '1':
          adv = AD_in (0);
          len = sprintf((char *)buf,(const char *)&env[4],adv);
          break;
        case '2':
          len = sprintf((char *)buf,(const char *)&env[4],(float)adv*3.3/4096);
          break;
        case '3':
          adv = (adv * 100) / 4096;
          len = sprintf((char *)buf,(const char *)&env[4],adv);
          break;
      }
      break;

    case 'x':
      /* AD Input - xml file 'ad.cgx' */
      adv = AD_in (0);
      len = sprintf((char *)buf,(const char *)&env[1],adv);
      break;

    case 'y':
      /* Button state - xml file 'button.cgx' */
      len = sprintf((char *)buf,"<checkbox><id>button%c</id><on>%s</on></checkbox>",
                    env[1],(get_button () & (1 << (env[1]-'0'))) ? "true" : "false");
      break;
  }
  return ((U16)len);
}
Exemplo n.º 3
0
// Generate dynamic web data from a script line.
uint32_t cgi_script (const char *env, char *buf, uint32_t buflen, uint32_t *pcgi) {
  TCP_INFO *tsoc;
  const char *lang;
  uint32_t len = 0;
  uint8_t id;
  static uint32_t adv;

  switch (env[0]) {
    // Analyze a 'c' script line starting position 2
    case 'a' :
      // Network parameters from 'network.cgi'
      switch (env[2]) {
        case 'i':
          // Write local IP address
          len = sprintf (buf, &env[4], LocM.IpAdr[0], LocM.IpAdr[1],
                                       LocM.IpAdr[2], LocM.IpAdr[3]);
          break;
        case 'm':
          // Write local network mask
          len = sprintf (buf, &env[4], LocM.NetMask[0], LocM.NetMask[1],
                                       LocM.NetMask[2], LocM.NetMask[3]);
          break;
        case 'g':
          // Write default gateway IP address
          len = sprintf (buf, &env[4], LocM.DefGW[0], LocM.DefGW[1],
                                       LocM.DefGW[2], LocM.DefGW[3]);
          break;
        case 'p':
          // Write primary DNS server IP address
          len = sprintf (buf, &env[4], LocM.PriDNS[0], LocM.PriDNS[1],
                                       LocM.PriDNS[2], LocM.PriDNS[3]);
          break;
        case 's':
          // Write secondary DNS server IP address
          len = sprintf (buf, &env[4], LocM.SecDNS[0], LocM.SecDNS[1],
                                       LocM.SecDNS[2], LocM.SecDNS[3]);
          break;
      }
      break;

    case 'b':
      // LED control from 'led.cgi'
      if (env[2] == 'c') {
        // Select Control
        len = sprintf (buf, &env[4], LEDrun ?     ""     : "selected",
                                     LEDrun ? "selected" :    ""     );
        break;
      }
      // LED CheckBoxes
      id = env[2] - '0';
      if (id > 7) {
        id = 0;
      }
      id = 1 << id;
      len = sprintf (buf, &env[4], (P2 & id) ? "checked" : "");
      break;

    case 'c':
      // TCP status from 'tcp.cgi'
      while ((len + 150) < buflen) {
        tsoc = &tcp_socket[MYBUF(pcgi)->xcnt];
        MYBUF(pcgi)->xcnt++;
        // 'sprintf' format string is defined here
        len += sprintf (buf+len,   "<tr align=\"center\">");
        if (tsoc->State <= tcpStateCLOSED) {
          len += sprintf (buf+len, "<td>%d</td><td>%s</td><td>-</td><td>-</td>"
                                   "<td>-</td><td>-</td></tr>\r\n",
                                   MYBUF(pcgi)->xcnt,state[tsoc->State]);
        }
        else if (tsoc->State == tcpStateLISTEN) {
          len += sprintf (buf+len, "<td>%d</td><td>%s</td><td>-</td><td>-</td>"
                                   "<td>%d</td><td>-</td></tr>\r\n",
                                   MYBUF(pcgi)->xcnt, state[tsoc->State], tsoc->LocPort);
        }
        else {
          len += sprintf (buf+len, "<td>%d</td><td>%s</td><td>%d.%d.%d.%d</td>"
                                   "<td>%d</td><td>%d</td><td>%d</td></tr>\r\n",
                                   MYBUF(pcgi)->xcnt, state[tsoc->State],
                                   tsoc->RemIpAdr[0], tsoc->RemIpAdr[1],
                                   tsoc->RemIpAdr[2], tsoc->RemIpAdr[3],
                                   tsoc->RemPort, tsoc->LocPort, tsoc->AliveTimer);
        }
        // Repeat for all TCP Sockets
        if (MYBUF(pcgi)->xcnt == tcp_NumSocks) {
          break;
        }
      }
      if (MYBUF(pcgi)->xcnt < tcp_NumSocks) {
        // Hi bit is a repeat flag
        len |= (1u << 31);
      }
      break;

    case 'd':
      // System password from 'system.cgi'
      switch (env[2]) {
        case '1':
          len = sprintf (buf, &env[4], http_EnAuth ? "Enabled" : "Disabled");
          break;
        case '2':
          len = sprintf (buf, &env[4], http_auth_passw);
          break;
      }
      break;

    case 'e':
      // Browser Language from 'language.cgi'
      lang = http_server_get_lang ();
      if      (strncmp (lang, "en", 2) == 0) {
        lang = "English";
      }
      else if (strncmp (lang, "de", 2) == 0) {
        lang = "German";
      }
      else if (strncmp (lang, "fr", 2) == 0) {
        lang = "French";
      }
      else if (strncmp (lang, "sl", 2) == 0) {
        lang = "Slovene";
      }
      else {
        lang = "Unknown";
      }
      len = sprintf (buf, &env[2], lang, http_server_get_lang());
      break;

    case 'f':
      // LCD Module control from 'lcd.cgi'
      switch (env[2]) {
        case '1':
          len = sprintf (buf, &env[4], lcd_text[0]);
          break;
        case '2':
          len = sprintf (buf, &env[4], lcd_text[1]);
          break;
      }
      break;

    case 'g':
      // AD Input from 'ad.cgi'
      switch (env[2]) {
        case '1':
          adv = AD_in (0);
          len = sprintf (buf, &env[4], adv);
          break;
        case '2':
          len = sprintf (buf, &env[4], (float)adv*3.3f/4096);
          break;
        case '3':
          adv = (adv * 100) / 4096;
          len = sprintf (buf, &env[4], adv);
          break;
      }
      break;

    case 'x':
      // AD Input from 'ad.cgx'
      adv = AD_in (0);
      len = sprintf (buf, &env[1], adv);
      break;

    case 'y':
      // Button state from 'button.cgx'
      len = sprintf (buf, "<checkbox><id>button%c</id><on>%s</on></checkbox>",
                     env[1], (get_button () & (1 << (env[1]-'0'))) ? "true" : "false");
      break;
  }
  return (len);
}
Exemplo n.º 4
0
U16 tnet_process_cmd (U8 *cmd, U8 *buf, U16 buflen, U32 *pvar) {
  /* This is a Telnet Client callback function to make a formatted output   */
  /* for 'stdout'. It returns the number of bytes written to the out buffer.*/
  /* Hi-bit of return value (len is or-ed with 0x8000) is a disconnect flag.*/
  /* Bit 14 (len is or-ed with 0x4000) is a repeat flag for the Tnet client.*/
  /* If this bit is set to 1, the system will call the 'tnet_process_cmd()' */
  /* again with parameter 'pvar' pointing to a 4-byte buffer. This buffer   */
  /* can be used for storing different status variables for this function.  */
  /* It is set to 0 by Telnet server on first call and is not altered by    */
  /* Telnet server for repeated calls. This function should NEVER write     */
  /* more than 'buflen' bytes to the buffer.                                */
  /* Parameters:                                                            */
  /*   cmd    - telnet received command string                              */
  /*   buf    - Telnet transmit buffer                                      */
  /*   buflen - length of this buffer (500-1400 bytes - depends on MSS)     */
  /*   pvar   - pointer to local storage buffer used for repeated loops     */
  /*            This is a U32 variable - size is 4 bytes. Value is:         */
  /*            - on 1st call = 0                                           */
  /*            - 2nd call    = as set by this function on first call       */
  TCP_INFO *tsoc;
  REMOTEM rm;
  U32 val,ch,temp;
  U16 len = 0;

  switch (MYBUF(pvar)->id) {
    case 0:
      /* First call to this function, the value of '*pvar' is 0 */
      break;

    case 1:
      /* Repeated call, command 'MEAS' measurements display. */
      while (len < buflen-80) {
        /* Let's use as much of the buffer as possible. */
        /* This will produce less packets and speedup the transfer. */
        len += sprintf ((char *)(buf+len), "\r\n%4d", MYBUF(pvar)->idx);
        for (val = 0; val < 8; val++) {
          len += sprintf ((char *)(buf+len), "%7d", AD_in(val));
        }
        if (++MYBUF(pvar)->idx >= MYBUF(pvar)->nmax) {
          /* OK, we are done. */
          return (len);
        }
      }
      /* Request a repeated call, bit 14 is a repeat flag. */
      return (len | 0x4000);

    case 2:
      /* Repeated call, TCP status display. */
      while (len < buflen-80) {
        /* Let's use as much of the buffer as possible. */
        /* This will produce less packets and speedup the transfer. */
        if (MYBUF(pvar)->idx == 0) {
          len += str_copy (buf, (U8 *)tcp_stat);
        }
        tsoc = &tcp_socket[MYBUF(pvar)->idx];
        len += sprintf   ((char *)(buf+len), "\r\n%9d %10s  ", MYBUF(pvar)->idx, 
                          state[tsoc->State]);
        if (tsoc->State <= TCP_STATE_CLOSED) {
          len += sprintf ((char *)(buf+len),
                          "        -             -         -       -\r\n");
        }
        else if (tsoc->State == TCP_STATE_LISTEN) {
          len += sprintf ((char *)(buf+len),
                          "        -             -     %5d       -\r\n",
                          tsoc->LocPort);
        }
        else {
          /* First temporary print for alignment. */
          sprintf ((char *)(buf+len+16),"%d.%d.%d.%d",tsoc->RemIpAdr[0],
                tsoc->RemIpAdr[1],tsoc->RemIpAdr[2],tsoc->RemIpAdr[3]);
          len += sprintf ((char *)(buf+len),"%15s    %5d    %5d     %4d\r\n",
                          buf+len+16,tsoc->RemPort,tsoc->LocPort,tsoc->AliveTimer);
        }
        if (++MYBUF(pvar)->idx >= tcp_NumSocks) {
          /* OK, we are done, reset the index counter for next callback. */
          MYBUF(pvar)->idx = 0;
          /* Setup a callback delay. This function will be called again after    */
          /* delay has expired. It is set to 20 system ticks 20 * 100ms = 2 sec. */
          tnet_set_delay (20);
          break;
        }
      }
      /* Request a repeated call, bit 14 is a repeat flag. */
      return (len |= 0x4000);
  }

  /* Simple Command line parser */
  len = strlen ((const char *)cmd);
  if (tnet_ccmp (cmd, "LED") == __TRUE) {
    /* 'LED' command received */
    if (len >= 5) {
      sscanf ((const char *)(cmd+4),"%x", &val);
      LED_out (val);
      len = 0;
      if (LEDrun == __TRUE) {
        len = str_copy (buf," --> Running Lights OFF");
        LEDrun = __FALSE;
      }
      return (len);
    }
    len = 0;
    if (LEDrun == __FALSE) {
      len = str_copy (buf," --> Running Lights ON");
      LEDrun = __TRUE;
    }
    return (len);
  }
  if (tnet_ccmp (cmd, "ADIN") == __TRUE) {
    /* 'ADIN' command received */
    if (len >= 6) {
      sscanf ((const char *)(cmd+5),"%d",&ch);
      val = AD_in (ch);
      len = sprintf ((char *)buf,"\r\n ADIN %d = %d",ch,val);
      return (len);
    }
  }
  if (tnet_ccmp (cmd, "BYE") == __TRUE) {
    /* 'BYE' command, send message and disconnect */
    len = str_copy (buf, "\r\nDisconnect...\r\n");
    /* Hi bit of return value is a disconnect flag */
    return (len | 0x8000);
  }

  if (tnet_ccmp (cmd, "PASSW") == __TRUE && tnet_EnAuth) {
    /* Change the system password. */
    if (len == 5) {
      /* Disable password. */
      tnet_auth_passw[0] = 0;
    }
    else {
      mem_copy (&tnet_auth_passw, &cmd[6], 20);
    }
    len = sprintf ((char *)buf, "\r\n OK, New Password: \"%s\"",tnet_auth_passw);
    return (len);
  }

  if (tnet_ccmp (cmd, "PASSWD") == __TRUE && tnet_EnAuth) {
    /* Only display the current system password. */
    len = sprintf ((char *)buf, "\r\n System Password: \"%s\"",tnet_auth_passw);
    return (len);
  }

  if (tnet_ccmp (cmd, "MEAS") == __TRUE) {
    /* During the repeated call to this function, the 'cmd' buffer is locked,  */
    /* so we can use it for our temporary storage. Each Telnet session has its */
    /* own buffer of size 96 bytes. We can use 95 bytes, last one is not free. */
    /* Here the local storage '*pvar' is initialized to 0 by Telnet Server.    */
    MYBUF(pvar)->id = 1;
    if (len > 5) {
      /* We must be careful here, because data is overlaid. */
      sscanf ((const char *)&cmd[5], "%d", &temp);
      MYBUF(pvar)->nmax = temp;
    }
    len = str_copy (buf,(U8 *)meas_header);
    if (MYBUF(pvar)->nmax) {
      /* Bit 14 is a repeat flag. */
      len |= 0x4000;
    }
    return (len);
  }

  if (tnet_ccmp (cmd, "TCPSTAT") == __TRUE) {
    /* Display a TCP status similar to that in HTTP_Demo example. */
    /* Here the local storage '*pvar' is initialized to 0 by Telnet Server.    */
    MYBUF(pvar)->id = 2;
    len = str_copy (buf, CLS);
    return (len | 0x4000);
  }

  if (tnet_ccmp (cmd, "RINFO") == __TRUE) {
    /* Display Remote Machine IP and MAC address. */
    tnet_get_info (&rm);
    len  = sprintf ((char *)buf,"\r\n Remote IP : %d.%d.%d.%d",
                    rm.IpAdr[0],rm.IpAdr[1],rm.IpAdr[2],rm.IpAdr[3]);
    len += sprintf ((char *)(buf+len),
                    "\r\n Remote MAC: %02X-%02X-%02X-%02X-%02X-%02X",
                    rm.HwAdr[0],rm.HwAdr[1],rm.HwAdr[2],
                    rm.HwAdr[3],rm.HwAdr[4],rm.HwAdr[5]);
    return (len);
  }

  if (tnet_ccmp (cmd, "HELP") == __TRUE || tnet_ccmp (cmd, "?") == __TRUE) {
    /* 'HELP' command, display help text */
    len = str_copy (buf,(U8 *)tnet_help1);
    if (tnet_EnAuth) {
      len += str_copy (buf+len,(U8 *)tnet_help2);
    }
    len += str_copy (buf+len,(U8 *)tnet_help3);
    return (len);
  }
  /* Unknown command, display message */
  len = str_copy  (buf, "\r\n==> Unknown Command: ");
  len += str_copy (buf+len, cmd);
  return (len);
}