Skip to content

Commit

Permalink
at server + Tether API
Browse files Browse the repository at this point in the history
  • Loading branch information
avtolstoy committed Oct 4, 2024
1 parent 9338b13 commit 17d1fea
Show file tree
Hide file tree
Showing 17 changed files with 1,360 additions and 60 deletions.
23 changes: 14 additions & 9 deletions hal/network/lwip/ppp_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ constexpr const char* Client::stateNames_[];
const auto NCP_CLIENT_LCP_ECHO_INTERVAL_SECONDS_DEFAULT = 5;
const auto NCP_CLIENT_LCP_ECHO_INTERVAL_SECONDS_R510 = 240; // 4 minutes (4.25 minutes max)
const auto NCP_CLIENT_LCP_ECHO_MAX_FAILS_DEFAULT = 10;
const auto NCP_CLIENT_LCP_ECHO_MAX_FAILS_DEFAULT_SERVER = 2;
const auto NCP_CLIENT_LCP_ECHO_MAX_FAILS_R510 = 1;

namespace {
Expand Down Expand Up @@ -115,6 +116,10 @@ void Client::init() {
SPARK_ASSERT(pcb_);
if_.flags &= ~NETIF_FLAG_UP;

if (server_) {
if_.name[1] = 's'; // "ps" instead of "pp"
}

LOCK_TCPIP_CORE();
ipcp_ = std::make_unique<Ipcp>(pcb_);
SPARK_ASSERT(ipcp_);
Expand Down Expand Up @@ -154,6 +159,11 @@ void Client::init() {
pcb_->lcp_echos_pending = 0; // reset echo count
}

if (server_) {
pcb_->settings.lcp_echo_interval = NCP_CLIENT_LCP_ECHO_INTERVAL_SECONDS_DEFAULT;
pcb_->settings.lcp_echo_fails = NCP_CLIENT_LCP_ECHO_MAX_FAILS_DEFAULT_SERVER;
}

pppapi_set_notify_phase_callback(pcb_, &Client::notifyPhaseCb);

os_queue_create(&queue_, sizeof(QueueEvent), 5, nullptr);
Expand Down Expand Up @@ -219,7 +229,7 @@ int Client::prepareConnect() {
#if HAL_PLATFORM_PPP_SERVER
LOCK_TCPIP_CORE();
if (server_) {
ppp_set_silent(pcb_, 1);
ppp_set_silent(pcb_, 0);
ppp_set_auth(pcb_, PPPAUTHTYPE_ANY, "particle", "particle");
ppp_set_auth_required(pcb_, 0);
} else {
Expand Down Expand Up @@ -321,15 +331,10 @@ int Client::input(const uint8_t* data, size_t size) {
const size_t header = 19;
if (pppos->in_state == PDDATA && pppos->in_head->len >= header) {
const size_t len = pppos->in_head->len - header;
const char breakAndAt[] = "+++AT";
const char breakAndAtDial[] = "+++ATD";
if (len >= strlen(breakAndAtDial) && !strncmp(((const char*)pppos->in_head->payload) + header, breakAndAtDial, strlen(breakAndAtDial))) {
const char okResponse[] = "\r\nCONNECT\r\n";
output((const uint8_t*)okResponse, strlen(okResponse));
} else if (len >= strlen(breakAndAt) && !strncmp(((const char*)pppos->in_head->payload) + header, breakAndAt, strlen(breakAndAt))) {
const char breakSeq[] = "+++";
if (len >= strlen(breakSeq) && !strncmp(((const char*)pppos->in_head->payload) + header, breakSeq, strlen(breakSeq))) {
pppos_drop_packet(pppos);
const char okResponse[] = "\r\nOK\r\n";
output((const uint8_t*)okResponse, strlen(okResponse));
disconnect();
}
}
}
Expand Down
212 changes: 185 additions & 27 deletions hal/network/lwip/pppservernetif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ LOG_SOURCE_CATEGORY("net.pppserver");
#include "dnsproxy.h"
#include "thread_runner.h"
#include "nat.h"
#include "at_server.h"
#include "device_code.h"
#include "deviceid_hal.h"
#include "bytes2hexbuf.h"
#include "network/ncp/cellular/cellular_network_manager.h"
#include "network/ncp/cellular/cellular_ncp_client.h"
#include "network/ncp/cellular/ncp.h"


using namespace particle::net;

Expand Down Expand Up @@ -171,6 +179,162 @@ int PppServerNetif::start() {

g_natInstance = nat_.get();

AtServerConfig conf;
auto server = std::make_unique<AtServer>();
SPARK_ASSERT(server);
server_ = std::move(server);
conf.stream(serial_.get());
conf.streamTimeout(1000);
server_->init(conf);

server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "H", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
// TODO: stop PPP
return 0;
}, nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "+CGMI", "Particle"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "+CGMM", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
char buf[64] = {};
get_device_usb_name(buf, sizeof(buf));
request->sendResponse(buf);
return 0;
}, nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "E0", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto conf = request->server()->config();
conf.echoEnabled(false);
request->server()->init(conf);
return 0;
}, nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "E", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto conf = request->server()->config();
conf.echoEnabled(true);
request->server()->init(conf);
return 0;
}, nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::ONE_INT_ARG, "X", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::ONE_INT_ARG, "V", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::ONE_INT_ARG, "&C", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "+GCAP", "+GCAP: +CGSM,+CLTE"));
// +CSCS=?
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "+CGMR", PP_STR(SYSTEM_VERSION_STRING)));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "+CGSN", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
uint8_t id[HAL_DEVICE_ID_SIZE] = {};
const auto n = hal_get_device_id(id, sizeof(id));
if (n != HAL_DEVICE_ID_SIZE) {
return SYSTEM_ERROR_UNKNOWN;
}
char deviceId[HAL_DEVICE_ID_SIZE * 2 + 1] = {};
bytes2hexbuf_lower_case(id, sizeof(id), deviceId);
request->sendResponse(deviceId);
return 0;
}, nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CMEE", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "I", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
char buf[64] = {};
get_device_usb_name(buf, sizeof(buf));
request->sendResponse("%s %s", "Particle", buf);
return 0;
}, nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::TEST, "+URAT", "+URAT: (0-9)")); // Pretend to support all
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+URAT", "+URAT: 3")); // Pretend to be LTE
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::TEST, "+CGDCONT", "+CGDCONT: (0-1),\"IP\",,,(0-2),(0-4),(0,1),(0,3),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1)"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+CGDCONT", "+CGDCONT: 1,\"IP\",\"particle\",0,0"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+CFUN", "+CFUN: 1,0")); // Full functionality
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CMER", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CGACT", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+CGACT", "+CGACT: 1,1"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::TEST, "+CMER", "+CMER: (0-3),(0),(0),(0-2),(0,1)"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+CPIN", "+CPIN: READY"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+CCID", "+CCID: 00000000000000000000"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "+CIMI", "000000000000000"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "+CNUM", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "PARTICLE1", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "PARTICLE2", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "Z", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "+CSQ", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
const auto mgr = cellularNetworkManager();
CHECK_TRUE(mgr, SYSTEM_ERROR_UNKNOWN);
const auto client = mgr->ncpClient();
CHECK_TRUE(client, SYSTEM_ERROR_UNKNOWN);
CellularSignalQuality s;
CHECK(client->getSignalQuality(&s));
const auto strn = s.strength();
const auto qual = s.quality();
request->sendResponse("+CSQ: %d,%d", strn, qual);
return 0;
}, nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::TEST, "+IFC", "+IFC: (0-2)(0-2)"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+IFC", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto stream = (SerialStream*)data;
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
if (stream->config() & SERIAL_FLOW_CONTROL_RTS_CTS) {
request->sendResponse("+IFC: 2,2");
} else {
request->sendResponse("+IFC: 0,0");
}
return 0;
}, serial_.get()));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+IFC", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto stream = (SerialStream*)data;
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
int v[2] = {};
CHECK_TRUE(request->scanf("%d,%d", &v[0], &v[1]) == 2, SYSTEM_ERROR_INVALID_ARGUMENT);
if (v[0] == 2 || v[1] == 2) {
auto c = stream->config() | SERIAL_FLOW_CONTROL_RTS_CTS;
return stream->setConfig(c);
} else if (v[0] == 0 || v[1] == 0) {
auto c = stream->config() & (~SERIAL_FLOW_CONTROL_RTS_CTS);
return stream->setConfig(c);
}
return SYSTEM_ERROR_INVALID_ARGUMENT;
}, serial_.get()));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CGEREP", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CREG", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CGREG", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CEREG", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+CREG", "+CREG: 2,1")); // Dummy
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+CGREG", "+CGREG: 2,1")); // Dummy
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+CEREG", "+CEREG: 2,1")); // Dummy
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CRC", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+CCWA", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+COPS", nullptr));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+COPS", "+COPS: 0,0,\"Particle\""));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::TEST, "+IPR", "+IPR: (0,9600,19200,38400,57600,115200,230400,460800,921600),()"));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::READ, "+IPR", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto stream = (SerialStream*)data;
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
request->sendResponse("+IPR: %u", stream->baudrate());
return 0;
}, serial_.get()));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WRITE, "+IPR", [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto stream = (SerialStream*)data;
CHECK_TRUE(stream, SYSTEM_ERROR_INVALID_STATE);
int v = 0;
CHECK_TRUE(request->scanf("%d", &v) == 1, SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK_TRUE(v > 0, SYSTEM_ERROR_INVALID_ARGUMENT);
CHECK(stream->setBaudRate(v));
return 0;
}, serial_.get()));
auto connectRequest = [](AtServerRequest* request, AtServerCommandType type, const char* command, void* data) -> int {
auto client = (net::ppp::Client*)data;
request->sendResponse("CONNECT %u", ((SerialStream*)request->server()->config().stream())->baudrate());
request->setFinalResponse(AtServerRequest::CONNECT);
request->server()->suspend();
client->setOutputCallback([](const uint8_t* data, size_t size, void* ctx) -> int {
// LOG(INFO, "output %u", size);
auto c = (Stream*)ctx;
int r = c->writeAll((const char*)data, size, 1000);
if (!r) {
return size;
}
return r;
}, request->server()->config().stream());
client->connect();
client->notifyEvent(ppp::Client::EVENT_LOWER_UP);
return 0;
};
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::WILDCARD, "D*", connectRequest, &client_));
server_->addCommandHandler(AtServerCommandHandler(AtServerCommandType::EXEC, "D", connectRequest, &client_));

