Esempio n. 1
0
void handle_synchro_timeout(socket_internal_t *current_socket)
	{
	msg_t send;
	if (thread_getstatus(current_socket->recv_pid) == STATUS_RECEIVE_BLOCKED)
		{
		if ((current_socket->socket_values.tcp_control.no_of_retries == 0) &&
				(timex_sub(vtimer_now(), current_socket->socket_values.tcp_control.last_packet_time).microseconds >
				TCP_SYN_INITIAL_TIMEOUT))
			{
			current_socket->socket_values.tcp_control.no_of_retries++;
			net_msg_send(&send, current_socket->recv_pid, 0, TCP_RETRY);
//			printf("FIRST RETRY!\n");
			}
		else if ((current_socket->socket_values.tcp_control.no_of_retries > 0) &&
				(timex_sub(vtimer_now(), current_socket->socket_values.tcp_control.last_packet_time).microseconds >
				(current_socket->socket_values.tcp_control.no_of_retries * TCP_SYN_TIMEOUT + TCP_SYN_INITIAL_TIMEOUT)))
			{
			current_socket->socket_values.tcp_control.no_of_retries++;
			if (current_socket->socket_values.tcp_control.no_of_retries > TCP_MAX_SYN_RETRIES)
				{
				net_msg_send(&send, current_socket->recv_pid, 0, TCP_TIMEOUT);
//				printf("TCP SYN TIMEOUT!!\n");
				}
			else
				{
				net_msg_send(&send, current_socket->recv_pid, 0, TCP_RETRY);
//				printf("NEXT RETRY!\n");
				}
			}
		}
	}
Esempio n. 2
0
void handle_synchro_timeout(socket_internal_t *current_socket)
{
    msg_t send;

    if (thread_getstatus(current_socket->recv_pid) == STATUS_RECEIVE_BLOCKED) {
        timex_t now;
        vtimer_now(&now);

        if ((current_socket->socket_values.tcp_control.no_of_retries == 0) &&
            (timex_uint64(timex_sub(now, current_socket->socket_values.tcp_control.last_packet_time)) > TCP_SYN_INITIAL_TIMEOUT)) {
            current_socket->socket_values.tcp_control.no_of_retries++;
            net_msg_send(&send, current_socket->recv_pid, 0, TCP_RETRY);
        }
        else if ((current_socket->socket_values.tcp_control.no_of_retries > 0) &&
                 (timex_uint64(timex_sub(now, current_socket->socket_values.tcp_control.last_packet_time)) >
                  (current_socket->socket_values.tcp_control.no_of_retries *
                   TCP_SYN_TIMEOUT + TCP_SYN_INITIAL_TIMEOUT))) {
            current_socket->socket_values.tcp_control.no_of_retries++;

            if (current_socket->socket_values.tcp_control.no_of_retries >
                TCP_MAX_SYN_RETRIES) {
                net_msg_send(&send, current_socket->recv_pid, 0, TCP_TIMEOUT);
            }
            else {
                net_msg_send(&send, current_socket->recv_pid, 0, TCP_RETRY);
            }
        }
    }
}
Esempio n. 3
0
void handle_established(socket_internal_t *current_socket)
	{
	msg_t send;
	double current_timeout = current_socket->socket_values.tcp_control.rto;
	if (current_timeout < SECOND)
		{
		current_timeout = SECOND;
		}
	uint8_t i;
	if ((current_socket->socket_values.tcp_control.send_nxt > current_socket->socket_values.tcp_control.send_una) &&
			(thread_getstatus(current_socket->send_pid) == STATUS_RECEIVE_BLOCKED))
		{
		for(i = 0; i < current_socket->socket_values.tcp_control.no_of_retries; i++)
			{
			current_timeout *= 2;
			}
		if (current_timeout > TCP_ACK_MAX_TIMEOUT)
			{
			net_msg_send(&send, current_socket->send_pid, 0, TCP_TIMEOUT);
//			printf("GOT NO ACK: TIMEOUT!\n");
			}
		else if (timex_sub(vtimer_now(), current_socket->socket_values.tcp_control.last_packet_time).microseconds >
					current_timeout)
			{
//			printReasBuffers();
			current_socket->socket_values.tcp_control.no_of_retries++;
			net_msg_send(&send, current_socket->send_pid, 0, TCP_RETRY);
//			printf("GOT NO ACK YET, %i. RETRY! Now: %lu  Before: %lu, Diff: %lu, Cur Timeout: %f\n", current_socket->socket_values.tcp_control.no_of_retries,
//					vtimer_now().microseconds, current_socket->socket_values.tcp_control.last_packet_time.microseconds,
//					vtimer_now().microseconds - current_socket->socket_values.tcp_control.last_packet_time.microseconds,
//					current_timeout);
			}
		}
	}
