1
0
mirror of https://github.com/Interlisp/maiko.git synced 2026-01-15 07:54:13 +00:00
Interlisp.maiko/src/ether_nethub.c
Nick Briggs 1c6277d313 Clean up usage of the native address of the I/O page and its struct typedef
The global variable holding the native address of the I/O page is spelled "IOPage"
The global variable "IOPage" is declared extern by "lspglob.h"
The structure pointed to by IOPage is named IOPAGE and is defined in "iopage.h"
If there is no direct reference to the IOPAGE struct do not include "iopage.h"
2023-02-17 17:01:27 -08:00

577 lines
17 KiB
C

/*******************************************************************************/
/* */
/* Support for Dodo Nethub networking (see: https://github.com/devhawala/dodo) */
/* */
/* Copyright (c) 2022, Dr. Hans-Walter Latz. All rights reserved. */
/* Released to the Public Domain. */
/* */
/*******************************************************************************/
#if defined(MAIKO_ENABLE_NETHUB) && !defined(MAIKO_ENABLE_ETHERNET)
#include "version.h"
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/poll.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include "commondefs.h"
#include "lispemul.h"
#include "lispmap.h"
#include "emlglob.h"
#include "lsptypes.h"
#include "lspglob.h"
#include "adr68k.h"
#include "ether.h"
#include "dbprint.h"
#include "etherdefs.h"
#include "ifpage.h"
#include "byteswapdefs.h"
#include "dbprint.h"
#include "timerdefs.h"
#include "lisp2cdefs.h"
/*
** --- ether implementation common data -------------------------------------------
*/
extern int ether_fd; /* file descriptor for ether socket */
extern u_char ether_host[6]; /* 48 bit address of this node */
extern u_char broadcast[6];
extern int ether_bsize; /* if nonzero then a receive is pending */
extern u_char *ether_buf; /* address of receive buffer */
extern LispPTR *PENDINGINTERRUPT68k;
extern fd_set LispReadFds;
/*
** --- nethub configuration data --------------------------------------------------
*/
static char* nethubHost = NULL;
static int nethubPort = 3333;
static int mac0 = 0xCA;
static int mac1 = 0xFF;
static int mac2 = 0xEE;
static int mac3 = 0x12;
static int mac4 = 0x34;
static int mac5 = 0x56;
void setNethubHost(char* host) {
if (host && *host) {
nethubHost = host;
DBPRINT(("nh :: host now: '%s'\n", nethubHost));
}
}
void setNethubPort(int port) {
if (port > 0 && port <= 65535) {
nethubPort = port;
DBPRINT(("nh :: port now: %d\n", nethubPort));
}
}
void setNethubMac(int m0, int m1, int m2, int m3, int m4, int m5) {
if ( m0 >= 0 && m0 <= 255
&& m1 >= 0 && m1 <= 255
&& m2 >= 0 && m2 <= 255
&& m3 >= 0 && m3 <= 255
&& m4 >= 0 && m4 <= 255
&& m5 >= 0 && m5 <= 255) {
mac0 = m0;
mac1 = m1;
mac2 = m2;
mac3 = m3;
mac4 = m4;
mac5 = m5;
DBPRINT(("nh :: mac now: %02X-%02X-%02X-%02X-%02X-%02X\n", mac0, mac1, mac2, mac3, mac4, mac5));
}
}
/*
** --- very simple logging --------------------------------------------------------
*/
static int loglevel = 0;
static int logcnt = 0;
void setNethubLogLevel(int ll) {
loglevel = ll;
DBPRINT(("nh :: loglevel now: %d\n", loglevel));
}
#define log_info(line) { if (loglevel == 1) \
{ printf("nh-info[%d]: ", logcnt++); printf line; }}
#define log_debug(line) { if (loglevel >= 2) \
{ printf("nh-debug[%d]: ", logcnt++); printf line; }}
#define log_all(line) { if (loglevel < 1) \
{ printf("nh[%d]: ", logcnt++); printf line; }}
/*
** --- utilities ------------------------------------------------------------------
*/
#define LONG_PTR_MASK ((long)(~((long)3)))
static void dblwordsSwap(u_char* basePtr, int forBytes) {
u_char* dblwordPtr = (u_char*)((long)basePtr & LONG_PTR_MASK);
int neededBytes = forBytes + (basePtr - dblwordPtr);
int dblwordCount = (neededBytes + 3) / 4;
word_swap_page((unsigned short*)dblwordPtr, dblwordCount);
}
/*
** --- connect, disconnect and transmit packets -----------------------------------
*/
void connectToHub(void) {
if (nethubHost == NULL) {
return;
}
if (ether_fd > -1) {
return;
}
log_debug(("connectToHub() - begin\n"));
ether_host[0] = mac0;
ether_host[1] = mac1;
ether_host[2] = mac2;
ether_host[3] = mac3;
ether_host[4] = mac4;
ether_host[5] = mac5;
log_debug((" resolving nethub hostname\n"));
struct hostent *host = gethostbyname(nethubHost);
if (host == NULL || host->h_addr_list == NULL) {
log_debug(("connectToHub(): hostname '%s' cannot be resolved\n", nethubHost));
log_info(("connectToHub(): hostname '%s' cannot be resolved\n", nethubHost));
log_all(("connectToHub(): hostname '%s' cannot be resolved\n", nethubHost));
return;
}
log_debug((" connecting to nethub\n"));
struct sockaddr_in hubaddr;
hubaddr.sin_family = AF_INET;
hubaddr.sin_addr.s_addr = *(in_addr_t *)host->h_addr_list[0];
hubaddr.sin_port = htons(nethubPort);
ether_fd = socket(AF_INET, SOCK_STREAM, 0);
if (ether_fd < 0) {
log_info(("connectToHub(): FAILED to create AF_INET/SOCK_STREAM socket\n"));
return;
}
if (connect(ether_fd, (struct sockaddr*)&hubaddr, sizeof(hubaddr)) < 0) {
perror("connectToHub() - connect failed");
close(ether_fd);
ether_fd = -1;
log_info(("connectToHub(): FAILED to connect to nethub\n"));
return;
}
log_debug((" connected to nethub, ether_fd = %d\n", ether_fd));
FD_SET(ether_fd, &LispReadFds);
log_debug((" added ether_fd to LispReadFds\n"));
log_debug(("connectToHub() - end\n\n"));
log_info(("connectToHub() - connected to nethub\n"));
log_all(("connectToHub() - connected to nethub\n"));
}
static void disconnectFromHub(void) {
if (ether_fd > -1) {
close(ether_fd);
ether_fd = -1;
log_debug(("disconnectFromHub() - disconnected from nethub\n"));
log_info(("disconnectFromHub() - disconnected from nethub\n"));
log_all(("disconnectFromHub() - disconnected from nethub\n"));
}
}
/* Input:
* ether_fd: fd to read Nethub format packets from
* ether_bsize: size of ether_buf storage
* Output:
* ether_buf: buffer to copy XIP packet into
* ether_bsize: set to 0 if packet returned
* Returns:
* -1: failed/not connected
* 0: no packet available
* >0: number of bytes received and placed in ether_buf
*/
static int recvPacket(void) {
int rcvLen;
unsigned short bLen;
if (ether_fd < 0) {
log_debug((" recvPacket() :: not connected to hub !!!\n"));
return -1;
}
if (ether_bsize < 1) {
log_debug((" recvPacket() :: no receive buffer present -> return 0\n"));
return 0;
}
/* start by reading the (network byte order) short value indicating the size of the
* XIP packet being received
*/
rcvLen = recv(ether_fd, &bLen, sizeof(bLen), MSG_DONTWAIT);
if (rcvLen < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
perror("recvPacket() :: recv(ether_fd, &bLen, sizeof(bLen), MSG_DONTWAIT)");
disconnectFromHub();
return -1;
}
if (rcvLen <= 0) {
log_debug((" recvPacket() :: no network packet available -> return 0\n"));
return 0;
}
bLen = ntohs(bLen);
log_debug((" recvPacket() :: received %d bytes, logical packet length = %d bytes\n", rcvLen, bLen));
if (bLen & 0x0001) {
log_debug(("recvPacket() ERROR :: odd byte length of logical packet -> disconnecting from nethub\n"));
log_info(("recvPacket() ERROR :: odd byte length of logical packet -> disconnecting from nethub\n"));
log_all(("recvPacket() ERROR :: odd byte length of logical packet -> disconnecting from nethub\n"));
disconnectFromHub();
return -1;
}
if (bLen > ether_bsize) {
log_debug((" recvPacket() ERROR :: logical packet larger than buffer -> disconnecting from nethub\n"));
log_info(("recvPacket() ERROR :: logical packet larger than buffer -> disconnecting from nethub\n"));
log_all(("recvPacket() ERROR :: logical packet larger than buffer -> disconnecting from nethub\n"));
disconnectFromHub();
return -1;
}
/* continue reading the XIP packet of the just determined size
*/
rcvLen = recv(ether_fd, ether_buf, bLen, MSG_DONTWAIT);
if (rcvLen < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
perror("recvPacket() :: recv(ether_fd, ether_buf, bLen, MSG_DONTWAIT)");
disconnectFromHub();
return -1;
}
if (rcvLen <= 0) {
log_debug((" recvPacket() :: no network packet available -> return 0\n"));
return 0;
}
if (bLen != rcvLen) {
log_debug((" recvPacket() WARNING :: packet size mismatch -> discard packet -> return 0\n"));
log_info(("recvPacket() WARNING :: packet size mismatch -> discard packet -> return 0\n"));
log_all(("recvPacket() WARNING :: packet size mismatch -> discard packet -> return 0\n"));
return 0;
}
if (bLen < 14) {
/* not even enough bytes for the ethernet header */
/* -> discard packet */
log_debug((" recvPacket() WARNING :: packet too small -> discard packet -> return 0\n"));
log_info(("recvPacket() WARNING :: packet too small -> discard packet -> return 0\n"));
log_all(("recvPacket() WARNING :: packet too small -> discard packet -> return 0\n"));
return 0;
}
if ( memcmp(ether_buf, ether_host, 6) != 0
&& memcmp(ether_buf, broadcast, 6) != 0) {
log_debug((" recvPacket() :: packet is not for us and not a broadcast, ignoring packet\n"));
return 0;
}
#if defined(BYTESWAP)
log_debug((" recvPacket() :: byte-swapping %d bytes at %p\n", bLen, (void *)ether_buf));
dblwordsSwap(ether_buf, bLen);
IOPage->dlethernet[2] = bLen;
#else
log_debug((" recvPacket() :: %d bytes at %p\n", bLen, (void *)ether_buf));
IOPage->dlethernet[3] = bLen;
#endif
ether_bsize = 0;
return bLen;
}
/* -1: failed/not connected; >= 0: packet bytes sent */
static int sendPacket(u_char *source, int sourceLen) {
struct msghdr msg = {0};
struct iovec iov[2];
uint16_t nhlength;
if (ether_fd < 0) {
log_debug((" sendPacket() :: not connected to hub !!!\n"));
return -1;
}
if (sourceLen < 14) {
log_debug((" sendPacket() :: invalid packet length: %d !!!\n", sourceLen));
return -1;
}
if (sourceLen & 0x0001) {
log_debug((" sendPacket() :: packet length not even (mutiple of 2) !!!\n"));
return -1;
}
nhlength = htons(sourceLen);
iov[0].iov_base = &nhlength;
iov[0].iov_len = 2;
iov[1].iov_base = source;
iov[1].iov_len = sourceLen;
msg.msg_iov = iov;
msg.msg_iovlen = 2;
int result = sendmsg(ether_fd, &msg, 0);
return result;
}
/*
** --- SUBR implementations -------------------------------------------------------
*/
/************************************************************************/
/* */
/* e t h e r _ s u s p e n d */
/* */
/* Suspend receiving packets. */
/* 175/70/0 */
/* */
/************************************************************************/
LispPTR ether_suspend(LispPTR args[])
{
if (nethubHost == NULL) {
return (ATOM_T);
}
log_debug(("ether_suspend() -- ignored!\n\n"));
log_info(("ether_suspend()\n"));
return (ATOM_T);
}
/************************************************************************/
/* */
/* e t h e r _ r e s u m e */
/* */
/* resume nit socket to receive all types of packets 175/71/0 */
/* */
/************************************************************************/
LispPTR ether_resume(LispPTR args[])
{
if (nethubHost == NULL) {
return (ATOM_T);
}
log_debug(("ether_resume() - begin\n"));
int_io_open(ether_fd);
log_debug(("ether_resume() - end\n\n"));
log_info(("ether_resume()\n"));
return (ATOM_T);
}
/************************************************************************/
/* */
/* e t h e r _ c t r l r */
/* */
/* return T if ether controller is available 175/72/0 */
/* */
/************************************************************************/
LispPTR ether_ctrlr(LispPTR args[])
{
if (nethubHost == NULL) {
return (NIL);
}
log_debug(("ether_ctrlr() - begin\n"));
connectToHub();
if (ether_fd < 0) {
log_debug(("ether_ctrlr() - end -> NIL\n\n"));
log_info(("ether_ctrlr() -> NIL\n"));
return (NIL);
} else {
int_io_open(ether_fd);
log_debug(("ether_ctrlr() - end -> ATOM_T\n\n"));
log_info(("ether_ctrlr() -> ATOM_T\n"));
return (ATOM_T);
}
}
/**********************************************************************
* ether_reset(args) 175/73/0
* reset ether controller and disable receipt of packets
**********************************************************************/
LispPTR ether_reset(LispPTR args[])
{
if (nethubHost == NULL) {
return (NIL);
}
log_debug(("ether_reset() - begin\n"));
if (ether_fd < 0) {
log_debug(("ether_reset() - end -> NIL\n\n"));
log_info(("ether_reset() -> NIL\n"));
return (NIL);
}
ether_bsize = 0; /* deactivate receiver */
log_debug(("ether_reset() - end -> ATOM_T\n\n"));
log_info(("ether_reset() -> ATOM_T\n"));
return (ATOM_T);
}
/************************************************************************/
/* */
/* e t h e r _ g e t (175/74/2) */
/* */
/* Set up the Ethernet driver to receive a packet. The driver */
/* first tries to read any pending packet from the net, and if */
/* there is one, ether_get returns T. If there is no pending */
/* packet, the failing read sets us up to get an interrupt when */
/* a packet DOES arrive, and ether_get returns NIL. */
/* */
/* args[0] Length of the buffer we're passed */
/* args[1] LISP address of a packet buffer */
/* */
/* sets ether_buf to the buffer address, for check_ether's use */
/* sets ether_bsize to the buffer size. ether_bsize>0 means */
/* it's OK to read packets from the network on interrupt. */
/* */
/************************************************************************/
LispPTR ether_get(LispPTR args[])
{
int receivedBytes;
u_char *target;
int maxByteCount;
if (nethubHost == NULL) {
return (NIL);
}
log_debug(("ether_get() - begin\n"));
target = (u_char *)NativeAligned2FromLAddr(args[1]);
maxByteCount = 2 * LispIntToCInt(args[0]); /* words to bytes */
log_debug((" target = %p maxBytecount: %d bytes\n", (void *)target, maxByteCount));
ether_buf = target;
ether_bsize = maxByteCount;
receivedBytes = recvPacket();
log_debug(("ether_get() :: receivedBytes: %d bytes\n", receivedBytes));
if (receivedBytes <= 0) {
log_debug(("ether_get() - end -> NIL\n\n"));
return (NIL);
}
log_debug(("ether_get() - end -> ATOM_T\n\n"));
log_info(("ether_get(): received packet, len = %d bytes\n", receivedBytes));
return (ATOM_T);
}
/**********************************************************************
* ether_send(args) 175/75/2 max_words,buffer_addr
* send a packet
**********************************************************************/
LispPTR ether_send(LispPTR args[])
{
if (nethubHost == NULL) {
return (NIL);
}
log_debug(("ether_send() - begin\n"));
u_char *source = (u_char *)NativeAligned2FromLAddr(args[1]);
int byteCount = 2 * LispIntToCInt(args[0]); /* words to bytes */
log_debug((" source = %p , bytecount: %d bytes\n", (void *)source, byteCount));
#if defined(BYTESWAP)
dblwordsSwap(source, byteCount);
int bytesSent = sendPacket(source, byteCount);
dblwordsSwap(source, byteCount);
#else
int bytesSent = sendPacket(source, byteCount);
#endif
if (bytesSent < 0) {
log_debug(("ether_send() - failed (bytesSent: %d bytes) -> NIL\n\n", bytesSent));
log_info(("ether_send(): FAILED to send packet, len = %d\n", byteCount));
return (NIL);
}
log_debug(("ether_send() - end -> ATOM_T\n\n"));
log_info(("ether_send(): sent packet, len = %d\n", bytesSent));
return (ATOM_T);
}
/**********************************************************************
* ether_setfilter(args) 175/76/1 filterbits
* check whether a packet has come. if does, notify iocb
**********************************************************************/
LispPTR ether_setfilter(LispPTR args[])
{
log_debug(("ether_setfilter() - ????\n\n"));
return (NIL);
}
/**********************************************************************
* check_ether() 175/77/0
* checks an incoming packet
**********************************************************************/
LispPTR check_ether(void)
{
int receivedBytes;
struct pollfd pfds[1];
if (ether_fd < 0) {
return (NIL);
}
log_debug(("check_ether() - begin\n"));
pfds[0].fd = ether_fd;
pfds[0].events = POLLIN;
pfds[0].revents = 0;
poll(pfds, 1, 0);
if (!(pfds[0].revents & POLLIN)) {
log_debug(("check_ether() - poll end -> NIL\n\n"));
return (NIL);
}
receivedBytes = recvPacket();
if (receivedBytes <= 0) {
log_debug(("check_ether() - data end -> NIL\n\n"));
return (NIL);
}
((INTSTAT *)NativeAligned4FromLAddr(*INTERRUPTSTATE_word))->ETHERInterrupt = 1;
Irq_Stk_Check = Irq_Stk_End = 0; /* ??? */
*PENDINGINTERRUPT68k = (ATOM_T);
log_debug(("check_ether() :: raised LISP interrupt\n"));
log_debug(("check_ether() :: INTERRUPTSTATE_word = 0x%08X\n",
*((int*)NativeAligned4FromLAddr(*INTERRUPTSTATE_word))));
log_info(("check_ether(): received packet, len = %d bytes\n", receivedBytes));
log_debug(("check_ether() - end -> ATOM_T\n\n"));
return (ATOM_T);
}
#endif /* MAIKO_ENABLE_NETHUB */