OVMS3/OVMS.V3/components/ovms_cellular/src/gsmpppos.cpp

266 lines
7.3 KiB
C++

/*
; Project: Open Vehicle Monitor System
; Date: 14th March 2017
;
; Changes:
; 1.0 Initial release
;
; (C) 2011 Michael Stegen / Stegen Electronics
; (C) 2011-2017 Mark Webb-Johnson
; (C) 2011 Sonny Chen @ EPRO/DX
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
; THE SOFTWARE.
*/
#include "ovms_log.h"
static const char *TAG = "gsm-ppp";
#include <lwip/ip_addr.h>
#include <lwip/netif.h>
#include <lwip/dns.h>
#include "gsmpppos.h"
#include "ovms_command.h"
#include "ovms_config.h"
#include "ovms_events.h"
static u32_t GsmPPPOS_OutputCallback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
{
GsmPPPOS* me = (GsmPPPOS*)ctx;
MyCommandApp.HexDump(TAG, "tx", (const char*)data, len);
return me->m_mux->tx(me->m_channel, data, len);
}
static void GsmPPPOS_StatusCallback(ppp_pcb *pcb, int err_code, void *ctx)
{
GsmPPPOS* me = (GsmPPPOS*)ctx;
struct netif *pppif = ppp_netif(pcb);
me->m_lasterrcode = err_code;
ESP_LOGI(TAG, "StatusCallBack: %s",me->ErrCodeName(err_code));
switch (err_code)
{
case PPPERR_NONE:
{
ESP_LOGI(TAG, "status_cb: Connected");
#if PPP_IPV4_SUPPORT
ESP_LOGI(TAG, " our_ipaddr = %s", ipaddr_ntoa(&pppif->ip_addr));
ESP_LOGI(TAG, " his_ipaddr = %s", ipaddr_ntoa(&pppif->gw));
ESP_LOGI(TAG, " netmask = %s", ipaddr_ntoa(&pppif->netmask));
const ip_addr_t* dns = dns_getserver(0);
ESP_LOGI(TAG, " DNS#0 = %s", ipaddr_ntoa(dns));
dns = dns_getserver(1);
ESP_LOGI(TAG, " DNS#1 = %s", ipaddr_ntoa(dns));
#endif /* PPP_IPV4_SUPPORT */
#if PPP_IPV6_SUPPORT
ESP_LOGI(TAG, " our6_ipaddr = %s", ip6addr_ntoa(netif_ip6_addr(pppif, 0)));
#endif /* PPP_IPV6_SUPPORT */
me->m_connected = true;
MyEvents.SignalEvent("network.interface.up", NULL);
MyEvents.SignalEvent("system.modem.gotip",NULL);
return;
}
case PPPERR_PARAM:
{
ESP_LOGE(TAG, "status_cb: Invalid parameter");
break;
}
case PPPERR_OPEN:
{
ESP_LOGE(TAG, "status_cb: Unable to open PPP session");
break;
}
case PPPERR_DEVICE:
{
ESP_LOGE(TAG, "status_cb: Invalid I/O device for PPP");
break;
}
case PPPERR_ALLOC:
{
ESP_LOGE(TAG, "status_cb: Unable to allocate resources");
break;
}
case PPPERR_USER:
{
if (me->m_connected)
{
ESP_LOGI(TAG, "PPP connection has been closed");
me->m_connected = false;
MyEvents.SignalEvent("system.modem.down",NULL);
}
return;
}
case PPPERR_CONNECT:
{
ESP_LOGE(TAG, "status_cb: Connection lost");
break;
}
case PPPERR_AUTHFAIL:
{
ESP_LOGE(TAG, "status_cb: Failed authentication challenge");
break;
}
case PPPERR_PROTOCOL:
{
ESP_LOGE(TAG, "status_cb: Failed to meet protocol");
break;
}
case PPPERR_PEERDEAD:
{
ESP_LOGE(TAG, "status_cb: Connection timeout");
break;
}
case PPPERR_IDLETIMEOUT:
{
ESP_LOGE(TAG, "status_cb: Idle Timeout");
break;
}
case PPPERR_CONNECTTIME:
{
ESP_LOGE(TAG, "status_cb: Max connect time reached");
break;
}
case PPPERR_LOOPBACK:
{
ESP_LOGE(TAG, "status_cb: Loopback detected");
break;
}
default:
{
ESP_LOGE(TAG, "status_cb: Unknown error code %d", err_code);
break;
}
}
ESP_LOGI(TAG, "Shutdown (via status callback)");
if (me->m_connected)
{
me->m_connected = false;
MyEvents.SignalEvent("system.modem.down",NULL);
}
// Try to reconnect in 30 seconds. This is assuming the modem level
// data channel is still open.
ESP_LOGI(TAG, "Attempting PPP reconnecting in 30 seconds...");
// Note: We are in tiT task context here so use ppp_connect not pppapi_connect.
ppp_connect(pcb, 30);
}
GsmPPPOS::GsmPPPOS(GsmMux* mux, int channel)
{
m_mux = mux;
m_channel = channel;
m_ppp = NULL;
m_connected = false;
m_lasterrcode = -1;
}
GsmPPPOS::~GsmPPPOS()
{
Shutdown(true);
if (m_ppp)
{
pppapi_free(m_ppp);
m_ppp = NULL;
}
}
void GsmPPPOS::IncomingData(uint8_t *data, size_t len)
{
MyCommandApp.HexDump(TAG, "rx", (const char*)data, len);
pppos_input_tcpip(m_ppp, (u8_t*)data, (int)len);
}
void GsmPPPOS::Initialise(GsmMux* mux, int channel)
{
ESP_LOGI(TAG, "Initialising...");
m_mux = mux;
m_channel = channel;
if (m_ppp == NULL)
{
m_ppp = pppapi_pppos_create(&m_ppp_netif,
GsmPPPOS_OutputCallback, GsmPPPOS_StatusCallback, this);
}
if (m_ppp == NULL)
{
ESP_LOGE(TAG, "Error init pppos");
return;
}
pppapi_set_default(m_ppp);
}
void GsmPPPOS::Startup()
{
if (m_ppp == NULL) return;
pppapi_set_auth(m_ppp, PPPAUTHTYPE_PAP,
MyConfig.GetParamValue("modem", "apn.user").c_str(),
MyConfig.GetParamValue("modem", "apn.password").c_str());
ppp_set_usepeerdns(m_ppp, 1); // Ask the peer for up to 2 DNS server addresses
pppapi_connect(m_ppp, 0);
}
void GsmPPPOS::Shutdown(bool hard)
{
if (m_ppp)
{
u8_t nocarrier = (u8_t)hard;
if (hard)
{
ESP_LOGI(TAG, "Shutting down (hard)...");
}
else
{
ESP_LOGI(TAG, "Shutting down (soft)...");
}
m_connected = false;
MyEvents.SignalEvent("system.modem.down",NULL);
pppapi_close(m_ppp, nocarrier);
ESP_LOGI(TAG, "PPP is shutdown");
}
else
{
ESP_LOGI(TAG, "Shutdown (direct)");
m_connected = false;
}
}
const char* GsmPPPOS::ErrCodeName(int errcode)
{
switch (errcode)
{
case PPPERR_NONE: return "None";
case PPPERR_PARAM: return "Invalid Parameter";
case PPPERR_OPEN: return "Unable to Open PPP";
case PPPERR_DEVICE: return "Invalid I/O Device";
case PPPERR_ALLOC: return "Unable to Allocate Resources";
case PPPERR_USER: return "User Interrupt";
case PPPERR_CONNECT: return "Connection Lost";
case PPPERR_AUTHFAIL: return "Authentication Failed";
case PPPERR_PROTOCOL: return "Failed to meet Protocol";
case PPPERR_PEERDEAD: return "Peer Dead";
case PPPERR_IDLETIMEOUT: return "Idle Timeout";
case PPPERR_CONNECTTIME: return "Max Connect Time Reached";
case PPPERR_LOOPBACK: return "Loopback Detected";
default: return "Undefined";
};
}