Esempio n. 4
0
void handle_established(socket_internal_t *current_socket)
{
    msg_t send;
    double current_timeout = current_socket->socket_values.tcp_control.rto;

    if (current_timeout < SECOND) {
        current_timeout = SECOND;
    }

    uint8_t i;

    if ((current_socket->socket_values.tcp_control.send_nxt >
         current_socket->socket_values.tcp_control.send_una) &&
        (thread_getstatus(current_socket->send_pid) == STATUS_RECEIVE_BLOCKED)) {
        for (i = 0; i < current_socket->socket_values.tcp_control.no_of_retries;
             i++) {
            current_timeout *= 2;
        }

        timex_t now;
        vtimer_now(&now);

        if (current_timeout > TCP_ACK_MAX_TIMEOUT) {
            net_msg_send(&send, current_socket->send_pid, 0, TCP_TIMEOUT);
        }
        else if (timex_uint64(timex_sub(now, current_socket->socket_values.tcp_control.last_packet_time)) >
                 current_timeout) {
            current_socket->socket_values.tcp_control.no_of_retries++;
            net_msg_send(&send, current_socket->send_pid, 0, TCP_RETRY);
        }
    }
}
// Receive a NET msg from the OVMS server
void net_msg_in(char* msg)
  {
  int k;

  if (net_msg_serverok == 0)
    {
    if (memcmppgm2ram(msg, (char const rom far*)"MP-S 0 ", 7) == 0)
      {
      net_msg_server_welcome(msg+7);
      }
    return; // otherwise ignore it
    }

  // Ok, we've got an encrypted message waiting for work.
  // The following is a nasty hack because base64decode doesn't like incoming
  // messages of length divisible by 4, and is really expecting a CRLF
  // terminated string, so we give it one...
  strcatpgm2ram(msg,(char const rom far*)"\r\n");
  k = base64decode(msg,net_scratchpad);
  RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, k);
  if (memcmppgm2ram(net_scratchpad, (char const rom far*)"MP-0 ", 5) == 0)
    {
    msg = net_scratchpad+5;
    switch (*msg)
      {
      case 'A': // PING
        strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 a");
        if (net_msg_sendpending==0)
          {
          net_msg_start();
          net_msg_encode_puts();
          net_msg_send();
          }
        break;
      case 'Z': // PEER connection
        if (msg[1] != '0')
          {
          net_apps_connected = 1;
          if (net_msg_sendpending==0)
            {
            net_msg_start();
            net_msg_stat();
            net_msg_gps();
            net_msg_tpms();
            net_msg_firmware();
            net_msg_environment();
            net_msg_send();
            }
          }
        else
          {
          net_apps_connected = 0;
          }
        break;
      }
    }
  }
////////////////////////////////////////////////////////////////////////
// net_state_ticker60()
// State Model: Per-minute ticker
// This function is called approximately once per minute (since state
// was first entered), and gives the state a timeslice for activity.
//
void net_state_ticker60(void)
  {
  switch (net_state)
    {
    case NET_STATE_READY:
      if (net_msg_sendpending>0)
        {
        net_granular_tick -= 5; // Try again in 5 seconds...
        return;
        }
      if ((net_link==1)&&(net_apps_connected>0))
        {
        net_msg_start();
        net_msg_stat();
        net_msg_gps();
        net_msg_tpms();
        net_msg_environment();
        net_msg_send();
        }
      net_state_vchar = net_state_vchar ^ 1;
      delay100(2);
      net_puts_rom(NET_CREG_CIPSTATUS);
      break;
    }
  }
Esempio n. 7
0
void handle_tcp_syn_packet(ipv6_hdr_t *ipv6_header, tcp_hdr_t *tcp_header,
                           socket_internal_t *tcp_socket)
{
    msg_t m_send_tcp;

    if (tcp_socket->socket_values.tcp_control.state == TCP_LISTEN) {
        socket_internal_t *new_socket = new_tcp_queued_socket(ipv6_header,
                                        tcp_header);

        if (new_socket != NULL) {
#ifdef TCP_HC
            update_tcp_hc_context(true, new_socket, tcp_header);
#endif
            /* notify socket function destiny_socket_accept(..) that a new
             * connection request has arrived. No need to wait for an answer
             * because the server destiny_socket_accept() function isnt reading
             * from anything other than the queued sockets */
            net_msg_send(&m_send_tcp, tcp_socket->recv_pid, 0, TCP_SYN);
        }
        else {
            printf("Dropped TCP SYN Message because an error occured while "\
                   "requesting a new queued socket!\n");
        }
    }
    else {
        printf("Dropped TCP SYN Message because socket was not in state TCP_LISTEN!");
    }
}
Esempio n. 8
0
void handle_tcp_ack_packet(ipv6_hdr_t *ipv6_header, tcp_hdr_t *tcp_header,
                           socket_internal_t *tcp_socket)
{
    msg_t m_recv_tcp, m_send_tcp;
    uint8_t target_pid;

    if (tcp_socket->socket_values.tcp_control.state == TCP_LAST_ACK) {
        target_pid = tcp_socket->recv_pid;
        close_socket(tcp_socket);
        msg_send(&m_send_tcp, target_pid, 0);
        return;
    }
    else if (tcp_socket->socket_values.tcp_control.state == TCP_CLOSING) {
        msg_send(&m_send_tcp, tcp_socket->recv_pid, 0);
        msg_send(&m_send_tcp, tcp_socket->send_pid, 0);
        return;
    }
    else if (get_waiting_connection_socket(tcp_socket->socket_id, ipv6_header,
                                           tcp_header) != NULL) {
        m_send_tcp.content.ptr = (char *)tcp_header;
        net_msg_send_recv(&m_send_tcp, &m_recv_tcp, tcp_socket->recv_pid, TCP_ACK);
        return;
    }
    else if (tcp_socket->socket_values.tcp_control.state == TCP_ESTABLISHED) {
        if (check_tcp_consistency(&tcp_socket->socket_values, tcp_header, 0) == PACKET_OK) {
            m_send_tcp.content.ptr = (char *)tcp_header;
            net_msg_send(&m_send_tcp, tcp_socket->send_pid, 0, TCP_ACK);
            return;
        }
    }

    printf("NO WAY OF HANDLING THIS ACK!\n");
}
void net_msg_cmd_do(void)
  {
  CHECKPOINT(0x44)
  delay100(2);

  // commands 40-49 are special AT commands, thus, disable net_msg here
  if ((net_msg_cmd_code < 40) || (net_msg_cmd_code > 49))
    net_msg_start();

    // Execute cmd: ask car module to execute first:
   if ((vehicle_fn_commandhandler == NULL)||
       (! vehicle_fn_commandhandler(TRUE, net_msg_cmd_code,net_msg_cmd_msg)))
     {
     // Car module does not feel responsible, fall back to standard:
     if( !net_msg_cmd_exec() )
       {
       // No standard as well => return "unimplemented"
       STP_UNIMPLEMENTED(net_scratchpad, net_msg_cmd_code);
       net_msg_encode_puts();
       }
     }

   // terminate IPSEND by Ctrl-Z (should this be disabled for commands 40-49 as well?)
   net_msg_send();

#ifdef OVMS_ACCMODULE
   acc_handle_msg(TRUE, net_msg_cmd_code, net_msg_cmd_msg);
#endif

   // clear command
   net_msg_cmd_code = 0;
   net_msg_cmd_msg[0] = 0;
  }
