Use picotcp for ppp protocol processing. Now all is needed is a tap or

tun interface.
This commit is contained in:
Flyinghead 2018-09-15 21:41:54 +02:00
parent ce3d8f2baa
commit 6699a8a294
12 changed files with 503 additions and 73 deletions

View File

@ -436,10 +436,11 @@ static int pico_arp_process_in(struct pico_frame *f, struct pico_arp_hdr *hdr, s
return -1;
}
if (pico_arp_check_flooding(f, me) < 0) {
pico_frame_discard(f);
return -1;
}
// FIXME Problem with proxy ARP
// if (pico_arp_check_flooding(f, me) < 0) {
// pico_frame_discard(f);
// return -1;
// }
/* If no existing entry was found, create a new entry, or fail trying. */
if ((!found) && (pico_arp_create_entry(hdr->s_mac, hdr->src, f->dev) < 0)) {

View File

@ -282,6 +282,7 @@ struct pico_device_ppp {
uint8_t frame_id;
uint8_t timer_on;
uint16_t mru;
uint32_t ipcp_peer_ip;
};
@ -513,7 +514,7 @@ static int pico_ppp_send(struct pico_device *dev, void *buf, int len)
int fcs_start;
int i = 0;
ppp_dbg(" >>>>>>>>> PPP OUT\n");
ppp_dbg(" >>>>>>>>> PPP OUT len %d\n", len);
if (ppp->ipcp_state != PPP_IPCP_STATE_OPENED)
return len;
@ -1141,12 +1142,12 @@ static inline uint32_t ipcp_request_options_size(struct pico_device_ppp *ppp)
{
uint32_t size = 0;
/* if (ppp->ipcp_ip) */
size += IPCP_ADDR_LEN;
/* if (ppp->ipcp_dns1) */
size += IPCP_ADDR_LEN;
/* if (ppp->ipcp_dns2) */
size += IPCP_ADDR_LEN;
if (ppp->ipcp_peer_ip)
size += IPCP_ADDR_LEN;
if (ppp->ipcp_dns1)
size += IPCP_ADDR_LEN;
if (ppp->ipcp_dns2)
size += IPCP_ADDR_LEN;
if (ppp->ipcp_nbns1)
size += IPCP_ADDR_LEN;
@ -1171,7 +1172,7 @@ static int ipcp_request_add_address(uint8_t *dst, uint8_t tag, uint32_t arg)
static void ipcp_request_fill(struct pico_device_ppp *ppp, uint8_t *opts)
{
if (ppp->ipcp_allowed_fields & IPCP_ALLOW_IP)
opts += ipcp_request_add_address(opts, IPCP_OPT_IP, ppp->ipcp_ip);
opts += ipcp_request_add_address(opts, IPCP_OPT_IP, ppp->ipcp_peer_ip);
if (ppp->ipcp_allowed_fields & IPCP_ALLOW_DNS1)
opts += ipcp_request_add_address(opts, IPCP_OPT_DNS1, ppp->ipcp_dns1);
@ -1216,12 +1217,16 @@ static void ipcp_reject_vj(struct pico_device_ppp *ppp, uint8_t *comp_req)
struct pico_ipcp_hdr *ih = (struct pico_ipcp_hdr *) (ipcp_req + prefix);
uint8_t *p = ipcp_req + prefix + sizeof(struct pico_ipcp_hdr);
uint32_t i;
uint8_t *p2 = comp_req + sizeof(struct pico_ipcp_hdr);
ih->id = ppp->frame_id++;
ih->code = PICO_CONF_REQ;
ih->id = ((struct pico_ipcp_hdr *)comp_req)->id;
ih->code = PICO_CONF_REJ;
ih->len = short_be(IPCP_VJ_LEN + sizeof(struct pico_ipcp_hdr));
for(i = 0; i < IPCP_OPT_VJ; i++)
p[i] = comp_req[i + sizeof(struct pico_ipcp_hdr)];
while (p2[0] != IPCP_OPT_VJ)
p2 += p2[1];
for(i = 0; i < IPCP_VJ_LEN; i++)
p[i] = p2[i];
ppp_dbg("Sending IPCP CONF REJ VJ\n");
pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_IPCP,
ipcp_req, /* Start of PPP packet */
@ -1243,9 +1248,10 @@ static void ppp_ipv4_conf(struct pico_device_ppp *ppp)
0
};
ip.addr = ppp->ipcp_ip;
nm.addr = 0xFFFFFF00;
nm.addr = 0xFFFFFFFF;
pico_ipv4_link_add(&ppp->dev, ip, nm);
pico_ipv4_route_add(any, any, any, 1, pico_ipv4_link_by_dev(&ppp->dev));
ip.addr = ppp->ipcp_peer_ip;
pico_ipv4_route_add(ip, nm, any, 1, pico_ipv4_link_by_dev(&ppp->dev));
dns1.addr = ppp->ipcp_dns1;
dns2.addr = ppp->ipcp_dns2;
@ -1253,12 +1259,14 @@ static void ppp_ipv4_conf(struct pico_device_ppp *ppp)
pico_dns_client_nameserver(&dns2, PICO_DNS_NS_ADD);
}
static void ipcp_send_nack(struct pico_device_ppp *ppp);
static void ipcp_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len)
{
struct pico_ipcp_hdr *ih = (struct pico_ipcp_hdr *)pkt;
uint8_t *p = pkt + sizeof(struct pico_ipcp_hdr);
int reject = 0;
int nak = 0;
while (p < pkt + len) {
if (p[0] == IPCP_OPT_VJ) {
reject++;
@ -1266,75 +1274,72 @@ static void ipcp_process_in(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t
if (p[0] == IPCP_OPT_IP) {
if (ih->code != PICO_CONF_REJ)
ppp->ipcp_ip = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5]));
else {
ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_IP);
ppp->ipcp_ip = 0;
{
uint32_t ipcp_ip = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5]));
if (ipcp_ip != ppp->ipcp_peer_ip)
nak++;
}
}
if (p[0] == IPCP_OPT_DNS1) {
if (ih->code != PICO_CONF_REJ)
ppp->ipcp_dns1 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5]));
else {
ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_DNS1);
ppp->ipcp_dns1 = 0;
}
}
if (p[0] == IPCP_OPT_NBNS1) {
if (ih->code != PICO_CONF_REJ)
ppp->ipcp_nbns1 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5]));
else {
ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_NBNS1);
ppp->ipcp_nbns1 = 0;
{
uint32_t ipcp_dns1 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5]));
if (ipcp_dns1 != ppp->ipcp_dns1)
nak++;
}
}
if (p[0] == IPCP_OPT_DNS2) {
if (ih->code != PICO_CONF_REJ)
ppp->ipcp_dns2 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5]));
else {
ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_DNS2);
ppp->ipcp_dns2 = 0;
}
}
if (p[0] == IPCP_OPT_NBNS2) {
if (ih->code != PICO_CONF_REJ)
ppp->ipcp_nbns2 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5]));
else {
ppp->ipcp_allowed_fields &= (~IPCP_ALLOW_NBNS2);
ppp->ipcp_nbns2 = 0;
{
uint32_t ipcp_dns2 = long_be((uint32_t)((p[2] << 24) + (p[3] << 16) + (p[4] << 8) + p[5]));
if (ipcp_dns2 != ppp->ipcp_dns2)
nak++;
}
}
p += p[1];
}
switch(ih->code) {
case PICO_CONF_ACK:
ppp_dbg("Received IPCP CONF ACK\n");
break;
case PICO_CONF_REQ:
ppp_dbg("Received IPCP CONF REQ\n");
break;
case PICO_CONF_NAK:
ppp_dbg("Received IPCP CONF NAK\n");
break;
case PICO_CONF_REJ:
ppp_dbg("Received IPCP CONF REJ\n");
break;
}
if (reject) {
ipcp_reject_vj(ppp, p);
ipcp_reject_vj(ppp, pkt);
return;
}
ppp->pkt = pkt;
ppp->len = len;
if (nak) {
ipcp_send_nack(ppp);
return;
}
switch(ih->code) {
case PICO_CONF_ACK:
ppp_dbg("Received IPCP CONF ACK\n");
evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_RCA);
break;
case PICO_CONF_REQ:
ppp_dbg("Received IPCP CONF REQ\n");
evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_RCR_POS);
break;
case PICO_CONF_NAK:
ppp_dbg("Received IPCP CONF NAK\n");
evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_RCN);
break;
case PICO_CONF_REJ:
ppp_dbg("Received IPCP CONF REJ\n");
evaluate_ipcp_state(ppp, PPP_IPCP_EVENT_RCN);
break;
}
@ -1923,9 +1928,61 @@ static void evaluate_auth_state(struct pico_device_ppp *ppp, enum ppp_auth_event
}
}
static inline uint32_t ipcp_nack_options_size(struct pico_device_ppp *ppp, uint8_t *pkt, uint32_t len)
{
uint8_t *p = pkt + sizeof(struct pico_ipcp_hdr);
uint32_t size = 0;
IGNORE_PARAMETER(ppp);
while (p < pkt + len) {
if (p[0] == IPCP_OPT_IP)
size += IPCP_ADDR_LEN;
else if (p[0] == IPCP_OPT_DNS1)
size += IPCP_ADDR_LEN;
else if (p[0] == IPCP_OPT_DNS2)
size += IPCP_ADDR_LEN;
p += p[1];
}
return size;
}
static void ipcp_send_nack(struct pico_device_ppp *ppp)
{
IGNORE_PARAMETER(ppp);
uint8_t *pkt = ppp->pkt;
uint32_t len = ppp->len;
uint8_t ipcp_req[PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + sizeof(struct pico_ipcp_hdr) + ipcp_nack_options_size(ppp, pkt, len) + PPP_FCS_SIZE + 1];
uint32_t prefix = PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE;
struct pico_ipcp_hdr *ih = (struct pico_ipcp_hdr *) (ipcp_req + prefix);
uint8_t *p = ipcp_req + prefix + sizeof(struct pico_ipcp_hdr);
uint8_t *preq = pkt + sizeof(struct pico_ipcp_hdr);
ih->id = ((struct pico_ipcp_hdr *)pkt)->id;
ih->code = PICO_CONF_NAK;
ih->len = short_be((uint16_t)(ipcp_nack_options_size(ppp, pkt, len) + sizeof(struct pico_ipcp_hdr)));
while (preq < pkt + len) {
if (preq[0] == IPCP_OPT_IP)
{
p += ipcp_request_add_address(p, IPCP_OPT_IP, ppp->ipcp_peer_ip);
}
else if (preq[0] == IPCP_OPT_DNS1)
{
p += ipcp_request_add_address(p, IPCP_OPT_DNS1, ppp->ipcp_dns1);
}
else if (preq[0] == IPCP_OPT_DNS2)
{
p += ipcp_request_add_address(p, IPCP_OPT_DNS2, ppp->ipcp_dns2);
}
preq += preq[1];
}
ppp_dbg("Sending IPCP CONF NAK\n");
pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_IPCP,
ipcp_req, /* Start of PPP packet */
(uint32_t)sizeof(ipcp_req));
}
static void ipcp_bring_up(struct pico_device_ppp *ppp)
@ -1934,10 +1991,10 @@ static void ipcp_bring_up(struct pico_device_ppp *ppp)
if (ppp->ipcp_ip) {
char my_ip[16], my_dns[16];
pico_ipv4_to_string(my_ip, ppp->ipcp_ip);
ppp_dbg("Received IP config %s\n", my_ip);
pico_ipv4_to_string(my_ip, ppp->ipcp_peer_ip);
ppp_dbg("Assigned IP to peer: %s\n", my_ip);
pico_ipv4_to_string(my_dns, ppp->ipcp_dns1);
ppp_dbg("Received DNS: %s\n", my_dns);
ppp_dbg("Assigned DNS: %s\n", my_dns);
ppp_ipv4_conf(ppp);
}
}
@ -2195,7 +2252,7 @@ struct pico_device *pico_ppp_create(void)
ppp->dev.link_state = pico_ppp_link_state;
ppp->frame_id = (uint8_t)(pico_rand() % 0xFF);
ppp->modem_state = PPP_MODEM_STATE_INITIAL;
ppp->modem_state = PPP_MODEM_STATE_CONNECTED;
ppp->lcp_state = PPP_LCP_STATE_INITIAL;
ppp->auth_state = PPP_AUTH_STATE_INITIAL;
ppp->ipcp_state = PPP_IPCP_STATE_INITIAL;
@ -2209,7 +2266,7 @@ struct pico_device *pico_ppp_create(void)
ppp->mru = PICO_PPP_MRU;
LCPOPT_SET_LOCAL(ppp, LCPOPT_MRU);
LCPOPT_SET_LOCAL(ppp, LCPOPT_AUTH); /* We support authentication, even if it's not part of the req */
//LCPOPT_SET_LOCAL(ppp, LCPOPT_AUTH); /* We support authentication, even if it's not part of the req */
LCPOPT_SET_LOCAL(ppp, LCPOPT_PROTO_COMP);
LCPOPT_SET_LOCAL(ppp, LCPOPT_ADDRCTL_COMP);
@ -2221,7 +2278,9 @@ struct pico_device *pico_ppp_create(void)
int pico_ppp_connect(struct pico_device *dev)
{
struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev;
ppp->autoreconnect = 1;
ppp_modem_connected(ppp);
evaluate_lcp_state(ppp, PPP_LCP_EVENT_OPEN);
return 0;
}
@ -2310,3 +2369,47 @@ int pico_ppp_set_password(struct pico_device *dev, const char *password)
strncpy(ppp->password, password, sizeof(ppp->password) - 1);
return 0;
}
int pico_ppp_set_ip(struct pico_device *dev, struct pico_ip4 ip)
{
struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev;
if (!dev)
return -1;
ppp->ipcp_ip = ip.addr;
return 0;
}
int pico_ppp_set_dns1(struct pico_device *dev, struct pico_ip4 ip)
{
struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev;
if (!dev)
return -1;
ppp->ipcp_dns1 = ip.addr;
return 0;
}
int pico_ppp_set_dns2(struct pico_device *dev, struct pico_ip4 ip)
{
struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev;
if (!dev)
return -1;
ppp->ipcp_dns2 = ip.addr;
return 0;
}
int pico_ppp_set_peer_ip(struct pico_device *dev, struct pico_ip4 ip)
{
struct pico_device_ppp *ppp = (struct pico_device_ppp *)dev;
if (!dev)
return -1;
ppp->ipcp_peer_ip = ip.addr;
return 0;
}

