AP_Networking: added option for PPP<->ethernet bridge

when NET_OPTIONS is set to enable PPP bridging both an ethernet and a
PPP link will be brought up, with IP forwarding making the PPP remote
endpoint available on the ethernet LAN
This commit is contained in:
Andrew Tridgell 2024-01-09 07:27:31 +11:00 committed by Tom Pittenger
parent 5414416230
commit 39a1fc9dbd
5 changed files with 154 additions and 28 deletions

View File

@ -86,6 +86,20 @@ const AP_Param::GroupInfo AP_Networking::var_info[] = {
AP_SUBGROUPINFO(param.test_ipaddr, "TEST_IP", 8, AP_Networking, AP_Networking_IPV4),
#endif
// @Param: OPTIONS
// @DisplayName: Networking options
// @Description: Networking options
// @Bitmask: 0:EnablePPP Ethernet gateway
// @RebootRequired: True
// @User: Advanced
AP_GROUPINFO("OPTIONS", 9, AP_Networking, param.options, 0),
#if AP_NETWORKING_PPP_GATEWAY_ENABLED
// @Group: REMPPP_IP
// @Path: AP_Networking_address.cpp
AP_SUBGROUPINFO(param.remote_ppp_ip, "REMPPP_IP", 10, AP_Networking, AP_Networking_IPV4),
#endif
AP_GROUPEND
};
@ -129,8 +143,19 @@ void AP_Networking::init()
}
#endif
#if AP_NETWORKING_PPP_GATEWAY_ENABLED
if (option_is_set(OPTION::PPP_ETHERNET_GATEWAY)) {
/*
when we are a PPP/Ethernet gateway we bring up the ethernet first
*/
backend = new AP_Networking_ChibiOS(*this);
backend_PPP = new AP_Networking_PPP(*this);
}
#endif
#if AP_NETWORKING_BACKEND_PPP
if (AP::serialmanager().have_serial(AP_SerialManager::SerialProtocol_PPP, 0)) {
if (backend == nullptr && AP::serialmanager().have_serial(AP_SerialManager::SerialProtocol_PPP, 0)) {
backend = new AP_Networking_PPP(*this);
}
#endif
@ -158,6 +183,13 @@ void AP_Networking::init()
return;
}
#if AP_NETWORKING_PPP_GATEWAY_ENABLED
if (backend_PPP != nullptr && !backend_PPP->init()) {
GCS_SEND_TEXT(MAV_SEVERITY_INFO, "NET: backend_PPP init failed");
backend_PPP = nullptr;
}
#endif
announce_address_changes();
GCS_SEND_TEXT(MAV_SEVERITY_INFO,"NET: Initialized");

View File