Esempio n. 10
0
void handle_tcp_fin_packet(ipv6_hdr_t *ipv6_header, tcp_hdr_t *tcp_header,
                           socket_internal_t *tcp_socket)
{
    (void) ipv6_header;

    msg_t m_send;
    socket_t *current_tcp_socket = &tcp_socket->socket_values;
    uint8_t send_buffer[BUFFER_SIZE];
    ipv6_hdr_t *temp_ipv6_header = ((ipv6_hdr_t *)(&send_buffer));
    tcp_hdr_t *current_tcp_packet = ((tcp_hdr_t *)(&send_buffer[IPV6_HDR_LEN]));

    set_tcp_cb(&current_tcp_socket->tcp_control, tcp_header->seq_nr + 1,
               current_tcp_socket->tcp_control.send_wnd, tcp_header->ack_nr + 1,
               tcp_header->ack_nr, tcp_header->window);

#ifdef TCP_HC
    current_tcp_socket->tcp_control.tcp_context.hc_type = COMPRESSED_HEADER;
#endif

    if (current_tcp_socket->tcp_control.state == TCP_FIN_WAIT_1) {
        current_tcp_socket->tcp_control.state = TCP_CLOSING;

        send_tcp(tcp_socket, current_tcp_packet, temp_ipv6_header, TCP_FIN_ACK, 0);
    }
    else {
        current_tcp_socket->tcp_control.state = TCP_LAST_ACK;

        send_tcp(tcp_socket, current_tcp_packet, temp_ipv6_header, TCP_FIN_ACK, 0);
    }

    net_msg_send(&m_send, tcp_socket->recv_pid, 0, CLOSE_CONN);
}
void net_msg_alarm(void)
  {
  char *p;

  delay100(2);
  net_msg_start();
  strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 PAVehicle alarm is sounding!");
  net_msg_encode_puts();
  net_msg_send();
  }
void net_msg_valettrunk(void)
  {
  char *p;

  delay100(2);
  net_msg_start();
  strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 PATrunk has been opened (valet mode).");
  net_msg_encode_puts();
  net_msg_send();
  }
void net_msg_socalert(void)
  {
  char *s;

  delay100(2);
  net_msg_start();
  s = stp_i(net_scratchpad, "MP-0 PAALERT!!! CRITICAL SOC LEVEL APPROACHED (", car_SOC); // 95%
  s = stp_rom(s, "% SOC)");
  net_msg_encode_puts();
  net_msg_send();
  }
void net_msg_erroralert(unsigned int errorcode, unsigned long errordata)
  {
  char *s;

  delay100(2);
  net_msg_start();
  s = stp_s(net_scratchpad, "MP-0 PE", car_type);
  s = stp_ul(s, ",", (unsigned long)errorcode);
  s = stp_ul(s, ",", (unsigned long)errordata);
  net_msg_encode_puts();
  net_msg_send();
  }
