1458db832SDavid du Colombier #include "u.h"
2458db832SDavid du Colombier #include "../port/lib.h"
3458db832SDavid du Colombier #include "mem.h"
4458db832SDavid du Colombier #include "dat.h"
5458db832SDavid du Colombier #include "fns.h"
6458db832SDavid du Colombier #include "io.h"
7458db832SDavid du Colombier #include "ureg.h"
8458db832SDavid du Colombier #include "../port/error.h"
9458db832SDavid du Colombier #include "../port/netif.h"
10458db832SDavid du Colombier
11458db832SDavid du Colombier #include "etherif.h"
12458db832SDavid du Colombier
13458db832SDavid du Colombier static Ether *etherxx[MaxEther];
144de34a7eSDavid du Colombier extern uchar etheraddr[];
15458db832SDavid du Colombier
16458db832SDavid du Colombier Chan*
etherattach(char * spec)17458db832SDavid du Colombier etherattach(char* spec)
18458db832SDavid du Colombier {
19458db832SDavid du Colombier ulong ctlrno;
20458db832SDavid du Colombier char *p;
21458db832SDavid du Colombier Chan *chan;
22458db832SDavid du Colombier
23458db832SDavid du Colombier ctlrno = 0;
24458db832SDavid du Colombier if(spec && *spec){
25458db832SDavid du Colombier ctlrno = strtoul(spec, &p, 0);
26458db832SDavid du Colombier if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
27458db832SDavid du Colombier error(Ebadarg);
28458db832SDavid du Colombier }
29458db832SDavid du Colombier if(etherxx[ctlrno] == 0)
30458db832SDavid du Colombier error(Enodev);
31458db832SDavid du Colombier
32458db832SDavid du Colombier chan = devattach('l', spec);
33458db832SDavid du Colombier chan->dev = ctlrno;
34458db832SDavid du Colombier if(etherxx[ctlrno]->attach)
35458db832SDavid du Colombier etherxx[ctlrno]->attach(etherxx[ctlrno]);
36458db832SDavid du Colombier return chan;
37458db832SDavid du Colombier }
38458db832SDavid du Colombier
39458db832SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)40458db832SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
41458db832SDavid du Colombier {
42458db832SDavid du Colombier return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
43458db832SDavid du Colombier }
44458db832SDavid du Colombier
45458db832SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)46458db832SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
47458db832SDavid du Colombier {
48458db832SDavid du Colombier return netifstat(etherxx[chan->dev], chan, dp, n);
49458db832SDavid du Colombier }
50458db832SDavid du Colombier
51458db832SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)52458db832SDavid du Colombier etheropen(Chan* chan, int omode)
53458db832SDavid du Colombier {
54458db832SDavid du Colombier return netifopen(etherxx[chan->dev], chan, omode);
55458db832SDavid du Colombier }
56458db832SDavid du Colombier
57458db832SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)58458db832SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
59458db832SDavid du Colombier {
60458db832SDavid du Colombier }
61458db832SDavid du Colombier
62458db832SDavid du Colombier static void
etherclose(Chan * chan)63458db832SDavid du Colombier etherclose(Chan* chan)
64458db832SDavid du Colombier {
65458db832SDavid du Colombier netifclose(etherxx[chan->dev], chan);
66458db832SDavid du Colombier }
67458db832SDavid du Colombier
68458db832SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)69458db832SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
70458db832SDavid du Colombier {
71458db832SDavid du Colombier Ether *ether;
72458db832SDavid du Colombier ulong offset = off;
73458db832SDavid du Colombier
74458db832SDavid du Colombier ether = etherxx[chan->dev];
75458db832SDavid du Colombier if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
76458db832SDavid du Colombier /*
77458db832SDavid du Colombier * With some controllers it is necessary to reach
78458db832SDavid du Colombier * into the chip to extract statistics.
79458db832SDavid du Colombier */
80458db832SDavid du Colombier if(NETTYPE(chan->qid.path) == Nifstatqid)
81458db832SDavid du Colombier return ether->ifstat(ether, buf, n, offset);
82458db832SDavid du Colombier else if(NETTYPE(chan->qid.path) == Nstatqid)
83458db832SDavid du Colombier ether->ifstat(ether, buf, 0, offset);
84458db832SDavid du Colombier }
85458db832SDavid du Colombier
86458db832SDavid du Colombier return netifread(ether, chan, buf, n, offset);
87458db832SDavid du Colombier }
88458db832SDavid du Colombier
89458db832SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)90458db832SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
91458db832SDavid du Colombier {
92458db832SDavid du Colombier return netifbread(etherxx[chan->dev], chan, n, offset);
93458db832SDavid du Colombier }
94458db832SDavid du Colombier
95458db832SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)96458db832SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
97458db832SDavid du Colombier {
98458db832SDavid du Colombier return netifwstat(etherxx[chan->dev], chan, dp, n);
99458db832SDavid du Colombier }
100458db832SDavid du Colombier
101458db832SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)102458db832SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
103458db832SDavid du Colombier {
104458db832SDavid du Colombier int i, n;
105458db832SDavid du Colombier Block *bp;
106458db832SDavid du Colombier
107458db832SDavid du Colombier if(qwindow(f->in) <= 0)
108458db832SDavid du Colombier return;
109458db832SDavid du Colombier if(len > 58)
110458db832SDavid du Colombier n = 58;
111458db832SDavid du Colombier else
112458db832SDavid du Colombier n = len;
113458db832SDavid du Colombier bp = iallocb(64);
114458db832SDavid du Colombier if(bp == nil)
115458db832SDavid du Colombier return;
116458db832SDavid du Colombier memmove(bp->wp, pkt->d, n);
117458db832SDavid du Colombier i = TK2MS(MACHP(0)->ticks);
118458db832SDavid du Colombier bp->wp[58] = len>>8;
119458db832SDavid du Colombier bp->wp[59] = len;
120458db832SDavid du Colombier bp->wp[60] = i>>24;
121458db832SDavid du Colombier bp->wp[61] = i>>16;
122458db832SDavid du Colombier bp->wp[62] = i>>8;
123458db832SDavid du Colombier bp->wp[63] = i;
124458db832SDavid du Colombier bp->wp += 64;
125458db832SDavid du Colombier qpass(f->in, bp);
126458db832SDavid du Colombier }
127458db832SDavid du Colombier
128458db832SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)129458db832SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
130458db832SDavid du Colombier {
131458db832SDavid du Colombier Etherpkt *pkt;
132458db832SDavid du Colombier ushort type;
133458db832SDavid du Colombier int len, multi, tome, fromme;
134458db832SDavid du Colombier Netfile **ep, *f, **fp, *fx;
135458db832SDavid du Colombier Block *xbp;
136458db832SDavid du Colombier
137458db832SDavid du Colombier ether->inpackets++;
138458db832SDavid du Colombier
139458db832SDavid du Colombier pkt = (Etherpkt*)bp->rp;
140458db832SDavid du Colombier len = BLEN(bp);
141458db832SDavid du Colombier type = (pkt->type[0]<<8)|pkt->type[1];
142458db832SDavid du Colombier fx = 0;
143458db832SDavid du Colombier ep = ðer->f[Ntypes];
144458db832SDavid du Colombier
145458db832SDavid du Colombier multi = pkt->d[0] & 1;
146*d95be1c0SDavid du Colombier /* check for valid multicast addresses */
147458db832SDavid du Colombier if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
148458db832SDavid du Colombier if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
149458db832SDavid du Colombier if(fromwire){
150458db832SDavid du Colombier freeb(bp);
151458db832SDavid du Colombier bp = 0;
152458db832SDavid du Colombier }
153458db832SDavid du Colombier return bp;
154458db832SDavid du Colombier }
155458db832SDavid du Colombier }
156458db832SDavid du Colombier
157458db832SDavid du Colombier /* is it for me? */
158458db832SDavid du Colombier tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
159458db832SDavid du Colombier fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
160458db832SDavid du Colombier
161458db832SDavid du Colombier /*
162458db832SDavid du Colombier * Multiplex the packet to all the connections which want it.
163458db832SDavid du Colombier * If the packet is not to be used subsequently (fromwire != 0),
164458db832SDavid du Colombier * attempt to simply pass it into one of the connections, thereby
165458db832SDavid du Colombier * saving a copy of the data (usual case hopefully).
166458db832SDavid du Colombier */
167458db832SDavid du Colombier for(fp = ether->f; fp < ep; fp++){
168458db832SDavid du Colombier if(f = *fp)
169458db832SDavid du Colombier if(f->type == type || f->type < 0)
170458db832SDavid du Colombier if(tome || multi || f->prom){
171458db832SDavid du Colombier /* Don't want to hear bridged packets */
172458db832SDavid du Colombier if(f->bridge && !fromwire && !fromme)
173458db832SDavid du Colombier continue;
174458db832SDavid du Colombier if(!f->headersonly){
175458db832SDavid du Colombier if(fromwire && fx == 0)
176458db832SDavid du Colombier fx = f;
177458db832SDavid du Colombier else if(xbp = iallocb(len)){
178458db832SDavid du Colombier memmove(xbp->wp, pkt, len);
179458db832SDavid du Colombier xbp->wp += len;
180458db832SDavid du Colombier qpass(f->in, xbp);
181458db832SDavid du Colombier }
182458db832SDavid du Colombier else
183458db832SDavid du Colombier ether->soverflows++;
184458db832SDavid du Colombier }
185458db832SDavid du Colombier else
186458db832SDavid du Colombier etherrtrace(f, pkt, len);
187458db832SDavid du Colombier }
188458db832SDavid du Colombier }
189458db832SDavid du Colombier
190458db832SDavid du Colombier if(fx){
191458db832SDavid du Colombier if(qpass(fx->in, bp) < 0)
192458db832SDavid du Colombier ether->soverflows++;
193458db832SDavid du Colombier return 0;
194458db832SDavid du Colombier }
195458db832SDavid du Colombier if(fromwire){
196458db832SDavid du Colombier freeb(bp);
197458db832SDavid du Colombier return 0;
198458db832SDavid du Colombier }
199458db832SDavid du Colombier
200458db832SDavid du Colombier return bp;
201458db832SDavid du Colombier }
202458db832SDavid du Colombier
203458db832SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)204458db832SDavid du Colombier etheroq(Ether* ether, Block* bp)
205458db832SDavid du Colombier {
206458db832SDavid du Colombier int len, loopback, s;
207458db832SDavid du Colombier Etherpkt *pkt;
208458db832SDavid du Colombier
209458db832SDavid du Colombier ether->outpackets++;
210458db832SDavid du Colombier /*
211458db832SDavid du Colombier * Check if the packet has to be placed back onto the input queue,
212458db832SDavid du Colombier * i.e. if it's a loopback or broadcast packet or the interface is
213458db832SDavid du Colombier * in promiscuous mode.
214458db832SDavid du Colombier * If it's a loopback packet indicate to etheriq that the data isn't
215458db832SDavid du Colombier * needed and return, etheriq will pass-on or free the block.
216458db832SDavid du Colombier * To enable bridging to work, only packets that were originated
217458db832SDavid du Colombier * by this interface are fed back.
218458db832SDavid du Colombier */
219458db832SDavid du Colombier pkt = (Etherpkt*)bp->rp;
220458db832SDavid du Colombier len = BLEN(bp);
221458db832SDavid du Colombier loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
222458db832SDavid du Colombier if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
223458db832SDavid du Colombier s = splhi();
224458db832SDavid du Colombier etheriq(ether, bp, 0);
225458db832SDavid du Colombier splx(s);
226458db832SDavid du Colombier }
227458db832SDavid du Colombier
228458db832SDavid du Colombier if(!loopback){
229458db832SDavid du Colombier qbwrite(ether->oq, bp);
230458db832SDavid du Colombier ether->transmit(ether);
231458db832SDavid du Colombier } else
232458db832SDavid du Colombier freeb(bp);
233458db832SDavid du Colombier
234458db832SDavid du Colombier return len;
235458db832SDavid du Colombier }
236458db832SDavid du Colombier
237458db832SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)238458db832SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
239458db832SDavid du Colombier {
240458db832SDavid du Colombier Ether *ether;
241458db832SDavid du Colombier Block *bp;
242458db832SDavid du Colombier int nn;
243458db832SDavid du Colombier
244458db832SDavid du Colombier ether = etherxx[chan->dev];
245458db832SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid) {
246458db832SDavid du Colombier nn = netifwrite(ether, chan, buf, n);
247458db832SDavid du Colombier if(nn >= 0)
248458db832SDavid du Colombier return nn;
249458db832SDavid du Colombier if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
250458db832SDavid du Colombier qnoblock(ether->oq, 1);
251458db832SDavid du Colombier return n;
252458db832SDavid du Colombier }
253458db832SDavid du Colombier if(ether->ctl!=nil)
254458db832SDavid du Colombier return ether->ctl(ether,buf,n);
255458db832SDavid du Colombier
256458db832SDavid du Colombier error(Ebadctl);
257458db832SDavid du Colombier }
258458db832SDavid du Colombier
259458db832SDavid du Colombier if(n > ether->maxmtu)
260458db832SDavid du Colombier error(Etoobig);
261458db832SDavid du Colombier if(n < ether->minmtu)
262458db832SDavid du Colombier error(Etoosmall);
263458db832SDavid du Colombier
264458db832SDavid du Colombier bp = allocb(n);
265458db832SDavid du Colombier if(waserror()){
266458db832SDavid du Colombier freeb(bp);
267458db832SDavid du Colombier nexterror();
268458db832SDavid du Colombier }
269458db832SDavid du Colombier memmove(bp->rp, buf, n);
270458db832SDavid du Colombier memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
271458db832SDavid du Colombier poperror();
272458db832SDavid du Colombier bp->wp += n;
273458db832SDavid du Colombier
274458db832SDavid du Colombier return etheroq(ether, bp);
275458db832SDavid du Colombier }
276458db832SDavid du Colombier
277458db832SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)278458db832SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
279458db832SDavid du Colombier {
280458db832SDavid du Colombier Ether *ether;
281458db832SDavid du Colombier long n;
282458db832SDavid du Colombier
283458db832SDavid du Colombier n = BLEN(bp);
284458db832SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid){
285458db832SDavid du Colombier if(waserror()) {
286458db832SDavid du Colombier freeb(bp);
287458db832SDavid du Colombier nexterror();
288458db832SDavid du Colombier }
289458db832SDavid du Colombier n = etherwrite(chan, bp->rp, n, 0);
290458db832SDavid du Colombier poperror();
291458db832SDavid du Colombier freeb(bp);
292458db832SDavid du Colombier return n;
293458db832SDavid du Colombier }
294458db832SDavid du Colombier ether = etherxx[chan->dev];
295458db832SDavid du Colombier
296458db832SDavid du Colombier if(n > ether->maxmtu){
297458db832SDavid du Colombier freeb(bp);
298458db832SDavid du Colombier error(Etoobig);
299458db832SDavid du Colombier }
300458db832SDavid du Colombier if(n < ether->minmtu){
301458db832SDavid du Colombier freeb(bp);
302458db832SDavid du Colombier error(Etoosmall);
303458db832SDavid du Colombier }
304458db832SDavid du Colombier
305458db832SDavid du Colombier return etheroq(ether, bp);
306458db832SDavid du Colombier }
307458db832SDavid du Colombier
308458db832SDavid du Colombier static struct {
309458db832SDavid du Colombier char* type;
310458db832SDavid du Colombier int (*reset)(Ether*);
311458db832SDavid du Colombier } cards[MaxEther+1];
312458db832SDavid du Colombier
313458db832SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))314458db832SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
315458db832SDavid du Colombier {
316458db832SDavid du Colombier static int ncard;
317458db832SDavid du Colombier
318458db832SDavid du Colombier if(ncard == MaxEther)
319458db832SDavid du Colombier panic("too many ether cards");
320458db832SDavid du Colombier cards[ncard].type = t;
321458db832SDavid du Colombier cards[ncard].reset = r;
322458db832SDavid du Colombier ncard++;
323458db832SDavid du Colombier }
324458db832SDavid du Colombier
325458db832SDavid du Colombier int
parseether(uchar * to,char * from)326458db832SDavid du Colombier parseether(uchar *to, char *from)
327458db832SDavid du Colombier {
328458db832SDavid du Colombier char nip[4];
329458db832SDavid du Colombier char *p;
330458db832SDavid du Colombier int i;
331458db832SDavid du Colombier
332458db832SDavid du Colombier p = from;
333458db832SDavid du Colombier for(i = 0; i < 6; i++){
334458db832SDavid du Colombier if(*p == 0)
335458db832SDavid du Colombier return -1;
336458db832SDavid du Colombier nip[0] = *p++;
337458db832SDavid du Colombier if(*p == 0)
338458db832SDavid du Colombier return -1;
339458db832SDavid du Colombier nip[1] = *p++;
340458db832SDavid du Colombier nip[2] = 0;
341458db832SDavid du Colombier to[i] = strtoul(nip, 0, 16);
342458db832SDavid du Colombier if(*p == ':')
343458db832SDavid du Colombier p++;
344458db832SDavid du Colombier }
345458db832SDavid du Colombier return 0;
346458db832SDavid du Colombier }
347458db832SDavid du Colombier
348458db832SDavid du Colombier static void
etherreset(void)349458db832SDavid du Colombier etherreset(void)
350458db832SDavid du Colombier {
351458db832SDavid du Colombier Ether *ether;
352458db832SDavid du Colombier int i, n, ctlrno;
353458db832SDavid du Colombier char name[32], buf[128];
354458db832SDavid du Colombier
355458db832SDavid du Colombier for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
356458db832SDavid du Colombier if(ether == 0)
357458db832SDavid du Colombier ether = malloc(sizeof(Ether));
358458db832SDavid du Colombier memset(ether, 0, sizeof(Ether));
359458db832SDavid du Colombier ether->ctlrno = ctlrno;
360458db832SDavid du Colombier ether->tbdf = BUSUNKNOWN;
361458db832SDavid du Colombier ether->mbps = 10;
362458db832SDavid du Colombier ether->minmtu = ETHERMINTU;
363458db832SDavid du Colombier ether->maxmtu = ETHERMAXTU;
364458db832SDavid du Colombier if(isaconfig("ether", ctlrno, ether) == 0)
365458db832SDavid du Colombier continue;
366458db832SDavid du Colombier for(n = 0; cards[n].type; n++){
367458db832SDavid du Colombier if(cistrcmp(cards[n].type, ether->type))
368458db832SDavid du Colombier continue;
3694de34a7eSDavid du Colombier memmove(ether->ea, etheraddr, 6);
370458db832SDavid du Colombier for(i = 0; i < ether->nopt; i++){
371458db832SDavid du Colombier if(strncmp(ether->opt[i], "ea=", 3))
372458db832SDavid du Colombier continue;
373458db832SDavid du Colombier if(parseether(ether->ea, ðer->opt[i][3]) == -1)
374458db832SDavid du Colombier memset(ether->ea, 0, Eaddrlen);
375458db832SDavid du Colombier }
376458db832SDavid du Colombier if(cards[n].reset(ether))
377458db832SDavid du Colombier break;
378458db832SDavid du Colombier
379458db832SDavid du Colombier /*
380458db832SDavid du Colombier * IRQ2 doesn't really exist, it's used to gang the interrupt
381458db832SDavid du Colombier * controllers together. A device set to IRQ2 will appear on
382458db832SDavid du Colombier * the second interrupt controller as IRQ9.
383458db832SDavid du Colombier */
384458db832SDavid du Colombier if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI)
385458db832SDavid du Colombier ether->irq = 9;
386458db832SDavid du Colombier snprint(name, sizeof(name), "ether%d", ctlrno);
387458db832SDavid du Colombier
388458db832SDavid du Colombier /*
389458db832SDavid du Colombier * If ether->irq is <0, it is a hack to indicate no interrupt
390458db832SDavid du Colombier * used by ethersink.
391458db832SDavid du Colombier */
392458db832SDavid du Colombier if(ether->irq >= 0)
393458db832SDavid du Colombier intrenable(ether->irq, ether->interrupt, ether, name);
394458db832SDavid du Colombier i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
395458db832SDavid du Colombier ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
396458db832SDavid du Colombier if(ether->mem)
397458db832SDavid du Colombier i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
398458db832SDavid du Colombier if(ether->size)
399458db832SDavid du Colombier i += sprint(buf+i, " size 0x%luX", ether->size);
4006063170eSDavid du Colombier i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
401458db832SDavid du Colombier ether->ea[0], ether->ea[1], ether->ea[2],
402458db832SDavid du Colombier ether->ea[3], ether->ea[4], ether->ea[5]);
403458db832SDavid du Colombier sprint(buf+i, "\n");
404458db832SDavid du Colombier print(buf);
405458db832SDavid du Colombier
406458db832SDavid du Colombier if(ether->mbps >= 100){
407458db832SDavid du Colombier netifinit(ether, name, Ntypes, 256*1024);
408458db832SDavid du Colombier if(ether->oq == 0)
409458db832SDavid du Colombier ether->oq = qopen(256*1024, Qmsg, 0, 0);
410458db832SDavid du Colombier }
411458db832SDavid du Colombier else{
412458db832SDavid du Colombier netifinit(ether, name, Ntypes, 65*1024);
413458db832SDavid du Colombier if(ether->oq == 0)
414458db832SDavid du Colombier ether->oq = qopen(65*1024, Qmsg, 0, 0);
415458db832SDavid du Colombier }
416458db832SDavid du Colombier if(ether->oq == 0)
417458db832SDavid du Colombier panic("etherreset %s", name);
418458db832SDavid du Colombier ether->alen = Eaddrlen;
419458db832SDavid du Colombier memmove(ether->addr, ether->ea, Eaddrlen);
420458db832SDavid du Colombier memset(ether->bcast, 0xFF, Eaddrlen);
421458db832SDavid du Colombier
422458db832SDavid du Colombier etherxx[ctlrno] = ether;
423458db832SDavid du Colombier ether = 0;
424458db832SDavid du Colombier break;
425458db832SDavid du Colombier }
426458db832SDavid du Colombier }
427458db832SDavid du Colombier if(ether)
428458db832SDavid du Colombier free(ether);
429458db832SDavid du Colombier }
430458db832SDavid du Colombier
431458db832SDavid du Colombier #define POLY 0xedb88320
432458db832SDavid du Colombier
433458db832SDavid du Colombier /* really slow 32 bit crc for ethers */
434458db832SDavid du Colombier ulong
ethercrc(uchar * p,int len)435458db832SDavid du Colombier ethercrc(uchar *p, int len)
436458db832SDavid du Colombier {
437458db832SDavid du Colombier int i, j;
438458db832SDavid du Colombier ulong crc, b;
439458db832SDavid du Colombier
440458db832SDavid du Colombier crc = 0xffffffff;
441458db832SDavid du Colombier for(i = 0; i < len; i++){
442458db832SDavid du Colombier b = *p++;
443458db832SDavid du Colombier for(j = 0; j < 8; j++){
444458db832SDavid du Colombier crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
445458db832SDavid du Colombier b >>= 1;
446458db832SDavid du Colombier }
447458db832SDavid du Colombier }
448458db832SDavid du Colombier return crc;
449458db832SDavid du Colombier }
450458db832SDavid du Colombier
451458db832SDavid du Colombier Dev etherdevtab = {
452458db832SDavid du Colombier 'l',
453458db832SDavid du Colombier "ether",
454458db832SDavid du Colombier
455458db832SDavid du Colombier etherreset,
456458db832SDavid du Colombier devinit,
457458db832SDavid du Colombier devshutdown,
458458db832SDavid du Colombier etherattach,
459458db832SDavid du Colombier etherwalk,
460458db832SDavid du Colombier etherstat,
461458db832SDavid du Colombier etheropen,
462458db832SDavid du Colombier ethercreate,
463458db832SDavid du Colombier etherclose,
464458db832SDavid du Colombier etherread,
465458db832SDavid du Colombier etherbread,
466458db832SDavid du Colombier etherwrite,
467458db832SDavid du Colombier etherbwrite,
468458db832SDavid du Colombier devremove,
469458db832SDavid du Colombier etherwstat,
470458db832SDavid du Colombier };
471