M pc/devether.c => pc/devether.c +22 -0
@@ 385,6 385,28 @@ etherreset(void)
free(ether);
}
+#define POLY 0xedb88320
+
+/* really slow 32 bit crc for ethers */
+ulong
+ethercrc(uchar *p, int len)
+{
+ int i, j;
+ ulong crc, b;
+
+ crc = 0xffffffff;
+ for(i = 0; i < len; i++){
+ b = *p++;
+ for(j = 0; j < 8; j++){
+ crc = (crc>>1);
+ if((crc^b) & 1)
+ crc ^= POLY;
+ b >>= 1;
+ }
+ }
+ return crc;
+}
+
Dev etherdevtab = {
'l',
"ether",
M pc/ether8390.c => pc/ether8390.c +56 -0
@@ 620,6 620,59 @@ promiscuous(void *arg, int on)
r = Ab;
if(on)
r |= Pro;
+ if(ether->nmaddr)
+ r |= Am;
+ ilock(ctlr);
+ regw(ctlr, Rcr, r);
+ iunlock(ctlr);
+}
+
+static void
+multicast(void* arg, uchar *addr, int on)
+{
+ Ether *ether;
+ Dp8390 *ctlr;
+ uchar r, cr;
+ int i;
+ ulong h;
+
+ USED(addr, on);
+
+ ether = arg;
+ ctlr = ether->ctlr;
+
+ /*
+ * change filter bits
+ */
+ h = ethercrc(addr, 6);
+ h = h>>(32-6);
+ i = h/8;
+ h = h%8;
+ ilock(ctlr);
+ cr = regr(ctlr, Cr) & ~Txp;
+ regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
+ r = regr(ctlr, Mar0+i);
+ if(on){
+ if(++(ctlr->mref[h]) == 1)
+ r |= 1<<h;
+ } else {
+ if(--(ctlr->mref[h]) <= 0){
+ ctlr->mref[h] = 0;
+ r &= ~(1<<h);
+ }
+ }
+ regw(ctlr, Mar0+i, r);
+ regw(ctlr, Cr, cr);
+ iunlock(ctlr);
+
+ /*
+ * Set/reset promiscuous mode.
+ */
+ r = Ab;
+ if(ether->nmaddr)
+ r |= Am;
+ if(ether->prom)
+ r |= Pro;
ilock(ctlr);
regw(ctlr, Rcr, r);
iunlock(ctlr);
@@ 642,6 695,8 @@ attach(Ether* ether)
r = Ab;
if(ether->prom)
r |= Pro;
+ if(ether->nmaddr)
+ r |= Am;
ilock(ctlr);
regw(ctlr, Rcr, r);
r = regr(ctlr, Cntr2);
@@ 719,6 774,7 @@ dp8390reset(Ether* ether)
ether->ifstat = 0;
ether->promiscuous = promiscuous;
+ ether->multicast = multicast;
ether->arg = ether;
return 0;
M pc/ether8390.h => pc/ether8390.h +2 -0
@@ 19,6 19,8 @@ typedef struct {
int txbusy; /* transmit */
uchar tstart; /* 8390 ring addresses */
+
+ int mref[64]; /* reference counts for multicast groups */
} Dp8390;
#define Dp8390BufSz 256
M pc/etherelnk3.c => pc/etherelnk3.c +3 -1
@@ 467,10 467,12 @@ multicast(void* arg, uchar *addr, int on)
ether = (Ether*)arg;
port = ether->port;
-print("mutlicast nmaddr == %d\n", ether->nmaddr);
+print("multicast nmaddr == %d\n", ether->nmaddr);
filter = receiveBroadcast|receiveIndividual;
if(ether->nmaddr)
filter |= receiveMulticast;
+ if(ether->prom)
+ filter |= receiveAllFrames;
COMMAND(port, SetRxFilter, filter);
}
M pc/etherif.h => pc/etherif.h +1 -0
@@ 24,6 24,7 @@ struct Ether {
extern Block* etheriq(Ether*, Block*, int);
extern void addethercard(char*, int(*)(Ether*));
+extern ulong ethercrc(uchar*, int);
#define NEXT(x, l) (((x)+1)%(l))
#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
M pc/fns.h => pc/fns.h +1 -2
@@ 48,11 48,10 @@ void insl(int, void*, int);
void intrenable(int, void (*)(Ureg*, void*), void*, int);
int iprint(char*, ...);
int isaconfig(char*, int, ISAConf*);
-ulong getisa(ulong, int, int);
-void putisa(ulong, int);
void kbdinit(void);
void lgdt(ushort[3]);
void lidt(ushort[3]);
+void links(void);
void ltr(ulong);
void mathinit(void);
#define mmuflushtlb(pdb) putcr3(pdb)
M port/portfns.h => port/portfns.h +0 -1
@@ 135,7 135,6 @@ void kprocchild(Proc*, void (*)(void*), void*);
void (*kproftimer)(ulong);
void ksetenv(char*, char*);
long latin1(uchar*, int);
-void links(void);
void lock(Lock*);
void lockinit(void);
Page* lookpage(Image*, ulong);