Esempio n. 15
0
File: tcp.c Progetto: fjrk/RIOT
void handle_tcp_syn_ack_packet(ipv6_hdr_t *ipv6_header, tcp_hdr_t *tcp_header,
                               socket_internal_t *tcp_socket)
{
    msg_t m_send_tcp;

    if (tcp_socket->socket_values.tcp_control.state == SYN_SENT) {
        m_send_tcp.content.ptr = (char *) tcp_header;
        net_msg_send(&m_send_tcp, tcp_socket->recv_pid, 0, TCP_SYN_ACK);
    }
    else {
        printf("Socket not in state SYN_SENT, dropping SYN-ACK-packet!");
    }
}
void net_msg_alert(void)
  {
  char *p;

  delay100(2);
  net_msg_start();
  strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 PA");

  switch (car_chargemode)
    {
    case 0x00:
      strcatpgm2ram(net_scratchpad,(char const rom far *)"Standard - "); // Charge Mode Standard
      break;
    case 0x01:
      strcatpgm2ram(net_scratchpad,(char const rom far *)"Storage - "); // Storage
      break;
    case 0x03:
      strcatpgm2ram(net_scratchpad,(char const rom far *)"Range - "); // Range
      break;
    case 0x04:
      strcatpgm2ram(net_scratchpad,(char const rom far *)"Performance - "); // Performance
    }
  switch (car_chargestate)
    {
    case 0x01:
      strcatpgm2ram(net_scratchpad,(char const rom far *)"Charging"); // Charge State Charging
      break;
    case 0x02:
      strcatpgm2ram(net_scratchpad,(char const rom far *)"Charging, Topping off"); // Topping off
      break;
    case 0x04:
      strcatpgm2ram(net_scratchpad,(char const rom far *)"Charging Done"); // Done
      break;
    default:
      strcatpgm2ram(net_scratchpad,(char const rom far *)"Charging Stopped"); // Stopped
    }

  strcatpgm2ram(net_scratchpad,(char const rom far *)"\rIdeal Range: "); // Ideal Range
  p = par_get(PARAM_MILESKM);
  if (*p == 'M') // Kmh or Miles
    sprintf(net_msg_scratchpad, (rom far char*)"%u mi", car_idealrange); // Miles
  else
    sprintf(net_msg_scratchpad, (rom far char*)"%u Km", (unsigned int) ((float) car_idealrange * 1.609)); // Kmh
  strcat((char*)net_scratchpad,net_msg_scratchpad);

  strcatpgm2ram(net_scratchpad,(char const rom far *)" SOC: ");
  sprintf(net_msg_scratchpad, (rom far char*)"%u%%", car_SOC); // 95%
  strcat(net_scratchpad,net_msg_scratchpad);
  net_msg_encode_puts();
  net_msg_send();
  }
void net_msg_reply_ussd(char *buf, unsigned char buflen)
{
  // called from net_state_activity()
  // buf contains a "+CUSD:" USSD command result
  // parse and return as command reply:
  char *s, *t = NULL;

  // Server not ready? abort
  // TODO: store, resend when server is connected
  if ((!net_msg_serverok) || (!buf) || (!buflen))
    return;

  // isolate USSD reply text
  if (t = memchr((void *) buf, '"', buflen))
  {
    ++t;
    buflen -= (t - buf);
    buf = t; // start of USSD string
    while ((*t) && (*t != '"') && ((t - buf) < buflen))
    {
      if (*t == ',') // "escape" comma for MP-0
        *t = '.';
      t++;
    }
    *t = 0; // end of USSD string
  }

  // format reply:
  s = stp_i(net_scratchpad, "MP-0 c", CMD_SendUSSD);
  if (t)
    s = stp_s(s, ",0,", buf);
  else
    s = stp_rom(s, ",1,Invalid USSD result");

  // send reply:

  if (net_msg_sendpending > 0)
  {
    delay100(20); // HACK... should buffer & retry later... but RAM is precious
    s = NULL; // flag
  }

  net_msg_start();
  net_msg_encode_puts();
  net_msg_send();

  if (!s)
    delay100(20); // HACK: give modem additional time if there was sendpending>0
}
void net_msg_12v_alert(void)
  {
  char *s;

  delay100(2);
  net_msg_start();
  if (can_minSOCnotified & CAN_MINSOC_ALERT_12V)
    s = stp_l2f(net_scratchpad, "MP-0 PAALERT!!! 12V BATTERY CRITICAL (", car_12vline, 1);
  else
    s = stp_l2f(net_scratchpad, "MP-0 PA12V BATTERY OK (", car_12vline, 1);
  s = stp_l2f(s, "V, ref=", car_12vline_ref, 1);
  s = stp_rom(s, "V)");
  net_msg_encode_puts();
  net_msg_send();
  }
void net_msg_forward_sms(char *caller, char *SMS)
  {
  //Server not ready, stop sending
  //TODO: store this message inside buffer, resend it when server is connected
  if ((net_msg_serverok == 0)||(net_msg_sendpending)>0)
    return;

  delay100(2);
  net_msg_start();
  strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 PA");
  strcatpgm2ram(net_scratchpad,(char const rom far*)"SMS FROM: ");
  strcat(net_scratchpad, caller);
  strcatpgm2ram(net_scratchpad,(char const rom far*)" - MSG: ");
  SMS[70]=0; // Hacky limit on the max size of an SMS forwarded
  strcat(net_scratchpad, SMS);
  net_msg_encode_puts();
  net_msg_send();
  }
