1
0
mirror of https://github.com/Interlisp/maiko.git synced 2026-01-14 15:36:34 +00:00
Nick Briggs a5410ef93d
Cleanup USE_DPLI usage (#378)
Until now, the only differentiation between using DLPI and using NIT for
the ethernet interface was expressed as a function of USE_DLPI.

This commit makes explicit when code is for the DLPI interface or the NIT
interface, with USE_DLPI and USE_NIT.  This is setup for using the BPF
interface to the ethernet as an alternative.
2021-04-07 20:51:28 -07:00

1132 lines
35 KiB
C

/* $Id: ether.c,v 1.4 2001/12/24 01:09:02 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved */
/************************************************************************/
/* */
/* (C) Copyright 1989-1996 inclusive Venue. All Rights Reserved. */
/* Manufactured in the United States of America. */
/* */
/************************************************************************/
#include "version.h"
#if defined(USE_DLPI)
#define PKTFILTER 1
#define NIOCSFLAGS SBIOCSFLAGS
#endif
#ifdef OS4
#define PKTFILTER 1
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#ifndef DOS
#include <sys/file.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#ifdef MAIKO_ENABLE_ETHERNET
#include <sys/socket.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#if defined(USE_DLPI)
#include "dlpidefs.h"
#elif defined(USE_NIT)
#include <net/nit.h>
#endif
#include <sys/ioctl.h>
#ifdef PKTFILTER
#include <stropts.h>
#include <fcntl.h>
#ifdef OS4
#include <net/nit_if.h>
#include <net/nit_pf.h>
/* #include <net/nit_buf.h> */
#include <net/packetfilt.h>
#else
#include <sys/pfmod.h>
#include <sys/bufmod.h>
#endif /* OS4 */
#endif /* PKTFILTER */
#if defined(USE_NIT)
#include <sys/mbuf.h>
#endif
#include <nlist.h>
#endif /* DOS */
#endif /* MAIKO_ENABLE_ETHERNET */
#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"
#if defined(USE_DLPI)
#define NIOCSETF PFIOCSETF
#endif
int ether_fd = -1; /* file descriptor for ether socket */
int ether_intf_type = 0;
u_char ether_host[6] = {0, 0, 0, 0, 0, 0}; /* 48 bit address of this node */
u_char broadcast[6] = {255, 255, 255, 255, 255, 255};
int ether_bsize = 0; /* if nonzero then a receive is pending */
u_char *ether_buf; /* address of receive buffer */
u_char nit_buf[3000]; /* the current chunk read from NIT (one packet) */
extern LispPTR *PENDINGINTERRUPT68k;
extern fd_set LispReadFds;
int ETHEREventCount = 0;
#define PacketTypeIP 0x0800
#define PacketTypeARP 0x0806
#define PacketTypeRARP 0x8035
#define PacketTypeXNS 0x0600
#define PacketTypePUP 0x0200
#define PacketType3TO10 0x0201
#ifdef MAIKO_ENABLE_ETHERNET
#ifdef PKTFILTER
/* the receiving packetfilter structure */
/* if this is changed, be sure to get the references to it in init_ether
and check the length (the second entry in the structure) */
/*
PACKET FILTERS
A packet filter consists of the filter command list length
(in units of u_shorts), and the filter command list itself.
(The priority field mentioned above is ignored in this
implementation.) Each filter command list specifies a
sequence of actions that operate on an internal stack of
u_shorts ("shortwords"). Each shortword of the command list
specifies one of the actions ENF_PUSHLIT, ENF_PUSHZERO, or
ENF_PUSHWORD+n, which respectively push the next shortword
of the command list, zero, or shortword n of the subject
message on the stack, and a binary operator from the set {
ENF_EQ, ENF_NEQ, ENF_LT, ENF_LE, ENF_GT, ENF_GE, ENF_AND,
ENF_OR, ENF_XOR } which then operates on the top two ele-
ments of the stack and replaces them with its result. When
both an action and operator are specified in the same short-
word, the action is performed followed by the operation.
The binary operator can also be from the set { ENF_COR,
ENF_CAND, ENF_CNOR, ENF_CNAND }. These are "short-circuit"
operators, in that they terminate the execution of the
filter immediately if the condition they are checking for is
found, and continue otherwise. All pop two elements from
the stack and compare them for equality; ENF_CAND returns
false if the result is false; ENF_COR returns true if the
result is true; ENF_CNAND returns true if the result is
false; ENF_CNOR returns false if the result is true. Unlike
the other binary operators, these four do not leave a result
on the stack, even if they continue.
The short-circuit operators should be used when possible, to
reduce the amount of time spent evaluating filters. When
they are used, you should also arrange the order of the
tests so that the filter will succeed or fail as soon as
possible; for example, checking the IP destination field of
a UDP packet is more likely to indicate failure than the
packet type field.
The special action ENF_NOPUSH and the special operator
ENF_NOP can be used to only perform the binary operation or
to only push a value on the stack. Since both are (con-
veniently) defined to be zero, indicating only an action
actually specifies the action followed by ENF_NOP, and indi-
cating only an operation actually specifies ENF_NOPUSH fol-
lowed by the operation.
After executing the filter command list, a non-zero value
(true) left on top of the stack (or an empty stack) causes
the incoming packet to be accepted and a zero value (false)
causes the packet to be rejected. (If the filter exits as
the result of a short-circuit operator, the top-of-stack
value is ignored.) Specifying an undefined operation or
action in the command list or performing an illegal opera-
tion or action (such as pushing a shortword offset past the
end of the packet or executing a binary operator with fewer
than two shortwords on the stack) causes a filter to reject
the packet.
*/
/* ethertype == IP => reject
ethertype == ARP => reject
(dest[0:1] == us &&
dest[2:3] == us &&
dest[4:5] == us)
||
(dest[0:1] == broadcast &&
dest[2:3] == broadcast &&
dest[4:5] == broadcast)
*/
struct packetfilt goodpf = {0,
29,
{ENF_PUSHWORD + 6, /* Ethertype field */
ENF_PUSHLIT + ENF_CNOR,
PacketTypeIP, /* punt if PacketTypeIP = 0x0800 */
ENF_PUSHWORD + 6,
ENF_PUSHLIT + ENF_CNOR,
PacketTypeARP, /* or PacketTypeARP = 0x0806 */
ENF_PUSHWORD,
ENF_PUSHLIT + ENF_EQ,
8, /* check our addr */
ENF_PUSHWORD + 1,
ENF_PUSHLIT + ENF_EQ,
11, /* which is filled in */
ENF_PUSHWORD + 2,
ENF_PUSHLIT + ENF_EQ,
14, /* in init_ether */
ENF_AND,
ENF_AND,
ENF_PUSHWORD,
ENF_PUSHLIT + ENF_EQ,
0xFFFF, /* check broadcast */
ENF_PUSHWORD + 1,
ENF_PUSHLIT + ENF_EQ,
0xFFFF, /* which is all ones */
ENF_PUSHWORD + 2,
ENF_PUSHLIT + ENF_EQ,
0xFFFF,
ENF_AND,
ENF_AND,
ENF_OR}};
/* struct packetfilt allpf = {0, 1, {ENF_PUSHFFFF}}; */
/* a filter that rejects all packets to be used by ether_suspend and the
initial routine to flush out ether_fd */
struct packetfilt nopf = {0, 1, {ENF_PUSHZERO}};
#endif /* PKTFILTER */
int ether_in = 0; /* number of packets received */
int ether_out = 0; /* number of packets sent */
#ifndef PKTFILTER
static struct nit_ioc nioc;
#endif /* PKTFILTER */
#endif /* MAIKO_ENABLE_ETHERNET */
/************************************************************************/
/* */
/* e t h e r _ s u s p e n d */
/* */
/* Suspend receiving packets from the NIT socket. */
/* 175/70/0 */
/* */
/************************************************************************/
LispPTR ether_suspend(LispPTR args[])
{
#ifdef MAIKO_ENABLE_ETHERNET
#ifdef PKTFILTER
static struct packetfilt pf = {0, 1, {ENF_PUSHZERO}};
struct strioctl si;
#endif /* PKTFILTER */
if (ether_fd == -1) return (NIL);
#ifndef PKTFILTER
nioc.nioc_typetomatch = NT_NOTYPES;
if (ioctl(ether_fd, SIOCSNIT, &nioc) != 0) {
printf("ether_suspend: ioctl failed\n");
return (NIL);
}
#else /* PKTFILTER */
/* The trick here is to install a packet filter */
/* that rejects all packets, I think... */
#if defined(USE_DLPI)
si.ic_cmd = PFIOCSETF;
si.ic_timout = -1;
si.ic_len = sizeof(nopf);
si.ic_dp = (char *)&nopf;
if (ioctl(ether_fd, I_STR, &si) < 0) {
perror("ether_suspend nopf ioctl: I_STR PFIOCSETF");
return (NIL);
}
#elif defined(USE_NIT)
if (ioctl(ether_fd, NIOCSETF, &nopf) != 0) {
perror("ether_suspend: NIOCSETF failed\n");
return (NIL);
}
#endif /* USE_DLPI */
#endif /* PKTFILTER */
#endif /* MAIKO_ENABLE_ETHERNET */
return (ATOM_T);
} /* ether_suspend */
/************************************************************************/
/* */
/* 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[])
{
#ifdef MAIKO_ENABLE_ETHERNET
struct strioctl si;
if (ether_fd == -1) return (NIL);
#ifndef PKTFILTER
nioc.nioc_typetomatch = NT_ALLTYPES;
if (ioctl(ether_fd, SIOCSNIT, &nioc) != 0) {
printf("ether_resume: ioctl failed\n");
return (NIL);
}
#else /* PKTFILTER */
/* Install a packet filter that accepts all packets we want */
#if defined(USE_DLPI)
si.ic_cmd = PFIOCSETF;
si.ic_timout = -1;
si.ic_len = sizeof(goodpf);
si.ic_dp = (char *)&goodpf;
if (ioctl(ether_fd, I_STR, &si) < 0) {
perror("ether_resume goodpf ioctl: I_STR PFIOCSETF");
return (NIL);
}
#elif defined(USE_NIT)
if (ioctl(ether_fd, NIOCSETF, &goodpf) != 0) {
perror("ether_resume: NIOCSETF failed\n");
return (NIL);
}
#endif /* USE_DLPI */
#endif /* PKTFILTER */
#endif /* MAIKO_ENABLE_ETHERNET */
return (ATOM_T);
} /* ether_resume */
/************************************************************************/
/* */
/* 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 (ether_fd < 0) return (NIL);
return (ATOM_T);
}
/**********************************************************************
* ether_reset(args) 175/73/0
* reset ether controller and disable receipt of packets
**********************************************************************/
LispPTR ether_reset(LispPTR args[])
{
if (ether_fd < 0) { return (NIL); }
/* JRB - host number check removed here; if ether_fd is open here,
net is on... */
ether_bsize = 0; /* deactivate receiver */
return (ATOM_T);
} /* ether_reset */
/************************************************************************/
/* */
/* 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[])
{
LispPTR result = NIL;
#ifdef MAIKO_ENABLE_ETHERNET
LispPTR MaxByteCount;
sigset_t signals;
MaxByteCount = 2 * (0xFFFF & args[0]); /* words to bytes */
DBPRINT(("Ether Get. "));
sigemptyset(&signals);
sigaddset(&signals, SIGIO);
/* turn off ENET interrupts */
sigprocmask(SIG_BLOCK, &signals, NULL);
if (ether_fd > 0 && (MaxByteCount > 0)) {
ether_buf = (u_char *)Addr68k_from_LADDR(args[1]);
ether_bsize = MaxByteCount; /* do this LAST; it enables reads */
result = get_packet();
/* check_ether(); for old behavior, move comment to above line */
}
/* enable interrupts */
sigprocmask(SIG_UNBLOCK, &signals, NULL);
#endif /* MAIKO_ENABLE_ETHERNET */
return (result);
} /* ether_get */
/**********************************************************************
* ether_send(args) 175/75/2 max_words,buffer_addr
* send a packet
**********************************************************************/
#define OFFSET sizeof(sa.sa_data)
LispPTR ether_send(LispPTR args[])
{
#ifdef MAIKO_ENABLE_ETHERNET
/*
* Send a packet.
*/
struct sockaddr sa;
LispPTR MaxByteCount;
u_char *BufferAddr; /* buffer address pointer(in native address) */
MaxByteCount = 2 * (0xFFFF & args[0]); /* words to bytes */
BufferAddr = (u_char *)Addr68k_from_LADDR(args[1]);
if (ether_fd > 0) {
#ifdef PKTFILTER
struct strbuf ctl, data;
#endif /* PKTFILTER */
sa.sa_family = AF_UNSPEC; /* required for the NIT protocol */
memcpy(sa.sa_data, BufferAddr, OFFSET);
#ifndef PKTFILTER
if (sendto(ether_fd, BufferAddr + OFFSET, MaxByteCount - OFFSET, 0, &sa, sizeof(sa)) ==
(MaxByteCount - OFFSET))
;
else
perror("Lisp Ether: sendto");
ether_out++;
#elif defined(USE_DLPI)
if (dlunitdatareq(ether_fd, BufferAddr, 6, 0, 0, BufferAddr, MaxByteCount)) {
perror("unitdatareq");
return (NIL);
}
ether_out++;
ioctl(ether_fd, I_FLUSH, FLUSHW);
#else /* PKTFILTER */
ctl.maxlen = ctl.len = sizeof(sa);
ctl.buf = (char *)&sa;
data.maxlen = data.len = MaxByteCount - OFFSET;
data.buf = BufferAddr + OFFSET;
if (putmsg(ether_fd, &ctl, &data, 0) < 0) {
perror("Ether_send lost");
return (NIL);
} else {
ether_out++;
/* flush the buffers to make sure the packet leaves */
/* maybe we'll use the buffering module some day... */
ioctl(ether_fd, I_FLUSH, FLUSHW);
}
#endif /* PKTFILTER */
}
#endif /* MAIKO_ENABLE_ETHERNET */
return (ATOM_T);
} /* ether_send */
/**********************************************************************
* ether_setfilter(args) 175/75/1 filterbits
* check whether a packet has come. if does, notify iocb
**********************************************************************/
LispPTR ether_setfilter(LispPTR args[])
{ return (NIL); } /* ether_setfilter */
/**********************************************************************
* ether_debug()
* returns the ethernet statistics.
**********************************************************************/
int estat[3];
int *ether_debug() {
#ifdef MAIKO_ENABLE_ETHERNET
estat[0] = 0;
if (ether_fd < 0) return (NIL);
printf("fd %d bsize %d buf %X icb %X in %d out %d\n ", ether_fd, ether_bsize, (int)ether_buf,
IOPage->dlethernet[3], ether_in, ether_out);
#endif /* MAIKO_ENABLE_ETHERNET */
return (estat);
} /* end ether_debug */
#ifdef MAIKO_ENABLE_ETHERNET
static struct timeval EtherTimeout = {0, 0};
#endif /* MAIKO_ENABLE_ETHERNET */
/**********************************************************************
* check_ether()
* checks an incoming packet
**********************************************************************/
#ifdef MAIKO_ENABLE_ETHERNET
#ifndef PKTFILTER
static int nitpos = 0, nitlen = 0; /* for NIT read buffer in OS3 */
#endif
#endif
LispPTR check_ether() {
/*
* If receiver active then check if any packets are
* available from the ethernet. If so, read the packet
* and signal the icb and return T.
*/
#ifdef MAIKO_ENABLE_ETHERNET
#ifndef PKTFILTER
fd_set rfds;
int result, fromlen;
struct nit_hdr header;
int posi, i;
#else /* PKTFILTER */
fd_set rfds;
int result;
int i;
int plen;
struct strbuf ctl, data;
char ctlbuf[2000];
#endif /* PKTFILTER */
FD_SET(ether_fd, &rfds);
#ifndef PKTFILTER
i = 2;
if (/* select(32, &rfds, NULL, NULL, &EtherTimeout) >= 0 ) */ (1)) {
if ((ether_fd >= 0) && (ether_bsize > 0)) {
while ((select(32, &rfds, NULL, NULL, &EtherTimeout) >= 0) && (i-- > 0)) {
if (nitpos >= nitlen) { /* Used up last NIT buffer full; read another. */
nitlen = read(ether_fd, nit_buf, sizeof(nit_buf));
nitpos = 0;
}
/* enumerate the NIT headers until the packet is found */
while (nitpos < nitlen) {
memcpy(&header, &nit_buf[nitpos], sizeof(header));
nitpos += sizeof(header);
switch (header.nh_state) {
case NIT_CATCH:
fromlen = header.nh_datalen;
if (check_filter(&nit_buf[nitpos])) {
memcpy(&ether_buf[0], &nit_buf[nitpos], fromlen);
ether_bsize = 0; /* deactivate receiver */
ether_in++;
IOPage->dlethernet[3] = fromlen;
DBPRINT(
("Found packet len %d, at pos %d in buflen %d.\n", fromlen, nitpos, nitlen));
nitpos += fromlen;
((INTSTAT *)Addr68k_from_LADDR(*INTERRUPTSTATE_word))->ETHERInterrupt = 1;
ETHEREventCount++;
Irq_Stk_Check = Irq_Stk_End = 0;
*PENDINGINTERRUPT68k = ATOM_T;
/* return(NIL); */
return (ATOM_T);
}
nitpos += fromlen;
break;
/* ignore all the other header types */
case NIT_QUIET: break;
case NIT_NOMBUF: DBPRINT(("No MBUFs\n")); break;
case NIT_NOCLUSTER: DBPRINT(("No Clusters\n")); break;
case NIT_NOSPACE: DBPRINT(("No Space\n")); break;
case NIT_SEQNO: break;
}
}
}
}
}
#else /* PKTFILTER */
if (ether_fd >= 0 && ether_bsize > 0
/* && select(32, &rfds, NULL, NULL, &EtherTimeout) >= 0
* -- [on '90/02/14: getsignsldata() check this] */
&& (FD_ISSET(ether_fd, &rfds))) {
data.maxlen = sizeof(nit_buf);
data.len = 0;
data.buf = (char *)nit_buf;
ctl.maxlen = sizeof(ctlbuf);
ctl.len = 0;
ctl.buf = ctlbuf;
plen = 0;
result = getmsg(ether_fd, &ctl, &data, &plen);
if (result >= 0) {
if (data.len <= ether_bsize && data.len > 0) {
memcpy(&ether_buf[0], nit_buf, data.len);
ether_bsize = 0;
ether_in++;
IOPage->dlethernet[3] = data.len;
((INTSTAT *)Addr68k_from_LADDR(*INTERRUPTSTATE_word))->ETHERInterrupt = 1;
ETHEREventCount++;
Irq_Stk_Check = Irq_Stk_End = 0;
*PENDINGINTERRUPT68k = ATOM_T;
return (NIL); /* return(ATOM_T); */
}
} else if (errno != EWOULDBLOCK) {
perror("Check_ether read error:\n");
}
}
#endif /* PKTFILTER */
#endif /* MAIKO_ENABLE_ETHERNET */
return (NIL);
} /* end check_ether */
/************************************************************************/
/* */
/* g e t _ p a c k e t */
/* */
/* Try getting a packet, ala check_ether, returning NIL if none, */
/* T if one was received. This is used by ether_get only. */
/* */
/************************************************************************/
LispPTR get_packet() {
#ifdef MAIKO_ENABLE_ETHERNET
#ifndef PKTFILTER
fd_set rfds;
int result, fromlen;
struct nit_hdr header;
int posi, i;
#else /* PKTFILTER */
fd_set rfds;
int result;
int i;
int plen;
struct strbuf ctl, data;
char ctlbuf[2000];
#endif /* PKTFILTER */
#ifndef PKTFILTER
while (1) {
if (nitpos >= nitlen) { /* Used up last NIT buffer full; read another. */
nitlen = read(ether_fd, nit_buf, sizeof(nit_buf));
if (nitlen < 0) return (NIL); /* No more packets to try. */
nitpos = 0;
}
/* enumerate the NIT headers until the packet is found */
while (nitpos < nitlen) {
memcpy(&header, &nit_buf[nitpos], sizeof(header));
nitpos += sizeof(header);
switch (header.nh_state) {
case NIT_CATCH:
fromlen = header.nh_datalen;
if (check_filter(&nit_buf[nitpos])) {
memcpy(&ether_buf[0], &nit_buf[nitpos], fromlen);
ether_bsize = 0; /* deactivate receiver */
ether_in++;
IOPage->dlethernet[3] = fromlen;
DBPRINT(("Found packet len %d, at pos %d in buflen %d.\n", fromlen, nitpos, nitlen));
nitpos += fromlen;
return (ATOM_T);
}
nitpos += fromlen;
break;
/* ignore all the other header types */
case NIT_QUIET: break;
case NIT_NOMBUF: DBPRINT(("No MBUFs\n")); break;
case NIT_NOCLUSTER: DBPRINT(("No Clusters\n")); break;
case NIT_NOSPACE: DBPRINT(("No Space\n")); break;
case NIT_SEQNO: break;
}
}
}
#else /* PKTFILTER */
data.maxlen = sizeof(nit_buf);
data.len = 0;
data.buf = (char *)nit_buf;
ctl.maxlen = sizeof(ctlbuf);
ctl.len = 0;
ctl.buf = ctlbuf;
plen = 0;
result = getmsg(ether_fd, &ctl, &data, &plen);
if (result >= 0) {
if (ctl.len > 0) printf("ctl msg rcvd.\n");
if (data.len <= ether_bsize && data.len > 0) {
memcpy(&ether_buf[0], nit_buf, data.len);
ether_bsize = 0;
ether_in++;
IOPage->dlethernet[3] = data.len;
return (ATOM_T);
}
} else if (errno != EWOULDBLOCK)
perror("Check_ether read error:\n");
#endif /* PKTFILTER */
#endif /* MAIKO_ENABLE_ETHERNET */
return (NIL);
} /* end get_packet */
#ifdef MAIKO_ENABLE_ETHERNET
/**********************************************************************
* ether_addr_equal(add1, add2)
* checks ethernet addresses equality
* Also believed obsolete
**********************************************************************/
static int ether_addr_equal(u_char add1[], u_char add2[])
{
register int i;
for (i = 0; i < 6; i++)
if (add1[i] != add2[i]) return (0);
return (1);
}
/**********************************************************************
* check_filter(buffer)
* see if this packet passes the current filter setting
* This is believed obsolete with packet filtering enabled
**********************************************************************/
static int check_filter(u_char *buffer)
{
/* broadcast packets */
if (ether_addr_equal(buffer, broadcast)) switch (((short *)buffer)[6]) {
case PacketTypeIP: return (0);
case PacketTypeARP: return (0);
default: return (1);
};
/* my address */
if (ether_addr_equal(buffer, ether_host)) switch (((short *)buffer)[6]) {
case PacketTypeIP: return (0);
case PacketTypeARP: return (0);
default: return (1);
};
return (0);
}
/**********************************************************************
* init_uid()
* sets effective user-id to real user-id
**********************************************************************/
static void init_uid() {
int rid;
rid = getuid();
seteuid(rid);
}
#endif /* MAIKO_ENABLE_ETHERNET */
/************************************************************************/
/* i n i t _ i f p a g e _ e t h e r */
/* */
/* sets Lisp's idea of \my.nsaddress. Clears it if ether not */
/* enabled */
/* */
/************************************************************************/
void init_ifpage_ether() {
InterfacePage->nshost0 = (DLword)((ether_host[0] << 8) + ether_host[1]);
InterfacePage->nshost1 = (DLword)((ether_host[2] << 8) + ether_host[3]);
InterfacePage->nshost2 = (DLword)((ether_host[4] << 8) + ether_host[5]);
}
#ifdef MAIKO_ENABLE_ETHERNET
/* this needs to be a global so the name can be set by main() in Ctest */
/* But MAIKO_ENABLE_ETHERNET doesn't support NIT, so dyke it out for MAIKO_ENABLE_ETHERNET */
#if defined(USE_NIT)
struct sockaddr_nit snit;
#endif /* USE_NIT */
#endif /* MAIKO_ENABLE_ETHERNET */
/************************************************************************/
/* i n i t _ e t h e r */
/* */
/* open nit socket, called from main before starting BCE. */
/* */
/************************************************************************/
void init_ether() {
#ifdef MAIKO_ENABLE_ETHERNET
/* JRB - This code will have to be a bit different for SUN 4.0; the probable
differences are in commented-out code below
(not ifdefed because they're untested...)
*/
struct strioctl si;
unsigned long snaplen = 0;
/* ((INTSTAT*)Addr68k_from_LADDR(*INTERRUPTSTATE_word))->ETHERInterrupt = 0;
((INTSTAT2 *)Addr68k_from_LADDR(*INTERRUPTSTATE_word))->handledmask = 0;
*/
if (ether_fd < 0) {
/* it's not open yet, try and open it;
if it's already open here, it was opened by ldeether and
all the appropriate stuff was done to it there.
*/
#if defined(USE_DLPI)
/* Use DLPI to connect to the ethernet. This code is stolen
from NFSWATCH4.3
*/
/* if (getuid() != geteuid()) */
{
if ((ether_fd = setup_dlpi_dev(NULL)) > 0) { /* Open an ether interface */
ether_intf_type = dlpi_devtype(ether_fd);
/* first and foremost, get the packet filter module attached
(used for ether_suspend and ether_resume) */
if (ioctl(ether_fd, I_PUSH, "pfmod") < 0) {
perror("IOCTL push of pf lost");
close(ether_fd);
goto I_Give_Up;
}
si.ic_cmd = PFIOCSETF;
si.ic_timout = -1;
si.ic_len = sizeof(nopf);
si.ic_dp = (char *)&nopf;
if (ioctl(ether_fd, I_STR, &si) < 0) {
perror("ioctl: I_STR PFIOCSETF");
return;
}
fcntl(ether_fd, F_SETFL, fcntl(ether_fd, F_GETFL, 0) | O_NONBLOCK);
} else {
I_Give_Up:
/* JDS 991228 remove perror("Can't open network; XNS unavailable.\n"); */
ether_fd = -1;
}
seteuid(getuid());
}
#elif defined(USE_NIT)
#ifndef OS4
if (getuid() != geteuid()) {
if ((ether_fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW)) >= 0) {
/* 4.0: socket -> open("/dev/nit", O_BOTH) */
/* it's open, now query it and find out its name and address */
/* JRB - must document that Maiko uses the first net board as
found by SIOCGIFCONF (see if(4)). Maybe we need an option to
specify which net board (suspect more than one net board on a
Maiko machine will be rare, but...).
*/
struct ifconf if_data;
struct ifreq ifbuf[20];
if_data.ifc_len = sizeof(ifbuf);
if_data.ifc_req = ifbuf;
/* 4.0 - before the SIOCGIFCONF, do:
memset(ifbuf, 0, sizeof(ifbuf))
*/
if (ioctl(ether_fd, SIOCGIFCONF, &if_data) < 0) {
perror("Couldn't GIFCONF socket; Net is off");
#else /* OS4 */
if (getuid() != geteuid()) {
if ((ether_fd = open("/dev/nit", O_RDWR | O_ASYNC)) >= 0) {
/* it's open, now query it and find out its name and address */
/* JRB - must document that LDE uses the first net board as
found by SIOCGIFCONF (see if(4)). Maybe we need an option
to specify which net board (suspect more than one net
board on an LDE machine will be rare, but...).
*/
struct ifconf if_data;
struct ifreq ifbuf[20];
/* first and foremost, get the packet filter module attached
(used for ether_suspend and ether_resume) */
if (ioctl(ether_fd, I_PUSH, "pf") < 0) {
perror("IOCTL push of pf lost");
close(ether_fd);
goto I_Give_Up;
}
if_data.ifc_len = sizeof(ifbuf);
if_data.ifc_req = ifbuf;
memset(ifbuf, 0, sizeof(ifbuf));
{
/* we have to get the interface name from another socket, since
/dev/nit doesn't know anything until it gets bound, and we
can't bind it without knowing the interface name... */
int s;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("No socket for interface name");
close(s);
#endif /* OS4 */
close(ether_fd);
ether_fd = -1;
#ifndef OS4
return;
#else /* OS4 */
goto I_Give_Up;
#endif /* OS4 */
}
#ifndef OS4
/* got its name, copy it into snit */
strcpy(snit.snit_ifname, if_data.ifc_req[0].ifr_name);
/* 4.0, before the SIOCGIFADDR, do:
ioctl(ether_fd, NIOCBIND, &if_data.ifc_req[0])
*/
/* now for the address */
if (ioctl(ether_fd, SIOCGIFADDR, &if_data.ifc_req[0]) < 0) {
perror("Couldn't GIFADDR socket: Net is off");
#else /* OS4 */
if (ioctl(s, SIOCGIFCONF, (char *)&if_data) < 0) {
perror("Couldn't get interface name from socket");
close(s);
#endif /* OS4 */
close(ether_fd);
ether_fd = -1;
#ifndef OS4
return (NIL);
#else /* OS4 */
goto I_Give_Up;
#endif /* OS4 */
}
#ifndef OS4
memcpy(ether_host, if_data.ifc_req[0].ifr_addr.sa_data, 6);
init_uid();
}
#else /* OS4 */
(void)close(s);
#endif /* OS4 */
}
#ifdef OS4
if (ioctl(ether_fd, NIOCBIND, &if_data.ifc_req[0]) < 0) {
perror("Couldn't NIOCBIND socket: Net is off");
close(ether_fd);
ether_fd = -1;
goto I_Give_Up;
}
/* now for the address */
if (ioctl(ether_fd, SIOCGIFADDR, &if_data.ifc_req[0]) < 0) {
perror("Couldn't GIFADDR socket: Net is off");
close(ether_fd);
ether_fd = -1;
goto I_Give_Up;
}
memcpy(ether_host, if_data.ifc_req[0].ifr_addr.sa_data, 6);
DBPRINT(("init_ether: **** Ethernet starts ****\n"));
} else {
I_Give_Up:
perror("Can't open network; XNS unavailable.\n");
ether_fd = -1;
}
seteuid(getuid());
}
#endif /* OS4 */
#endif /* USE_DLPI */
}
/******************************/
/* Have now either opened enet here, or in ldeether */
/***************************************************/
if (ether_fd >= 0) {
#ifndef PKTFILTER
/* bind the socket to an interface */
snit.snit_family = AF_NIT;
bind(ether_fd, &snit, sizeof(snit));
#else /* PKTFILTER */
/* I think all you really have to do here is set the SNAP length, flags,
and configure the buffering module */
struct timeval zerotime;
#endif /* PKTFILTER */
#ifndef PKTFILTER
/* establish the operating modes */
memset(&nioc, 0, sizeof(nioc));
nioc.nioc_bufspace = 20000;
nioc.nioc_chunksize = 50; /* small chunks so each packet read */
nioc.nioc_typetomatch = NT_ALLTYPES;
nioc.nioc_snaplen = 32767;
nioc.nioc_flags = 0;
if (ioctl(ether_fd, SIOCSNIT, &nioc) != 0) {
printf("init_ether: ioctl failed\n");
close(ether_fd);
ether_fd = -1;
return;
}
#else /* PKTFILTER */
/* first and foremost, flush out ether_fd's buffers and filter it */
/* install packetfilter that rejects everything */
#if defined(USE_DLPI)
si.ic_cmd = PFIOCSETF;
si.ic_timout = -1;
si.ic_len = sizeof(nopf);
si.ic_dp = (char *)&nopf;
if (ioctl(ether_fd, I_STR, &si) < 0) {
perror("init_ether nopf ioctl: I_STR PFIOCSETF");
close(ether_fd);
ether_fd = -1;
return;
}
#elif defined(USE_NIT)
if (ioctl(ether_fd, NIOCSETF, &nopf) != 0) {
perror("init_ether: nopf NIOCSETF failed:\n");
close(ether_fd);
ether_fd = -1;
return;
}
#endif /* USE_DLPI */
#endif /* PKTFILTER -- jds 23 sep 96 unmatched if fix */
#ifndef PKTFILTER
if (fcntl(ether_fd, F_SETFL, fcntl(ether_fd, F_GETFL, 0) | O_ASYNC | O_NONBLOCK) < 0)
perror("Ether setup SETFLAGS fcntl");
if (fcntl(ether_fd, F_SETOWN, getpid()) < 0) perror("Ether setup SETOWN");
#else /* PKTFILTER */
/* then throw away everything that's currently buffered there;
this descriptor may have been open since ldeether ran, with
no filtering; a busy net will have stuffed it full */
#if defined(USE_DLPI)
if (ioctl(ether_fd, I_FLUSH, (char *)FLUSHR) < 0) { perror("init_ether I_FLUSH"); }
#elif defined(USE_NIT)
{
FD_SET(ether_fd, &rfds);
while (select(32, &rfds, NULL, NULL, &EtherTimeout) > 0)
read(ether_fd, nit_buf, sizeof(nit_buf));
}
#endif /* USE_DLPI */
/* put the address into the packetfilter structure */
/* DANGER! Vulnerable to byte ordering! DANGER! */
goodpf.Pf_Filter[8] = (DLword)((ether_host[0] << 8) + ether_host[1]);
goodpf.Pf_Filter[11] = (DLword)((ether_host[2] << 8) + ether_host[3]);
goodpf.Pf_Filter[14] = (DLword)((ether_host[4] << 8) + ether_host[5]);
/* and set up the packetfilter */
#if defined(USE_DLPI)
si.ic_cmd = PFIOCSETF;
si.ic_timout = -1;
si.ic_len = sizeof(goodpf);
si.ic_dp = (char *)&goodpf;
if (ioctl(ether_fd, I_STR, &si) < 0) {
perror("init_ether goodpf ioctl: I_STR PFIOCSETF");
close(ether_fd);
ether_fd = -1;
return;
}
#else
if (ioctl(ether_fd, NIOCSETF, &goodpf) != 0) {
perror("init_ether: NIOCSETF failed:\n");
close(ether_fd);
ether_fd = -1;
return;
}
#endif /* USE_DLPI */
#if defined(USE_NIT)
DBPRINT(("INIT ETHER: Doing I_SETSIG.\n"));
if (ioctl(ether_fd, I_SETSIG, S_INPUT) != 0) {
perror("init_ether: I_SETSIG failed:\n");
close(ether_fd);
ether_fd = -1;
return;
}
#endif /* USE_NIT */
#endif /* PKTFILTER */
if (ether_fd < 0) error ("ether_fd is -1, but enet opened??");
FD_SET(ether_fd, &LispReadFds);
DBPRINT(("init_ether: **** Ethernet starts ****\n"));
}
#endif /* MAIKO_ENABLE_ETHERNET */
}
#define MASKWORD1 0xffff
/************************************************************************/
/* */
/* c h e c k _ s u m */
/* */
/* Implements the CHECKSUM opcode; compute the checksum for an */
/* ethernet packet. */
/* */
/* args[0] LispPTR base; */
/* args[1] LispPTR nwords; */
/* args[2] LispPTR initsum; */
/* */
/* */
/************************************************************************/
LispPTR check_sum(register LispPTR *args)
{
register LispPTR checksum;
register DLword *address;
register int nwords;
address = (DLword *)Addr68k_from_LADDR(*args++);
nwords = *args++;
if (*args != NIL)
checksum = (*args) & MASKWORD1;
else
checksum = 0;
for (; nwords > (S_POSITIVE); address++, nwords--) {
checksum = checksum + GETWORD(address);
if (checksum > 0xffff) checksum = (checksum & 0xffff) + 1; /* add carry */
if (checksum > 0x7fff) /* ROTATE LEFT 1 */
checksum = ((checksum & 0x7fff) << 1) | 1;
else
checksum = checksum << 1;
}
if (checksum == MASKWORD1)
return (S_POSITIVE); /* ret 0 */
else
return (S_POSITIVE | checksum);
} /*check_sum */