From 6699a8a29444efd8a66f8bcd01f245b3d481ea04 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Sat, 15 Sep 2018 21:41:54 +0200 Subject: [PATCH] Use picotcp for ppp protocol processing. Now all is needed is a tap or tun interface. --- core/deps/picotcp/modules/pico_arp.c | 9 +- core/deps/picotcp/modules/pico_dev_ppp.c | 217 +++++++++++++++++------ core/deps/picotcp/modules/pico_dev_ppp.h | 4 + core/deps/picotcp/modules/pico_dev_tap.c | 10 +- core/deps/picotcp/modules/pico_dev_tap.h | 2 +- core/deps/picotcp/modules/pico_dev_tun.c | 4 +- core/deps/picotcp/modules/pico_dev_tun.h | 2 +- core/deps/picotcp/modules/pico_ipv4.c | 5 +- core/hw/modem/modem.cpp | 7 + core/hw/modem/picoppp.cpp | 213 ++++++++++++++++++++++ core/hw/modem/picoppp.h | 4 + core/hw/modem/pppd.cpp | 99 ++++++++++- 12 files changed, 503 insertions(+), 73 deletions(-) create mode 100644 core/hw/modem/picoppp.cpp create mode 100644 core/hw/modem/picoppp.h diff --git a/core/deps/picotcp/modules/pico_arp.c b/core/deps/picotcp/modules/pico_arp.c index 8b4b68f8c..4a026506e 100644 --- a/core/deps/picotcp/modules/pico_arp.c +++ b/core/deps/picotcp/modules/pico_arp.c @@ -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)) { diff --git a/core/deps/picotcp/modules/pico_dev_ppp.c b/core/deps/picotcp/modules/pico_dev_ppp.c index e778b1629..5dc0188b8 100644 --- a/core/deps/picotcp/modules/pico_dev_ppp.c +++ b/core/deps/picotcp/modules/pico_dev_ppp.c @@ -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; +} diff --git a/core/deps/picotcp/modules/pico_dev_ppp.h b/core/deps/picotcp/modules/pico_dev_ppp.h index 5d479c486..a00147243 100644 --- a/core/deps/picotcp/modules/pico_dev_ppp.h +++ b/core/deps/picotcp/modules/pico_dev_ppp.h @@ -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 */ diff --git a/core/deps/picotcp/modules/pico_dev_tap.c b/core/deps/picotcp/modules/pico_dev_tap.c index 877941f45..c5d8ff641 100644 --- a/core/deps/picotcp/modules/pico_dev_tap.c +++ b/core/deps/picotcp/modules/pico_dev_tap.c @@ -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 #include #include -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] = {}; diff --git a/core/deps/picotcp/modules/pico_dev_tap.h b/core/deps/picotcp/modules/pico_dev_tap.h index 384226ed6..e67f8a7a3 100644 --- a/core/deps/picotcp/modules/pico_dev_tap.h +++ b/core/deps/picotcp/modules/pico_dev_tap.h @@ -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 diff --git a/core/deps/picotcp/modules/pico_dev_tun.c b/core/deps/picotcp/modules/pico_dev_tun.c index 148ad921f..8721b0ea2 100644 --- a/core/deps/picotcp/modules/pico_dev_tun.c +++ b/core/deps/picotcp/modules/pico_dev_tun.c @@ -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)); diff --git a/core/deps/picotcp/modules/pico_dev_tun.h b/core/deps/picotcp/modules/pico_dev_tun.h index 85b9dbf94..c31436d43 100644 --- a/core/deps/picotcp/modules/pico_dev_tun.h +++ b/core/deps/picotcp/modules/pico_dev_tun.h @@ -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 diff --git a/core/deps/picotcp/modules/pico_ipv4.c b/core/deps/picotcp/modules/pico_ipv4.c index fda8178da..631f21fdd 100644 --- a/core/deps/picotcp/modules/pico_ipv4.c +++ b/core/deps/picotcp/modules/pico_ipv4.c @@ -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); diff --git a/core/hw/modem/modem.cpp b/core/hw/modem/modem.cpp index 7b5f3c20b..0077605be 100644 --- a/core/hw/modem/modem.cpp +++ b/core/hw/modem/modem.cpp @@ -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 diff --git a/core/hw/modem/picoppp.cpp b/core/hw/modem/picoppp.cpp new file mode 100644 index 000000000..444e28ac1 --- /dev/null +++ b/core/hw/modem/picoppp.cpp @@ -0,0 +1,213 @@ +#include + +extern "C" { +#include +#include +#include +#include +#include +#ifdef DHCP +#include +#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 in_buffer; +static std::queue 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 /32 dev tap0 # where 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 /32 dev tun0 # where 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; + } +} diff --git a/core/hw/modem/picoppp.h b/core/hw/modem/picoppp.h new file mode 100644 index 000000000..b2d6ac5d2 --- /dev/null +++ b/core/hw/modem/picoppp.h @@ -0,0 +1,4 @@ +bool start_pico(); +void stop_pico(); +void write_pico(u8 b); +int read_pico(); diff --git a/core/hw/modem/pppd.cpp b/core/hw/modem/pppd.cpp index 39f9a8b88..cd6e09a24 100644 --- a/core/hw/modem/pppd.cpp +++ b/core/hw/modem/pppd.cpp @@ -22,13 +22,16 @@ */ #include "types.h" -#if HOST_OS == OS_LINUX +#if 1//HOST_OS == OS_LINUX #include #include #include #include #include +#include +#include +#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) {