void net_msg_reply_ussd(char *buf)
{
  // called from net_state_activity()
  // buf contains a "+CUSD:" USSD command result
  // parse and return as command reply:
  char *s, *t = NULL;

  // Server not ready? abort
  // TODO: store, resend when server is connected
  if ((!net_msg_serverok) || (!buf))
    return;

  // isolate USSD reply text
  if (t = strchr(buf, '"'))
  {
    buf = ++t; // start of USSD string
    while ((*t) && (*t != '"'))
    {
      if (*t == ',') // replace comma
        *t = '.';
      t++;
    }
    *t = 0; // end of USSD string
  }

  // format reply:
  s = stp_i(net_scratchpad, "MP-0 c", CMD_SendUSSD);
  if (t)
    s = stp_s(s, ",0,", buf);
  else
    s = stp_rom(s, ",1,Invalid USSD result");

  // send reply:
  if (net_msg_sendpending > 0)
    delay100(20); // HACK... should abort, buffer & retry later...
  net_msg_start();
  net_msg_encode_puts();
  net_msg_send();
}
////////////////////////////////////////////////////////////////////////
// net_state_ticker600()
// State Model: Per-10-minute ticker
// This function is called approximately once per ten minutes (since
// state was first entered), and gives the state a timeslice for activity.
//
void net_state_ticker600(void)
  {
  switch (net_state)
    {
    case NET_STATE_READY:
      if ((net_link==1)&&(net_apps_connected==0))
        {
        if (net_msg_sendpending>0)
          {
          net_granular_tick -= 5; // Try again in 5 seconds...
          }
        else
          {
          net_msg_start();
          net_msg_stat();
          net_msg_gps();
          net_msg_tpms();
          net_msg_environment();
          net_msg_send();
          }
        }
      break;
    }
  }
////////////////////////////////////////////////////////////////////////
// net_state_activity()
// State Model: Some async data has been received
// This is called to indicate to the state that a complete piece of async
// data has been received in net_buf (with length net_buf_pos, and mode
// net_buf_mode), and the data should be completely handled before
// returning.
//
void net_state_activity()
  {
  if (net_buf_mode == NET_BUF_SMS)
    {
    // An SMS has arrived, and net_caller has been primed
    if ((net_reg != 0x01)&&(net_reg != 0x05))
      { // Treat this as a network registration
      net_watchdog=0; // Disable watchdog, as we have connectivity
      net_reg = 0x05;
      led_net(1);
      }
    net_sms_in(net_caller,net_buf,net_buf_pos);
    return;
    }
  else if (net_buf_mode != NET_BUF_CRLF)
    {
    // An IP data message has arrived
    net_msg_in(net_buf);
    return;
    }

  switch (net_state)
    {
    case NET_STATE_DOINIT:
      if ((net_buf_pos >= 2)&&(net_buf[0] == 'O')&&(net_buf[1] == 'K'))
        {
        net_state_enter(NET_STATE_COPS);
        }
      break;
    case NET_STATE_COPS:
      if ((net_buf_pos >= 2)&&(net_buf[0] == 'O')&&(net_buf[1] == 'K'))
        net_state_enter(NET_STATE_DONETINIT); // COPS reconnect was OK
      else if ((net_buf_pos >= 5)&&(net_buf[0] == 'E')&&(net_buf[1] == 'R'))
        net_state_enter(NET_STATE_SOFTRESET); // Reset the entire async
      break;
    case NET_STATE_DONETINIT:
      if ((net_buf_pos >= 2)&&
               (net_buf[0] == 'E')&&
               (net_buf[1] == 'R')&&
               (net_state_vchar == 5)) // ERROR response to AT+CIFSR
        {
        // This is a nasty case. The GPRS has locked up.
        // The only solution I can find is a hard reset of the modem
        led_act(0);
        net_state_enter(NET_STATE_HARDRESET);
        }
      else if ((net_buf_pos >= 2)&&
          (((net_buf[0] == 'O')&&(net_buf[1] == 'K')))|| // OK
          (((net_buf[0] == 'S')&&(net_buf[1] == 'H')))||  // SHUT OK
          (net_state_vchar == 5)) // Local IP address
        {
        net_buf_pos = 0;
        net_timeout_ticks = 60;
        net_link = 0;
        delay100(1);
        switch (++net_state_vchar)
          {
          case 1:
            net_puts_rom("AT+CGDCONT=1,\"IP\",\"");
            net_puts_ram(par_get(PARAM_GPRSAPN));
            net_puts_rom("\"\r");
            break;
          case 2:
            net_puts_rom("AT+CSTT=\"");
            net_puts_ram(par_get(PARAM_GPRSAPN));
            net_puts_rom("\",\"");
            net_puts_ram(par_get(PARAM_GPRSUSER));
            net_puts_rom("\",\"");
            net_puts_ram(par_get(PARAM_GPRSPASS));
            net_puts_rom("\"\r");
            break;
          case 3:
            net_puts_rom("AT+CIICR\r");
            break;
          case 4:
            net_puts_rom("AT+CIPHEAD=1\r");
            break;
          case 5:
            net_puts_rom("AT+CIFSR\r");
            break;
          case 6:
            net_puts_rom("AT+CLPORT=\"TCP\",\"6867\"\r");
            break;
          case 7:
            net_puts_rom("AT+CIPSTART=\"TCP\",\"");
            net_puts_ram(par_get(PARAM_SERVERIP));
            net_puts_rom("\",\"6867\"\r");
            break;
          case 8:
            net_state_enter(NET_STATE_READY);
            break;
          }
        }
      else if ((net_buf_pos>=7)&&
               (memcmppgm2ram(net_buf, (char const rom far*)"+CREG: 0", 8) == 0))
        { // Lost network connectivity during NETINIT
        net_state_enter(NET_STATE_SOFTRESET);
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"+PDP: DEACT", 11) == 0)
        { // PDP couldn't be activated - try again...
        net_state_enter(NET_STATE_SOFTRESET);
        }
      break;
    case NET_STATE_READY:
      if (memcmppgm2ram(net_buf, (char const rom far*)"+CREG", 5) == 0)
        { // "+CREG" Network registration
        if (net_buf[8]==',')
          net_reg = net_buf[9]&0x07; // +CREG: 1,x
        else
          net_reg = net_buf[7]&0x07; // +CREG: x
        if ((net_reg == 0x01)||(net_reg == 0x05)) // Registered to network?
          {
          net_watchdog=0; // Disable watchdog, as we have connectivity
          led_net(1);
          }
        else if (net_watchdog == 0)
          {
          net_watchdog = 120; // We need connectivity within 120 seconds
          led_net(0);
          }
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"+CLIP", 5) == 0)
        { // Incoming CALL
        if ((net_reg != 0x01)&&(net_reg != 0x05))
          { // Treat this as a network registration
          net_watchdog=0; // Disable watchdog, as we have connectivity
          net_reg = 0x05;
          led_net(1);
          }
        delay100(1);
        net_puts_rom(NET_HANGUP);
        net_notify_status();
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"CONNECT OK", 10) == 0)
        {
        if (net_link == 0)
          {
          net_msg_start();
          net_msg_register();
          net_msg_send();
          }
        net_link = 1;
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"STATE: ", 7) == 0)
        { // Incoming CIPSTATUS
        if (memcmppgm2ram(net_buf, (char const rom far*)"STATE: CONNECT OK", 17) == 0)
          {
          if (net_link == 0)
            {
            net_msg_start();
            net_msg_register();
            net_msg_send();
            }
          net_link = 1;
          }
        else
          {
          net_link = 0;
          if ((net_reg == 0x01)||(net_reg == 0x05))
            {
            // We have a GSM network, but CIPSTATUS is not up
            net_msg_disconnected();
            net_state_enter(NET_STATE_DONETINIT);
            }
          }
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"SEND OK", 7) == 0)
        {
        net_msg_sendpending = 0;
        }
      else if ( (memcmppgm2ram(net_buf, (char const rom far*)"SEND FAIL", 9) == 0)||
                (memcmppgm2ram(net_buf, (char const rom far*)"CLOSED", 6) == 0)||
                (memcmppgm2ram(net_buf, (char const rom far*)"+CME ERROR", 10) == 0)||
                (memcmppgm2ram(net_buf, (char const rom far*)"+PDP: DEACT", 11) == 0) )
        { // Various GPRS error results
        // Re-initialize GPRS network and TCP socket
        net_msg_disconnected();
        net_state_enter(NET_STATE_DONETINIT);
        }
      break;
    }
  }
