// 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; } } }
// <stat> guarded encode the message in net_scratchpad and start the send process char net_msg_encode_statputs(char stat, WORD *oldcrc) { WORD newcrc = crc16(net_scratchpad, strlen(net_scratchpad)); switch (stat) { case 0: // Always output net_msg_encode_puts(); *oldcrc = newcrc; break; case 1: // Guarded output, but net_msg_start() has already been sent if (*oldcrc != newcrc) { net_msg_encode_puts(); *oldcrc = newcrc; } break; case 2: // Guarded output, but net_msg_start() has not yet been sent if (*oldcrc != newcrc) { net_msg_start(); net_msg_encode_puts(); *oldcrc = newcrc; stat = 1; } break; } return stat; }
//////////////////////////////////////////////////////////////////////// // 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; } }
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; }
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_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_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(); }
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; } }
BOOL net_msg_cmd_exec(void) { int k; char *p, *s; delay100(2); CHECKPOINT(0x43) switch (net_msg_cmd_code) { case 1: // Request feature list (params unused) for (k=0;k<FEATURES_MAX;k++) { s = stp_i(net_scratchpad, "MP-0 c1,0,", k); s = stp_i(s, ",", FEATURES_MAX); s = stp_i(s, ",", sys_features[k]); net_msg_encode_puts(); } break; case 2: // Set feature (params: feature number, value) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value k = atoi(net_msg_cmd_msg); if ((k>=0)&&(k<FEATURES_MAX)) { sys_features[k] = atoi(p); if (k>=FEATURES_MAP_PARAM) // Top N features are persistent par_set(PARAM_FEATURE_S+(k-FEATURES_MAP_PARAM), p); if (k == FEATURE_CANWRITE) vehicle_initialise(); STP_OK(net_scratchpad, net_msg_cmd_code); } else { STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code); } } else { STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); break; case 3: // Request parameter list (params unused) for (k=0;k<PARAM_MAX;k++) { p = par_get(k); if (k==PARAM_SERVERPASS) *p=0; // Don't show netpass1 s = stp_i(net_scratchpad, "MP-0 c3,0,", k); s = stp_i(s, ",", PARAM_MAX); s = stp_s(s, ",", p); net_msg_encode_puts(); } break; case 4: // Set parameter (params: param number, value) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value k = atoi(net_msg_cmd_msg); if ((k>=0)&&(k<PARAM_FEATURE_S)) { par_set(k, p); STP_OK(net_scratchpad, net_msg_cmd_code); if ((k==PARAM_MILESKM) || (k==PARAM_VEHICLETYPE)) vehicle_initialise(); #ifdef OVMS_ACCMODULE // Reset the ACC state it an ACC parameter is changed if ((k>=PARAM_ACC_S)&&(k<(PARAM_ACC_S+PARAM_ACC_COUNT))) acc_state_enter(ACC_STATE_FIRSTRUN); #endif } else { STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code); } } else { STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); break; case 5: // Reboot (params unused) STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); net_state_enter(NET_STATE_HARDSTOP); break; case 6: // CHARGE ALERT (params unused) net_msg_alert(); net_msg_encode_puts(); break; case 7: // SMS command wrapper // process command: net_msg_bufpos = net_msg_scratchpad; k = net_sms_in(par_get(PARAM_REGPHONE), net_msg_cmd_msg); net_msg_bufpos = NULL; // output is now in net_msg_scratchpad // create return string: s = stp_i(net_scratchpad, NET_MSG_CMDRESP, net_msg_cmd_code); s = stp_i(s, ",", 1-k); // 0=ok 1=error if (k) { *s++ = ','; for (p = net_msg_scratchpad; *p; p++) { if (*p == '\n') *s++ = '\r'; // translate LF to CR else if (*p == ',') *s++ = ';'; // translate , to ; else *s++ = *p; } *s = 0; } // send return string: net_msg_encode_puts(); break; case 40: // Send SMS (params: phone number, SMS message) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the phone number, and <p> to the SMS message net_send_sms_start(net_msg_cmd_msg); net_puts_ram(p); net_puts_rom("\x1a"); delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); } else { net_msg_start(); STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); delay100(2); break; case 41: // Send MMI/USSD Codes (param: USSD_CODE) net_puts_rom("AT+CUSD=1,\""); net_puts_ram(net_msg_cmd_msg); net_puts_rom("\",15\r"); // cmd reply #1 to acknowledge command: delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); delay100(2); // cmd reply #2 sent on USSD response, see net_msg_reply_ussd() break; case 49: // Send raw AT command (param: raw AT command) net_puts_ram(net_msg_cmd_msg); net_puts_rom("\r"); delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); delay100(2); break; default: return FALSE; } return TRUE; }
//////////////////////////////////////////////////////////////////////// // 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; } }
BOOL net_msg_cmd_exec(void) { int k; char *p, *s; delay100(2); CHECKPOINT(0x43) switch (net_msg_cmd_code) { case 1: // Request feature list (params unused) for (k=0;k<FEATURES_MAX;k++) { s = stp_i(net_scratchpad, "MP-0 c1,0,", k); s = stp_i(s, ",", FEATURES_MAX); s = stp_i(s, ",", sys_features[k]); net_msg_encode_puts(); } break; case 2: // Set feature (params: feature number, value) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value k = atoi(net_msg_cmd_msg); if ((k>=0)&&(k<FEATURES_MAX)) { sys_features[k] = atoi(p); if (k>=FEATURES_MAP_PARAM) // Top N features are persistent par_set(PARAM_FEATURE_S+(k-FEATURES_MAP_PARAM), p); if (k == FEATURE_CANWRITE) vehicle_initialise(); STP_OK(net_scratchpad, net_msg_cmd_code); } else { STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code); } } else { STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); break; case 3: // Request parameter list (params unused) for (k=0;k<PARAM_MAX;k++) { p = par_get(k); if (k==PARAM_SERVERPASS) *p=0; // Don't show netpass1 s = stp_i(net_scratchpad, "MP-0 c3,0,", k); s = stp_i(s, ",", PARAM_MAX); s = stp_s(s, ",", p); net_msg_encode_puts(); } break; case 4: // Set parameter (params: param number, value) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value k = atoi(net_msg_cmd_msg); if ((k>=0)&&(k<PARAM_FEATURE_S)) { par_set(k, p); STP_OK(net_scratchpad, net_msg_cmd_code); if ((k==PARAM_MILESKM) || (k==PARAM_VEHICLETYPE)) vehicle_initialise(); } else { STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code); } } else { STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); break; case 5: // Reboot (params unused) STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); net_state_enter(NET_STATE_HARDSTOP); break; case 6: // CHARGE ALERT (params unused) net_msg_alert(); net_msg_encode_puts(); break; case 40: // Send SMS (params: phone number, SMS message) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the phone number, and <p> to the SMS message net_send_sms_start(net_msg_cmd_msg); net_puts_ram(p); net_puts_rom("\x1a"); delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); } else { net_msg_start(); STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); delay100(2); break; case 41: // Send MMI/USSD Codes (param: USSD_CODE) net_puts_rom("AT+CUSD=1,\""); net_puts_ram(net_msg_cmd_msg); net_puts_rom("\",15\r"); // cmd reply #1 to acknowledge command: delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); delay100(2); // cmd reply #2 sent on USSD response, see net_msg_reply_ussd() break; case 49: // Send raw AT command (param: raw AT command) net_puts_ram(net_msg_cmd_msg); net_puts_rom("\r"); delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); delay100(2); break; default: return FALSE; } return TRUE; }
// 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_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; } }