SPARK_ASSERT(os_thread_create(&thread_, "pppserver", OS_THREAD_PRIORITY_NETWORK, &PppServerNetif::loop, this, OS_THREAD_STACK_SIZE_DEFAULT_HIGH) == 0);
return 0;
}
Expand All @@ -181,21 +345,28 @@ if_t PppServerNetif::interface() {

void PppServerNetif::loop(void* arg) {
PppServerNetif* self = static_cast<PppServerNetif*>(arg);
unsigned int timeout = 1000;
while(!self->exit_) {
auto ev = self->serial_->waitEvent(SerialStream::READABLE | PPP_SERVER_NETIF_EVENT_EXIT, timeout);
auto ev = self->serial_->waitEvent(PPP_SERVER_NETIF_EVENT_EXIT, 0);
if (ev & PPP_SERVER_NETIF_EVENT_EXIT) {
//break;
break;
}
if (!self->server_->suspended()) {
self->server_->process();
} else {
auto ev = self->serial_->waitEvent(SerialStream::READABLE | PPP_SERVER_NETIF_EVENT_EXIT, 1000);
if (ev & PPP_SERVER_NETIF_EVENT_EXIT) {
break;
}

if (ev & SerialStream::READABLE) {
char tmp[256] = {};
while (self->serial_->availForRead() > 0) {
int sz = self->serial_->read(tmp, sizeof(tmp));
// LOG(INFO, "input %d", sz);
auto r = self->client_.input((const uint8_t*)tmp, sz);
(void)r;
// LOG(INFO, "input result = %d", r);
if (ev & SerialStream::READABLE) {
char tmp[256] = {};
while (self->serial_->availForRead() > 0) {
int sz = self->serial_->read(tmp, sizeof(tmp));
// LOG(INFO, "input %d", sz);
auto r = self->client_.input((const uint8_t*)tmp, sz);
(void)r;
// LOG(INFO, "input result = %d", r);
}
}
}
}
Expand All @@ -206,24 +377,11 @@ void PppServerNetif::loop(void* arg) {
}

int PppServerNetif::up() {
LOG(INFO, "up");
CHECK(start());
client_.setOutputCallback([](const uint8_t* data, size_t size, void* ctx) -> int {
// LOG(INFO, "output %u", size);
auto c = (PppServerNetif*)ctx;
int r = c->serial_->writeAll((const char*)data, size, 1000);
if (!r) {
return size;
}
return r;
}, this);
client_.connect();
client_.notifyEvent(ppp::Client::EVENT_LOWER_UP);
return SYSTEM_ERROR_NONE;
}

int PppServerNetif::down() {
LOG(INFO, "down");
if (dnsRunner_) {
dnsRunner_->destroy();
}
Expand All @@ -236,7 +394,6 @@ int PppServerNetif::down() {
}

int PppServerNetif::powerUp() {
LOG(INFO, "powerUp");
// FIXME: As long as the interface is initialized,
// it must have been powered up as of right now.
// The system network manager transit the interface to powering up,
Expand All @@ -246,7 +403,6 @@ int PppServerNetif::powerUp() {
}

int PppServerNetif::powerDown() {
LOG(INFO, "powerDown");
int ret = down();
// FIXME: This don't really power off the module.
// Notify the system network manager that the module is powered down
Expand Down Expand Up @@ -302,7 +458,6 @@ void PppServerNetif::pppEventHandlerCb(particle::net::ppp::Client* c, uint64_t e
}

void PppServerNetif::pppEventHandler(uint64_t ev, int data) {
LOG(INFO, "ppp event %llx %d", ev, data);
if (ev == particle::net::ppp::Client::EVENT_UP) {
unsigned mtu = client_.getIf()->mtu;
LOG(TRACE, "Negotiated MTU: %u", mtu);
Expand All @@ -320,6 +475,9 @@ void PppServerNetif::pppEventHandler(uint64_t ev, int data) {
dns_->destroy();
}
nat_->disable(interface());
// Drop back into AT mode
client_.notifyEvent(ppp::Client::EVENT_LOWER_DOWN);
server_->resume();
} else if (ev == particle::net::ppp::Client::EVENT_CONNECTING) {
} else if (ev == particle::net::ppp::Client::EVENT_ERROR) {
LOG(ERROR, "PPP error event data=%d", data);
Expand Down
3 changes: 3 additions & 0 deletions hal/network/lwip/pppservernetif.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <lwip/pbuf.h>
#include "ppp_client.h"
#include "serial_stream.h"
#include "at_server.h"

#ifdef __cplusplus

Expand Down Expand Up @@ -102,6 +103,8 @@ class PppServerNetif : public BaseNetif {
std::unique_ptr<::particle::ThreadRunner> dnsRunner_;
std::unique_ptr<particle::net::nat::Nat64> nat_;
if_req_ppp_server_uart_settings settings_;
std::unique_ptr<AtServer> server_;

};

} } // namespace particle::net
Expand Down
Loading

0 comments on commit 17d1fea

Please sign in to comment.