// Receive a NET msg from the OVMS server
void net_msg_in(char* msg)
  {
  int k;
  char s;

  if (net_msg_serverok == 0)
    {
    if (memcmppgm2ram(msg, (char const rom far*)"MP-S 0 ", 7) == 0)
      {
      net_msg_server_welcome(msg+7);
      net_granular_tick = 3590; // Nasty hack to force a status transmission in 10 seconds
      }
    return; // otherwise ignore it
    }

  // Ok, we've got an encrypted message waiting for work.
  // The following is a nasty hack because base64decode doesn't like incoming
  // messages of length divisible by 4, and is really expecting a CRLF
  // terminated string, so we give it one...
  CHECKPOINT(0x40)
  if (((strlen(msg)*4)/3) >= (NET_BUF_MAX-3))
    {
    // Quick exit to reset link if incoming message is too big
    net_state_enter(NET_STATE_DONETINIT);
    return;
    }
  strcatpgm2ram(msg,(char const rom far*)"\r\n");
  k = base64decode(msg,net_scratchpad);
  CHECKPOINT(0x41)
  RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, k);
  if (memcmppgm2ram(net_scratchpad, (char const rom far*)"MP-0 ", 5) != 0)
    {
    net_state_enter(NET_STATE_DONETINIT);
    return;
    }
  msg = net_scratchpad+5;

  if ((*msg == 'E')&&(msg[1]=='M'))
    {
    // A paranoid-mode message from the server (or, more specifically, app)
    // The following is a nasty hack because base64decode doesn't like incoming
    // messages of length divisible by 4, and is really expecting a CRLF
    // terminated string, so we give it one...
    msg += 2; // Now pointing to the code just before encrypted paranoid message
    strcatpgm2ram(msg,(char const rom far*)"\r\n");
    k = base64decode(msg+1,net_msg_scratchpad+1);
    RC4_setup(&pm_crypto1, &pm_crypto2, pdigest, MD5_SIZE);
    for (k=0;k<1024;k++)
      {
      net_scratchpad[0] = 0;
      RC4_crypt(&pm_crypto1, &pm_crypto2, net_scratchpad, 1);
      }
    RC4_crypt(&pm_crypto1, &pm_crypto2, net_msg_scratchpad+1, k);
    net_msg_scratchpad[0] = *msg; // The code
    // The message is now out of paranoid mode...
    msg = net_msg_scratchpad;
    }

  CHECKPOINT(0x42)
  switch (*msg)
    {
    case 'A': // PING
      strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 a");
      if (net_msg_sendpending==0)
        {
        net_msg_start();
        net_msg_encode_puts();
        net_msg_send();
        }
      break;
    case 'Z': // PEER connection
      if (msg[1] != '0')
        {
        net_apps_connected = 1;
        if (net_msg_sendpending==0)
          {
          net_msg_start();
          net_msgp_stat(0);
          net_msgp_gps(0);
          net_msgp_tpms(0);
          net_msgp_firmware(0);
          net_msgp_environment(0);
          net_msg_send();
          }
        }
      else
        {
        net_apps_connected = 0;
        }
      break;
    case 'h': // Historical data acknowledgement
#ifdef OVMS_LOGGINGMODULE
      logging_ack(atoi(msg+1));
#endif // #ifdef OVMS_LOGGINGMODULE
      break;
    case 'C': // COMMAND
      net_msg_cmd_in(msg+1);
      if (net_msg_sendpending==0) net_msg_cmd_do();
      break;
    }
  }