View File

@ -22,5 +22,9 @@ int pico_ppp_set_serial_set_speed(struct pico_device *dev, int (*sspeed)(struct
int pico_ppp_set_apn(struct pico_device *dev, const char *apn);
int pico_ppp_set_username(struct pico_device *dev, const char *username);
int pico_ppp_set_password(struct pico_device *dev, const char *password);
int pico_ppp_set_ip(struct pico_device *dev, struct pico_ip4 ip);
int pico_ppp_set_dns1(struct pico_device *dev, struct pico_ip4 ip);
int pico_ppp_set_dns2(struct pico_device *dev, struct pico_ip4 ip);
int pico_ppp_set_peer_ip(struct pico_device *dev, struct pico_ip4 ip);
#endif /* INCLUDE_PICO_PPP */

View File

@ -89,7 +89,7 @@ void pico_tap_destroy(struct pico_device *dev)
}
#ifndef __FreeBSD__
static int tap_open(char *name)
static int tap_open(const char *name)
{
struct ifreq ifr;
int tap_fd;
@ -107,7 +107,7 @@ static int tap_open(char *name)
return tap_fd;
}
#else
static int tap_open(char *name)
static int tap_open(const char *name)
{
int tap_fd;
(void)name;
@ -118,7 +118,7 @@ static int tap_open(char *name)
#ifndef __FreeBSD__
static int tap_get_mac(char *name, uint8_t *mac)
static int tap_get_mac(const char *name, uint8_t *mac)
{
int sck;
struct ifreq eth;
@ -146,7 +146,7 @@ static int tap_get_mac(char *name, uint8_t *mac)
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <net/if_types.h>
static int tap_get_mac(char *name, uint8_t *mac)
static int tap_get_mac(const char *name, uint8_t *mac)
{
struct sockaddr_dl *sdl;
struct ifaddrs *ifap, *root;
@ -172,7 +172,7 @@ static int tap_get_mac(char *name, uint8_t *mac)
}
#endif
struct pico_device *pico_tap_create(char *name)
struct pico_device *pico_tap_create(const char *name)
{
struct pico_device_tap *tap = PICO_ZALLOC(sizeof(struct pico_device_tap));
uint8_t mac[6] = {};

View File

@ -9,7 +9,7 @@
#include "pico_device.h"
void pico_tap_destroy(struct pico_device *tap);
struct pico_device *pico_tap_create(char *name);
struct pico_device *pico_tap_create(const char *name);
#endif

View File

@ -60,7 +60,7 @@ void pico_tun_destroy(struct pico_device *dev)
}
static int tun_open(char *name)
static int tun_open(const char *name)
{
struct ifreq ifr;
int tun_fd;
@ -80,7 +80,7 @@ static int tun_open(char *name)
struct pico_device *pico_tun_create(char *name)
struct pico_device *pico_tun_create(const char *name)
{
struct pico_device_tun *tun = PICO_ZALLOC(sizeof(struct pico_device_tun));

View File

@ -9,7 +9,7 @@
#include "pico_device.h"
void pico_tun_destroy(struct pico_device *tun);
struct pico_device *pico_tun_create(char *name);
struct pico_device *pico_tun_create(const char *name);
#endif

View File

@ -1575,8 +1575,9 @@ static int pico_ipv4_pre_forward_checks(struct pico_frame *f)
static int pico_ipv4_forward_check_dev(struct pico_frame *f)
{
if (f->dev->eth != NULL)
f->len -= PICO_SIZE_ETHHDR;
// TODO What was this for? Clearly causing problems with tap
// if (f->dev->eth != NULL)
// f->len -= PICO_SIZE_ETHHDR;
if (f->len > f->dev->mtu) {
pico_notify_pkt_too_big(f);

View File

@ -26,8 +26,15 @@
#include "hw/holly/holly_intc.h"
#include "hw/sh4/sh4_sched.h"
#include "oslib/oslib.h"
#include "picoppp.h"
#include "pppd.h"
#define start_pppd start_pico
#define stop_pppd stop_pico
#define write_pppd write_pico
#define read_pppd read_pico
#define MODEM_COUNTRY_RES 0
#define MODEM_COUNTRY_JAP 1
#define MODEM_COUNTRY_USA 2

213
core/hw/modem/picoppp.cpp Normal file
View File

@ -0,0 +1,213 @@
#include <queue>
extern "C" {
#include <pico_stack.h>
#include <pico_dev_ppp.h>
#include <pico_dev_tap.h>
#include <pico_arp.h>
#include <pico_dev_tun.h>
#ifdef DHCP
#include <pico_dhcp_client.h>
#endif
}
#define NETWORK_TUN
#include "types.h"
#include "cfg/cfg.h"
#include "picoppp.h"
static struct pico_device *ppp;
struct pico_device* tap;
struct pico_device* tun;
static std::queue<u8> in_buffer;
static std::queue<u8> out_buffer;
static int modem_read(struct pico_device *dev, void *data, int len)
{
u8 *p = (u8 *)data;
int count = 0;
while (!out_buffer.empty() && count < len)
{
*p++ = out_buffer.front();
out_buffer.pop();
count++;
}
return count;
}
static int modem_write(struct pico_device *dev, const void *data, int len)
{
u8 *p = (u8 *)data;
while (len > 0)
{
in_buffer.push(*p++);
len--;
}
return len;
}
void write_pico(u8 b)
{
out_buffer.push(b);
}
int read_pico()
{
pico_stack_tick();
if (in_buffer.empty())
return -1;
else
{
u32 b = in_buffer.front();
in_buffer.pop();
return b;
}
}
static int modem_set_speed(struct pico_device *dev, uint32_t speed)
{
return 0;
}
#ifdef DHCP
static uint32_t dhcpclient_xid;
static struct pico_ip4 dchp_address = { 0 };
void callback_dhcpclient(void *arg, int code)
{
char s_address[16] = { }, s_gateway[16] = { };
printf("DHCP client: callback happened with code %d!\n", code);
if (code == PICO_DHCP_SUCCESS)
{
dchp_address = pico_dhcp_get_address(arg);
//gateway = pico_dhcp_get_gateway(arg);
pico_ipv4_to_string(s_address, dchp_address.addr);
//pico_ipv4_to_string(s_gateway, gateway.addr);
printf("DHCP client: got IP %s assigned with cli %p\n", s_address, arg);
}
}
#endif
static bool pico_stack_inited;
bool start_pico()
{
struct pico_ip4 ipaddr, netmask, zero = {
0
};
if (!pico_stack_inited)
{
pico_stack_init();
pico_stack_inited = true;
}
// PPP
ppp = pico_ppp_create();
if (!ppp)
return false;
string dc_ip = cfgLoadStr("network", "IP", "");
if (dc_ip.length() == 0)
{
printf("No IP address set for Netplay. Set IP= in the [network] section\n");
return false;
}
pico_string_to_ipv4(dc_ip.c_str(), &ipaddr.addr);
pico_ppp_set_peer_ip(ppp, ipaddr);
pico_string_to_ipv4("192.168.167.1", &ipaddr.addr);
pico_ppp_set_ip(ppp, ipaddr);
string dns_ip = cfgLoadStr("network", "DNS", "46.101.91.123");
pico_string_to_ipv4(dns_ip.c_str(), &ipaddr.addr);
pico_ppp_set_dns1(ppp, ipaddr);
#ifdef NETWORK_TAP
// TAP
// tap config:
// # ip tuntap add mode tap user joe
// # ifconfig tap0 192.168.5.5
// # ip link set tap0 up
// # ip route add <IP>/32 dev tap0 # where <IP> is the value of network:IP in emu.cfg./. This also allows proxy arp
// # echo '1' >/proc/sys/net/ipv4/conf/all/proxy_arp
// (or ...conf/tap0/proxy_arp and ...conf/eth0/proxy_arp only)
tap = pico_tap_create("tap0");
if (!tap)
{
stop_pico();
return false;
}
pico_string_to_ipv4("192.168.166.2", &ipaddr.addr);
pico_string_to_ipv4("255.255.255.0", &netmask.addr);
pico_ipv4_link_add(tap, ipaddr, netmask);
// Proxy ARP
pico_arp_create_entry(tap->eth->mac.addr, ipaddr, ppp);
#endif
#ifdef NETWORK_TUN
// TUN
// tun config:
// # ip tuntap add mode tun user joe
// # ip link set tun0 up
// # ip route add <IP>/32 dev tun0 # where <IP> is the value of network:IP in emu.cfg./. This also allows proxy arp
// # echo '1' >/proc/sys/net/ipv4/conf/all/proxy_arp
// (or ...conf/tun0/proxy_arp and ...conf/eth0/proxy_arp only)
tun = pico_tun_create("tun0");
if (!tun)
{
stop_pico();
return false;
}
pico_string_to_ipv4("192.168.166.1", &ipaddr.addr);
pico_string_to_ipv4("255.255.255.255", &netmask.addr);
pico_ipv4_link_add(tun, ipaddr, netmask);
#endif
// Default route
pico_string_to_ipv4("192.168.166.1", &ipaddr.addr);
pico_ipv4_route_add(zero, zero, ipaddr, 1, NULL);
pico_ppp_set_serial_read(ppp, modem_read);
pico_ppp_set_serial_write(ppp, modem_write);
pico_ppp_set_serial_set_speed(ppp, modem_set_speed);
pico_ppp_connect(ppp);
#ifdef DHCP
if (pico_dhcp_initiate_negotiation(tap, &callback_dhcpclient, &dhcpclient_xid) < 0)
{
printf("%s: error initiating negotiation: %s\n", __FUNCTION__, strerror(pico_err));
return false;
}
#endif
return true;
}
void stop_pico()
{
if (ppp)
{
pico_ppp_destroy(ppp);
ppp = NULL;
}
if (tap)
{
pico_device_destroy(tap);
tap = NULL;
}
if (tun)
{
pico_device_destroy(tun);
tun = NULL;
}
}

4
core/hw/modem/picoppp.h Normal file
View File

@ -0,0 +1,4 @@
bool start_pico();
void stop_pico();
void write_pico(u8 b);
int read_pico();

View File

@ -22,13 +22,16 @@
*/
#include "types.h"
#if HOST_OS == OS_LINUX
#if 1//HOST_OS == OS_LINUX
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <bitset>
#include <string>
#include "oslib/oslib.h"
#include "pppd.h"
static int pppd_pid;
@ -38,6 +41,11 @@ static int outpipe = -1;
static u8 in_buffer[128];
static int in_bufsize;
static int in_bufindex;
static bool v42_negotiate = false;
static u32 v42_odp_idx;
static u32 v42_odp_count;
const u8 v42_odp[] { 0x45, 0xfc, 0x17, 0xf9, 0x5f, 0xc4, 0x7f, 0x91, 0xff };
double last_adp_sent;
void start_pppd()
{
@ -75,6 +83,9 @@ void start_pppd()
inpipe = inpipefd[0];
outpipe = outpipefd[1];
fcntl(inpipe, F_SETFL, fcntl(inpipe, F_GETFL) | O_NONBLOCK);
in_bufindex = 0;
in_bufsize = 1;
in_buffer[0] = 0;
}
void stop_pppd()
@ -97,8 +108,89 @@ void stop_pppd()
}
}
static u8 reverse_bits(u8 x)
{
x = ((x * 0x0802 & 0x22110) | (x * 0x8020 & 0x88440)) * 0x10101 >> 16;
return x & 0xFF;
}
static void send_v42_adp()
{
in_bufsize = 0;
in_bufindex = 0;
// V.42 disabled E, 8-16 ones, NULL, 8-16 ones // FIXME leading one is a test
const std::string adp_nov42("1" "0101000101" "11111111" "0000000001" "11111111");
const std::string adp_v42("1" "0101000101" "11111111" "0110000101" "11111111");
const std::string& adp = adp_nov42;
const std::string ones("1111111111111111");
int adp_idx = 0;
for (int i = 0; i < 10; )
{
int end = min(adp_idx + 8, (int)adp.length());
std::string binary = adp.substr(adp_idx, end - adp_idx);
adp_idx += 8;
if (adp_idx > end)
{
adp_idx -= adp.length();
if (i == 9)
binary += ones.substr(0, adp_idx);
else
binary += adp.substr(0, adp_idx);
i++;
}
else
{
if (adp_idx >= adp.length())
{
adp_idx = 0;
i++;
}
}
std::bitset<8> bs(binary);
in_buffer[in_bufsize++] = reverse_bits(bs.to_ulong());
if (in_bufsize == sizeof(in_buffer))
{
printf("PPPD in buffer overflow\n");
return;
}
}
v42_negotiate = false;
}
void write_pppd(u8 b)
{
if (v42_negotiate)
{
if (b == v42_odp[v42_odp_idx])
{
v42_odp_idx++;
if (v42_odp_idx >= sizeof(v42_odp))
{
v42_odp_count++;
if (v42_odp_count >= 2)
{
if (last_adp_sent == 0 || os_GetSeconds() - last_adp_sent > 0.75) // T400
{
printf("PPPD V42 2 ODP received. Sending ADP\n");
last_adp_sent = os_GetSeconds();
send_v42_adp();
}
v42_odp_count = 0;
}
v42_odp_idx = 0;
}
}
else
{
v42_odp_idx = 0;
printf("PPPD ignored byte %02x\n", b);
}
return;
}
int rc = write(outpipe, &b, 1);
if (rc < 0)
perror("write outpipe");
@ -110,6 +202,11 @@ int read_pppd()
{
if (in_bufindex == in_bufsize)
{
in_bufindex = 0;
in_bufsize = 0;
if (v42_negotiate)
return -1;
int rc = read(inpipe, in_buffer, sizeof(in_buffer));
if (rc < 0)
{