@ -26,6 +26,7 @@ class AP_Networking
public:
friend class AP_Networking_Backend;
friend class AP_Networking_ChibiOS;
friend class AP_Networking_PPP;
friend class AP_Vehicle;
friend class Networking_Periph;
@ -149,6 +150,13 @@ public:
static const struct AP_Param::GroupInfo var_info[];
enum class OPTION {
PPP_ETHERNET_GATEWAY=(1U<<0),
};
bool option_is_set(OPTION option) const {
return (param.options.get() & int32_t(option)) != 0;
}
private:
static AP_Networking *singleton;
@ -172,10 +180,18 @@ private:
AP_Int32 tests;
AP_Networking_IPV4 test_ipaddr{AP_NETWORKING_TEST_IP};
#endif
#if AP_NETWORKING_PPP_GATEWAY_ENABLED
AP_Networking_IPV4 remote_ppp_ip{AP_NETWORKING_REMOTE_PPP_IP};
#endif
} param;
AP_Networking_Backend *backend;
#if AP_NETWORKING_PPP_GATEWAY_ENABLED
AP_Networking_Backend *backend_PPP;
#endif
HAL_Semaphore sem;
enum class NetworkPortType {

View File

@ -119,3 +119,17 @@
#ifndef AP_NETWORKING_SENDFILE_BUFSIZE
#define AP_NETWORKING_SENDFILE_BUFSIZE (64*512)
#endif
#ifndef AP_NETWORKING_PPP_GATEWAY_ENABLED
#define AP_NETWORKING_PPP_GATEWAY_ENABLED (AP_NETWORKING_BACKEND_CHIBIOS && AP_NETWORKING_BACKEND_PPP)
#endif
/*
the IP address given to the remote end of the PPP link when running
as a PPP<->ethernet gateway. If this is on the same subnet as the
ethernet interface IP then proxyarp will be used
*/
#ifndef AP_NETWORKING_REMOTE_PPP_IP
#define AP_NETWORKING_REMOTE_PPP_IP "0.0.0.0"
#endif

View File

@ -57,10 +57,17 @@ void AP_Networking_PPP::ppp_status_callback(struct ppp_pcb_s *pcb, int code, voi
switch (code) {
case PPPERR_NONE:
// got new addresses for the link
driver.activeSettings.ip = ntohl(netif_ip4_addr(pppif)->addr);
driver.activeSettings.gw = ntohl(netif_ip4_gw(pppif)->addr);
driver.activeSettings.nm = ntohl(netif_ip4_netmask(pppif)->addr);
driver.activeSettings.last_change_ms = AP_HAL::millis();
#if AP_NETWORKING_PPP_GATEWAY_ENABLED
if (driver.frontend.option_is_set(AP_Networking::OPTION::PPP_ETHERNET_GATEWAY)) {
GCS_SEND_TEXT(MAV_SEVERITY_INFO, "PPP: got addresses");
} else
#endif
{
driver.activeSettings.ip = ntohl(netif_ip4_addr(pppif)->addr);
driver.activeSettings.gw = ntohl(netif_ip4_gw(pppif)->addr);
driver.activeSettings.nm = ntohl(netif_ip4_netmask(pppif)->addr);
driver.activeSettings.last_change_ms = AP_HAL::millis();
}
break;
case PPPERR_OPEN:
@ -94,10 +101,13 @@ bool AP_Networking_PPP::init()
return false;
}
// initialise TCP/IP thread
LWIP_TCPIP_LOCK();
tcpip_init(NULL, NULL);
LWIP_TCPIP_UNLOCK();
const bool ethernet_gateway = frontend.option_is_set(AP_Networking::OPTION::PPP_ETHERNET_GATEWAY);
if (!ethernet_gateway) {
// initialise TCP/IP thread
LWIP_TCPIP_LOCK();
tcpip_init(NULL, NULL);
LWIP_TCPIP_UNLOCK();
}
hal.scheduler->delay(100);
@ -127,9 +137,14 @@ void AP_Networking_PPP::ppp_loop(void)
while (!hal.scheduler->is_system_initialized()) {
hal.scheduler->delay_microseconds(1000);
}
const bool ppp_gateway = frontend.option_is_set(AP_Networking::OPTION::PPP_ETHERNET_GATEWAY);
if (ppp_gateway) {
// wait for the ethernet interface to be up
AP::network().startup_wait();
}
// ensure this thread owns the uart
uart->begin(0);
uart->begin(AP::serialmanager().find_baudrate(AP_SerialManager::SerialProtocol_PPP, 0));
uart->set_unbuffered_writes(true);
while (true) {
@ -137,9 +152,63 @@ void AP_Networking_PPP::ppp_loop(void)
// connect and set as default route
LWIP_TCPIP_LOCK();
#if AP_NETWORKING_PPP_GATEWAY_ENABLED
if (ppp_gateway) {
/*
when bridging setup the ppp interface with the same IP
as the ethernet interface, and set the remote IP address
as the local address + 1
*/
ip4_addr_t our_ip, his_ip;
const uint32_t ip = frontend.get_ip_active();
uint32_t rem_ip = frontend.param.remote_ppp_ip.get_uint32();
if (rem_ip == 0) {
// use ethernet IP +1 by default
rem_ip = ip+1;
}
our_ip.addr = htonl(ip);
his_ip.addr = htonl(rem_ip);
ppp_set_ipcp_ouraddr(ppp, &our_ip);
ppp_set_ipcp_hisaddr(ppp, &his_ip);
if (netif_list != nullptr) {
const uint32_t nmask = frontend.get_netmask_param();
if ((ip & nmask) == (rem_ip & nmask)) {
// remote PPP IP is on the same subnet as the
// local ethernet IP, so enable proxyarp to avoid
// users having to setup routes in all devices
netif_set_proxyarp(netif_list, &his_ip);
}
}
}
// connect to the remote end
ppp_connect(ppp, 0);
if (ppp_gateway) {
extern struct netif *netif_list;
/*
when we are setup as a PPP gateway we want the pppif to be
first in the list so routing works if it is on the same
subnet
*/
if (netif_list != nullptr &&
netif_list->next != nullptr &&
netif_list->next->next == pppif) {
netif_list->next->next = nullptr;
pppif->next = netif_list;
netif_list = pppif;
}
} else {
netif_set_default(pppif);
}
#else
// normal PPP link, connect to the remote end and set as the
// default route
ppp_connect(ppp, 0);
netif_set_default(pppif);
#endif // AP_NETWORKING_PPP_GATEWAY_ENABLED
LWIP_TCPIP_UNLOCK();
need_restart = false;

View File

@ -74,7 +74,6 @@ extern "C"
#define LWIP_ICMP LWIP_IPV4
#define LWIP_SNMP LWIP_UDP
#define MIB2_STATS LWIP_SNMP
#ifdef LWIP_HAVE_MBEDTLS
#define LWIP_SNMP_V3 (LWIP_SNMP)
#endif
@ -255,6 +254,7 @@ a lot of data that needs to be copied, this should be set high. */
#define LWIP_ARP 1
#define ARP_TABLE_SIZE 10
#define ARP_QUEUEING 1
#define ARP_PROXYARP_SUPPORT 1
/* ---------- IP options ---------- */
@ -263,6 +263,12 @@ a lot of data that needs to be copied, this should be set high. */
on a device with only one network interface, define this to 0. */
#define IP_FORWARD 1
/*
extra header space when forwarding for adding the ethernet header
*/
#define PBUF_LINK_HLEN 16
/* IP reassembly and segmentation.These are orthogonal even
* if they both deal with IP fragments */
#define IP_REASSEMBLY 1
@ -302,22 +308,8 @@ a lot of data that needs to be copied, this should be set high. */
/* ---------- Statistics options ---------- */
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
#if LWIP_STATS
#define LINK_STATS 1
#define IP_STATS 1
#define ICMP_STATS 1
#define IGMP_STATS 1
#define IPFRAG_STATS 1
#define UDP_STATS 1
#define TCP_STATS 1
#define MEM_STATS 1
#define MEMP_STATS 1
#define PBUF_STATS 1
#define SYS_STATS 1
#endif /* LWIP_STATS */
#define LWIP_STATS 0
#define LWIP_STATS_DISPLAY 0
/* ---------- NETBIOS options ---------- */
#define LWIP_NETBIOS_RESPOND_NAME_QUERY 1
@ -343,7 +335,10 @@ a lot of data that needs to be copied, this should be set high. */
#define MSCHAP_SUPPORT 0 /* Set > 0 for MSCHAP */
#define CBCP_SUPPORT 0 /* Set > 0 for CBCP (NOT FUNCTIONAL!) */
#define CCP_SUPPORT 0 /* Set > 0 for CCP */
#define VJ_SUPPORT 1 /* Set > 0 for VJ header compression. */
/*
VJ support disabled due to bugs with IP forwarding
*/
#define VJ_SUPPORT 0 /* Set > 0 for VJ header compression. */
#define MD5_SUPPORT 0 /* Set > 0 for MD5 (see also CHAP) */
#endif /* PPP_SUPPORT */