void net_msg_server_welcome(char *msg)
  {
  // The server has sent a welcome (token <space> base64digest)
  char *d,*p,*s;
  int k;
  unsigned char hwv = 1;

  #ifdef OVMS_HW_V2
  hwv = 2;
  #endif

  if( !msg ) return;
  for (d=msg;(*d != 0)&&(*d != ' ');d++) ;
  if (*d != ' ') return;
  *d++ = 0;

  // At this point, <msg> is token, and <x> is base64digest
  // (both null-terminated)

  // Check for token-replay attack
  if (strcmp(token,msg)==0)
    return; // Server is using our token!

  // Validate server token
  p = par_get(PARAM_SERVERPASS);
  hmac_md5(msg, strlen(msg), p, strlen(p), digest);
  base64encode(digest, MD5_SIZE, net_scratchpad);
  if (strcmp(d,net_scratchpad)!=0)
    return; // Invalid server digest

  // Ok, at this point, our token is ok
  strcpy(net_scratchpad,msg);
  strcat(net_scratchpad,token);
  hmac_md5(net_scratchpad,strlen(net_scratchpad),p,strlen(p),digest);

  // Setup, and prime the rx and tx cryptos
  RC4_setup(&rx_crypto1, &rx_crypto2, digest, MD5_SIZE);
  for (k=0;k<1024;k++)
    {
    net_scratchpad[0] = 0;
    RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, 1);
    }
  RC4_setup(&tx_crypto1, &tx_crypto2, digest, MD5_SIZE);
  for (k=0;k<1024;k++)
    {
    net_scratchpad[0] = 0;
    RC4_crypt(&tx_crypto1, &tx_crypto2, net_scratchpad, 1);
    }

  net_msg_serverok = 1;

  p = par_get(PARAM_PARANOID);
  if (*p == 'P')
    {
    // Paranoid mode initialisation
    if (ptokenmade==0)
      {
      // We need to make the ptoken
      for (k=0;k<TOKEN_SIZE;k++)
        {
        ptoken[k] = cb64[rand()%64];
        }
      ptoken[TOKEN_SIZE] = 0;
      }

    // To be truly paranoid, we must send the paranoid token to the server ;-)
    ptokenmade=0; // Leave it off for the MP-0 ET message
    strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 ET");
    strcat(net_scratchpad,ptoken);
    net_msg_start();
    net_msg_encode_puts();
    net_msg_send();
    ptokenmade=1; // And enable paranoid mode from now on...

    // And calculate the pdigest for future use
    p = par_get(PARAM_MODULEPASS);
    hmac_md5(ptoken, strlen(ptoken), p, strlen(p), pdigest);
    }
  else
    {
    ptokenmade = 0; // This disables paranoid mode
  }


  /* DEBUG / QA stats: Send crash counter and last reason:
   *
   * MP-0 H*-OVM-DebugCrash,0,2592000
   *  ,<firmware_version>/<vehicle_type><vehicle_version>/V<hardware_version>
   *  ,<crashcnt>,<crashreason>,<checkpoint>
   */

  if (debug_crashreason & 0x80)
    {
    debug_crashreason &= ~0x80; // clear checkpoint hold bit

    s = stp_i(net_scratchpad, "MP-0 H*-OVM-DebugCrash,0,2592000,", ovms_firmware[0]);
    s = stp_i(s, ".", ovms_firmware[1]);
    s = stp_i(s, ".", ovms_firmware[2]);
    s = stp_s(s, "/", par_get(PARAM_VEHICLETYPE));
    if (vehicle_version)
       s = stp_rom(s, vehicle_version);
    s = stp_i(s, "/V", hwv);
    s = stp_i(s, ",", debug_crashcnt);
    s = stp_x(s, ",", debug_crashreason);
    s = stp_i(s, ",", debug_checkpoint);

    delay100(20);
    net_msg_start();
    net_msg_encode_puts();
    net_msg_send();
    }
