diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 5eb091d58..e407d4364 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -15,7 +15,7 @@ set(net_sources) list(APPEND net_sources network.c net_pcap.c net_slirp.c net_dp8390.c net_3c501.c net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c net_null.c - net_eeprom_nmc93cxx.c net_tulip.c net_rtl8139.c net_l80225.c net_modem.c) + net_eeprom_nmc93cxx.c net_tulip.c net_rtl8139.c net_l80225.c net_modem.c utils/getline.c) find_package(PkgConfig REQUIRED) pkg_check_modules(SLIRP REQUIRED IMPORTED_TARGET slirp) diff --git a/src/network/net_modem.c b/src/network/net_modem.c index 97f038157..2396863bd 100644 --- a/src/network/net_modem.c +++ b/src/network/net_modem.c @@ -1,3 +1,6 @@ + +/* TODO: SLIP support. */ + #include #include #include @@ -14,6 +17,7 @@ #include <86box/fifo8.h> #include <86box/timer.h> #include <86box/serial.h> +#include <86box/plat.h> #include <86box/network.h> #include <86box/plat_unused.h> @@ -48,6 +52,18 @@ typedef enum modem_mode_t MODEM_MODE_DATA = 1 } modem_mode_t; +typedef enum modem_slip_stage_t +{ + MODEM_SLIP_STAGE_USERNAME, + MODEM_SLIP_STAGE_PASSWORD +} modem_slip_stage_t; + +typedef struct modem_phonebook_entry_t +{ + char phone[1024]; + char address[1024]; +} modem_phonebook_entry_t; + typedef struct modem_t { uint8_t mac[6]; @@ -90,6 +106,9 @@ typedef struct modem_t bool recCommand; uint8_t command; } telClient; + + modem_phonebook_entry_t entries[20]; + uint32_t entries_num; netcard_t *card; } modem_t; @@ -107,6 +126,43 @@ static modem_t *instance; static void modem_do_command(modem_t* modem); +extern ssize_t local_getline(char **buf, size_t *bufsiz, FILE *fp); + +static void +modem_read_phonebook_file(modem_t* modem, const char* path) +{ + FILE* file = plat_fopen(path, "r"); + char* buf = NULL; + size_t size = 0; + if (!file) + return; + + modem->entries_num = 0; + + while (local_getline(&buf, &size, file) != -1) { + modem_phonebook_entry_t entry = { { 0 }, { 0 } }; + int res = 0; + buf[strcspn(buf, "\r\n")] = 0; + + res = sscanf(buf, "%s %s", entry.phone, entry.address); + + if (res == 0 || res == 1) { + /* Appears to be a bad line. */ + continue; + } + + if (strspn(entry.phone, "01234567890*=,;#+>") != strlen(entry.phone)) { + /* Invalid characters. */ + continue; + } + + modem->entries[modem->entries_num++] = entry; + if (modem->entries_num >= 20) + break; + } + fclose(file); +} + static void modem_echo(modem_t* modem, uint8_t c) { @@ -190,6 +246,8 @@ process_tx_packet(modem_t *modem, uint8_t *p, uint32_t len) uint8_t *processed_tx_packet = calloc(len, 1); uint8_t c = 0; + pclog("Processing SLIP packet of %u bytes\n", len); + while (pos < len) { c = p[pos]; pos++; @@ -223,7 +281,18 @@ process_tx_packet(modem_t *modem, uint8_t *p, uint32_t len) } send_tx_packet: - network_tx(modem->card, processed_tx_packet, received); + if (received) + { + uint8_t* buf = calloc(received + 14, 1); + buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = 0xFF; + buf[6] = buf[7] = buf[8] = buf[9] = buf[10] = buf[11] = 0xFC; + buf[12] = 0x08; + buf[13] = 0x00; + memcpy(buf + 14, processed_tx_packet, received); + network_tx(modem->card, buf, received + 14); + free(processed_tx_packet); + free(buf); + } return; } @@ -267,7 +336,6 @@ host_to_modem_cb(void *priv) if (modem->mode == MODEM_MODE_DATA && fifo8_num_used(&modem->rx_data)) { serial_write_fifo(modem->serial, fifo8_pop(&modem->rx_data)); - fprintf(stderr, "(data)\n"); } else if (fifo8_num_used(&modem->data_pending)) { uint8_t val = fifo8_pop(&modem->data_pending); serial_write_fifo(modem->serial, val); @@ -326,11 +394,15 @@ modem_write(UNUSED(serial_t *s), void *priv, uint8_t txval) } void modem_send_res(modem_t* modem, const ResTypes response) { + char response_str_connect[256] = { 0 }; const char* response_str = NULL; uint32_t code = -1; + + snprintf(response_str_connect, sizeof(response_str_connect), "CONNECT %u", modem->baudrate); + switch (response) { case ResOK: code = 0; response_str = "OK"; break; - case ResCONNECT: code = 1; response_str = "CONNECT 33600"; break; + case ResCONNECT: code = 1; response_str = response_str_connect; break; case ResRING: code = 2; response_str = "RING"; break; case ResNOCARRIER: code = 3; response_str = "NO CARRIER"; break; case ResERROR: code = 4; response_str = "ERROR"; break; @@ -416,9 +488,13 @@ void modem_dial(modem_t* modem, const char* str) { /* TODO: Port TCP/IP support from DOSBox. */ - if (!strncmp(str, "0.0.0.0", sizeof("0.0.0.0") - 1)) { + if (!strncmp(str, "0.0.0.0", sizeof("0.0.0.0") - 1)) + { + pclog("Turning on SLIP\n"); modem_enter_connected_state(modem); - } else { + } + else + { modem_send_res(modem, ResNOCARRIER); modem_enter_idle_state(modem); } @@ -779,19 +855,31 @@ fifo8_resize_2x(Fifo8* fifo) static int modem_rx(void *priv, uint8_t *buf, int io_len) { +#if 1 modem_t* modem = (modem_t*)priv; uint8_t c = 0; uint32_t i = 0; if (!modem->connected) { /* Drop packet. */ + pclog("Dropping %d bytes\n", io_len - 14); return 0; } - if ((io_len) <= (fifo8_num_free(&modem->rx_data) / 2)) { + if ((io_len) >= (fifo8_num_free(&modem->rx_data))) { fifo8_resize_2x(&modem->rx_data); } + if (!(buf[12] == 0x08 && buf[13] == 0x00)) { + pclog("Dropping %d bytes (non-IP packet (ethtype 0x%02X%02X))\n", io_len - 14, buf[12], buf[13]); + return 0; + } + + pclog("Receiving %d bytes\n", io_len - 14); + /* Strip the Ethernet header. */ + io_len -= 14; + buf += 14; + fifo8_push(&modem->rx_data, END); for (i = 0; i < io_len; i++) { switch (buf[i]) { @@ -810,6 +898,7 @@ modem_rx(void *priv, uint8_t *buf, int io_len) } fifo8_push(&modem->rx_data, END); return 1; +#endif } static void diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 6aff76a90..599ee896d 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -37,6 +37,7 @@ #include <86box/ini.h> #include <86box/config.h> #include <86box/video.h> +#include <86box/bswap.h> #define _SSIZE_T_DEFINED #include @@ -76,6 +77,29 @@ typedef struct net_slirp_t { #endif } net_slirp_t; +/* Pulled off from libslirp code. This is only needed for modem. */ +#pragma pack(push, 1) +struct arphdr_local { + unsigned char h_dest[6]; /* destination eth addr */ + unsigned char h_source[6]; /* source ether addr */ + unsigned short h_proto; /* packet type ID field */ + + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + + /* + * Ethernet looks like this : This bit is variable sized however... + */ + uint8_t ar_sha[6]; /* sender hardware address */ + uint32_t ar_sip; /* sender IP address */ + uint8_t ar_tha[6]; /* target hardware address */ + uint32_t ar_tip; /* target IP address */ +}; +#pragma pack(pop) + #ifdef ENABLE_SLIRP_LOG int slirp_do_log = ENABLE_SLIRP_LOG; @@ -455,6 +479,32 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv #ifdef _WIN32 slirp->sock_event = CreateEvent(NULL, FALSE, FALSE, NULL); #endif + + if (!strcmp(network_card_get_internal_name(net_cards_conf[net_card_current].device_num), "modem")) { + /* Send a gratuitous ARP here to make SLiRP work properly with SLIP connections. */ + struct arphdr_local arphdr; + /* ARP part. */ + arphdr.ar_hrd = bswap16(1); + arphdr.ar_pro = bswap16(0x0800); + arphdr.ar_hln = 6; + arphdr.ar_pln = 4; + arphdr.ar_op = bswap16(1); + memcpy(&arphdr.ar_sha, mac_addr, 6); + memcpy(&arphdr.ar_tha, mac_addr, 6); + arphdr.ar_sip = dhcp.s_addr; + arphdr.ar_tip = dhcp.s_addr; + + /* Ethernet header part. */ + arphdr.h_proto = bswap16(0x0806); + memset(arphdr.h_dest, 0xff, 6); + memset(arphdr.h_source, 0x52, 6); + arphdr.h_source[2] = 0x0a; + arphdr.h_source[3] = 0x00; + arphdr.h_source[4] = slirp_card_num; + arphdr.h_source[5] = 2; + slirp_input(slirp->slirp, (const uint8_t *)&arphdr, sizeof(struct arphdr_local)); + } + slirp_log("SLiRP: creating thread...\n"); slirp->poll_tid = thread_create(net_slirp_thread, slirp); diff --git a/src/network/network.c b/src/network/network.c index 94403c2f4..fe3bf8489 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -454,6 +454,7 @@ netcard_t * network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_link_state) { netcard_t *card = calloc(1, sizeof(netcard_t)); + int net_type = net_cards_conf[net_card_current].net_type; card->queued_pkt.data = calloc(1, NET_MAX_FRAME); card->card_drv = card_drv; card->rx = rx; @@ -470,7 +471,12 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin network_queue_init(&card->queues[i]); } - switch (net_cards_conf[net_card_current].net_type) { + if (!strcmp(network_card_get_internal_name(net_cards_conf[net_card_current].device_num), "modem") && net_type >= NET_TYPE_PCAP) { + /* Force SLiRP here. Modem only operates on non-Ethernet frames. */ + net_type = NET_TYPE_SLIRP; + } + + switch (net_type) { case NET_TYPE_SLIRP: card->host_drv = net_slirp_drv; card->host_drv.priv = card->host_drv.init(card, mac, NULL, net_drv_error); diff --git a/src/network/utils/getline.c b/src/network/utils/getline.c new file mode 100644 index 000000000..69ee258fd --- /dev/null +++ b/src/network/utils/getline.c @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +ssize_t +local_getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) +{ + char *ptr, *eptr; + + + if (*buf == NULL || *bufsiz == 0) { + *bufsiz = BUFSIZ; + if ((*buf = malloc(*bufsiz)) == NULL) + return -1; + } + + for (ptr = *buf, eptr = *buf + *bufsiz;;) { + int c = fgetc(fp); + if (c == -1) { + if (feof(fp)) { + ssize_t diff = (ssize_t)(ptr - *buf); + if (diff != 0) { + *ptr = '\0'; + return diff; + } + } + return -1; + } + *ptr++ = c; + if (c == delimiter) { + *ptr = '\0'; + return ptr - *buf; + } + if (ptr + 2 >= eptr) { + char *nbuf; + size_t nbufsiz = *bufsiz * 2; + ssize_t d = ptr - *buf; + if ((nbuf = realloc(*buf, nbufsiz)) == NULL) + return -1; + *buf = nbuf; + *bufsiz = nbufsiz; + eptr = nbuf + nbufsiz; + ptr = nbuf + d; + } + } +} + +ssize_t +local_getline(char **buf, size_t *bufsiz, FILE *fp) +{ + return local_getdelim(buf, bufsiz, '\n', fp); +}