#ifdef OVMS_LOGGINGMODULE
  logging_serverconnect();
#endif // #ifdef OVMS_LOGGINGMODULE
}
void net_msg_server_welcome(char *msg)
  {
  // The server has sent a welcome (token <space> base64digest)
  char *d,*p;
  int k;

  for (d=msg;(*d != 0)&&(*d != ' ');d++) ;
  if (*d != ' ') return;
  *d++ = 0;

  // At this point, <msg> is token, and <x> is base64digest
  // (both null-terminated)

  // Check for token-replay attack
  if (strcmp(token,msg)==0)
    return; // Server is using our token!

  // Validate server token
  p = par_get(PARAM_NETPASS1);
  hmac_md5(msg, strlen(msg), p, strlen(p), digest);
  base64encode(digest, MD5_SIZE, net_scratchpad);
  if (strcmp(d,net_scratchpad)!=0)
    return; // Invalid server digest

  // Ok, at this point, our token is ok
  strcpy(net_scratchpad,msg);
  strcat(net_scratchpad,token);
  hmac_md5(net_scratchpad,strlen(net_scratchpad),p,strlen(p),digest);

  // Setup, and prime the rx and tx cryptos
  RC4_setup(&rx_crypto1, &rx_crypto2, digest, MD5_SIZE);
  for (k=0;k<1024;k++)
    {
    net_scratchpad[0] = 0;
    RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, 1);
    }
  RC4_setup(&tx_crypto1, &tx_crypto2, digest, MD5_SIZE);
  for (k=0;k<1024;k++)
    {
    net_scratchpad[0] = 0;
    RC4_crypt(&tx_crypto1, &tx_crypto2, net_scratchpad, 1);
    }

  net_msg_serverok = 1;

  p = par_get(PARAM_PARANOID);
  if (*p == 'P')
    {
    // Paranoid mode initialisation
    if (ptokenmade==0)
      {
      // We need to make the ptoken
      for (k=0;k<TOKEN_SIZE;k++)
        {
        ptoken[k] = cb64[rand()%64];
        }
      ptoken[TOKEN_SIZE] = 0;
      }

    // To be truly paranoid, we must send the paranoid token to the server ;-)
    ptokenmade=0; // Leave it off for the MP-0 ET message
    strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 ET");
    strcat(net_scratchpad,ptoken);
    net_msg_start();
    net_msg_encode_puts();
    net_msg_send();
    ptokenmade=1; // And enable paranoid mode from now on...

    // And calculate the pdigest for future use
    p = par_get(PARAM_REGPASS);
    hmac_md5(ptoken, strlen(ptoken), p, strlen(p), pdigest);
    }
  else
    {
    ptokenmade = 0; // This disables paranoid mode
    }
  }
////////////////////////////////////////////////////////////////////////
// net_state_ticker1()
// State Model: Per-second ticker
// This function is called approximately once per second, and gives
// the state a timeslice for activity.
//
void net_state_ticker1(void)
  {
  char *p;

  switch (net_state)
    {
    case NET_STATE_START:
      net_state_vchar = net_state_vchar ^ 1; // Toggle LED on/off
      led_act(net_state_vchar);
      break;
    case NET_STATE_DOINIT:
      if ((net_timeout_ticks==10)&&(net_timeout_ticks==20))
        net_puts_rom(NET_INIT); // Try again...
      break;   
    case NET_STATE_COPS:
      net_state_vchar = net_state_vchar ^ 1; // Toggle LED on/off
      led_net(net_state_vchar);
      led_act(net_state_vchar^1);
      break;
    case NET_STATE_SOFTRESET:
      net_state_enter(NET_STATE_START);
      break;
    case NET_STATE_READY:
      if (net_watchdog > 0)
        {
        if (--net_watchdog == 0)
          {
          net_state_enter(NET_STATE_COPS); // Reset network connection
          return;
          }
        }
      if (net_msg_sendpending>0)
        {
        net_msg_sendpending++;
        if (net_msg_sendpending>60)
          {
          // Pending for more than 60 seconds..
          net_state_enter(NET_STATE_DONETINIT); // Reset GPRS link
          return;
          }
        }
      if ((net_reg == 0x01)||(net_reg == 0x05))
        {
        if ((net_msg_notify==1)&&(net_msg_serverok==1))
          {
          net_msg_notify = 0;
          delay100(10);
          net_msg_alert();
          return;
          }
        if (net_sms_notify==1)
          {
          net_sms_notify = 0;
          delay100(10);
          p = par_get(PARAM_REGPHONE);
          net_sms_stat(p);
          return;
          }
        if ((net_msg_notifyenvironment==1)&&
            (net_msg_serverok==1)&&
            (net_apps_connected>0)&&
            (net_msg_sendpending==0))
          {
          net_msg_notifyenvironment = 0;
          delay100(10);
          net_msg_start();
          net_msg_environment();
          net_msg_send();
          }
        }
      break;
    }
  }