1154abd99SDavid du Colombier #include "u.h"
2154abd99SDavid du Colombier #include "../port/lib.h"
3154abd99SDavid du Colombier #include "mem.h"
4154abd99SDavid du Colombier #include "dat.h"
5154abd99SDavid du Colombier #include "fns.h"
6154abd99SDavid du Colombier #include "io.h"
7154abd99SDavid du Colombier #include "../port/error.h"
8154abd99SDavid du Colombier
9154abd99SDavid du Colombier #include "../port/netif.h"
10154abd99SDavid du Colombier #include "etherif.h"
11154abd99SDavid du Colombier
12c6569576SDavid du Colombier extern int archether(unsigned ctlno, Ether *ether);
13154abd99SDavid du Colombier
14154abd99SDavid du Colombier static Ether *etherxx[MaxEther];
15154abd99SDavid du Colombier
16154abd99SDavid du Colombier Chan*
etherattach(char * spec)17154abd99SDavid du Colombier etherattach(char* spec)
18154abd99SDavid du Colombier {
19154abd99SDavid du Colombier int ctlrno;
20154abd99SDavid du Colombier char *p;
21154abd99SDavid du Colombier Chan *chan;
22154abd99SDavid du Colombier
23154abd99SDavid du Colombier ctlrno = 0;
24154abd99SDavid du Colombier if(spec && *spec){
25154abd99SDavid du Colombier ctlrno = strtoul(spec, &p, 0);
26154abd99SDavid du Colombier if((ctlrno == 0 && p == spec) || *p != 0)
27154abd99SDavid du Colombier error(Ebadarg);
28154abd99SDavid du Colombier if(ctlrno < 0 || ctlrno >= MaxEther)
29154abd99SDavid du Colombier error(Ebadarg);
30154abd99SDavid du Colombier }
31154abd99SDavid du Colombier if(etherxx[ctlrno] == 0)
32154abd99SDavid du Colombier error(Enodev);
33154abd99SDavid du Colombier
34154abd99SDavid du Colombier chan = devattach('l', spec);
35154abd99SDavid du Colombier if(waserror()){
36154abd99SDavid du Colombier chanfree(chan);
37154abd99SDavid du Colombier nexterror();
38154abd99SDavid du Colombier }
390d0cdc9eSDavid du Colombier chan->dev = ctlrno;
40154abd99SDavid du Colombier if(etherxx[ctlrno]->attach)
41154abd99SDavid du Colombier etherxx[ctlrno]->attach(etherxx[ctlrno]);
42154abd99SDavid du Colombier poperror();
43154abd99SDavid du Colombier return chan;
44154abd99SDavid du Colombier }
45154abd99SDavid du Colombier
46154abd99SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)47154abd99SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
48154abd99SDavid du Colombier {
490d0cdc9eSDavid du Colombier return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
50154abd99SDavid du Colombier }
51154abd99SDavid du Colombier
52154abd99SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)53154abd99SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
54154abd99SDavid du Colombier {
550d0cdc9eSDavid du Colombier return netifstat(etherxx[chan->dev], chan, dp, n);
56154abd99SDavid du Colombier }
57154abd99SDavid du Colombier
58154abd99SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)59154abd99SDavid du Colombier etheropen(Chan* chan, int omode)
60154abd99SDavid du Colombier {
610d0cdc9eSDavid du Colombier return netifopen(etherxx[chan->dev], chan, omode);
62154abd99SDavid du Colombier }
63154abd99SDavid du Colombier
64154abd99SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)65154abd99SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
66154abd99SDavid du Colombier {
67154abd99SDavid du Colombier }
68154abd99SDavid du Colombier
69154abd99SDavid du Colombier static void
etherclose(Chan * chan)70154abd99SDavid du Colombier etherclose(Chan* chan)
71154abd99SDavid du Colombier {
720d0cdc9eSDavid du Colombier netifclose(etherxx[chan->dev], chan);
73154abd99SDavid du Colombier }
74154abd99SDavid du Colombier
75154abd99SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)76154abd99SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
77154abd99SDavid du Colombier {
78154abd99SDavid du Colombier Ether *ether;
79154abd99SDavid du Colombier ulong offset = off;
80154abd99SDavid du Colombier
810d0cdc9eSDavid du Colombier ether = etherxx[chan->dev];
82154abd99SDavid du Colombier if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
83154abd99SDavid du Colombier /*
84154abd99SDavid du Colombier * With some controllers it is necessary to reach
85154abd99SDavid du Colombier * into the chip to extract statistics.
86154abd99SDavid du Colombier */
87154abd99SDavid du Colombier if(NETTYPE(chan->qid.path) == Nifstatqid)
88154abd99SDavid du Colombier return ether->ifstat(ether, buf, n, offset);
89154abd99SDavid du Colombier else if(NETTYPE(chan->qid.path) == Nstatqid)
90154abd99SDavid du Colombier ether->ifstat(ether, buf, 0, offset);
91154abd99SDavid du Colombier }
92154abd99SDavid du Colombier
93154abd99SDavid du Colombier return netifread(ether, chan, buf, n, offset);
94154abd99SDavid du Colombier }
95154abd99SDavid du Colombier
96154abd99SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)97154abd99SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
98154abd99SDavid du Colombier {
990d0cdc9eSDavid du Colombier return netifbread(etherxx[chan->dev], chan, n, offset);
100154abd99SDavid du Colombier }
101154abd99SDavid du Colombier
102154abd99SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)103154abd99SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
104154abd99SDavid du Colombier {
1050d0cdc9eSDavid du Colombier return netifwstat(etherxx[chan->dev], chan, dp, n);
106154abd99SDavid du Colombier }
107154abd99SDavid du Colombier
108154abd99SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)109154abd99SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
110154abd99SDavid du Colombier {
111154abd99SDavid du Colombier int i, n;
112154abd99SDavid du Colombier Block *bp;
113154abd99SDavid du Colombier
1140d0cdc9eSDavid du Colombier if(qwindow(f->in) <= 0)
115154abd99SDavid du Colombier return;
116154abd99SDavid du Colombier if(len > 58)
117154abd99SDavid du Colombier n = 58;
118154abd99SDavid du Colombier else
119154abd99SDavid du Colombier n = len;
120154abd99SDavid du Colombier bp = iallocb(64);
121154abd99SDavid du Colombier if(bp == nil)
122154abd99SDavid du Colombier return;
123154abd99SDavid du Colombier memmove(bp->wp, pkt->d, n);
124154abd99SDavid du Colombier i = TK2MS(MACHP(0)->ticks);
125154abd99SDavid du Colombier bp->wp[58] = len>>8;
126154abd99SDavid du Colombier bp->wp[59] = len;
127154abd99SDavid du Colombier bp->wp[60] = i>>24;
128154abd99SDavid du Colombier bp->wp[61] = i>>16;
129154abd99SDavid du Colombier bp->wp[62] = i>>8;
130154abd99SDavid du Colombier bp->wp[63] = i;
131154abd99SDavid du Colombier bp->wp += 64;
1320d0cdc9eSDavid du Colombier qpass(f->in, bp);
133154abd99SDavid du Colombier }
134154abd99SDavid du Colombier
135154abd99SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)136154abd99SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
137154abd99SDavid du Colombier {
138154abd99SDavid du Colombier Etherpkt *pkt;
139154abd99SDavid du Colombier ushort type;
140154abd99SDavid du Colombier int len, multi, tome, fromme;
141154abd99SDavid du Colombier Netfile **ep, *f, **fp, *fx;
142154abd99SDavid du Colombier Block *xbp;
143154abd99SDavid du Colombier
144154abd99SDavid du Colombier ether->inpackets++;
145154abd99SDavid du Colombier
146154abd99SDavid du Colombier pkt = (Etherpkt*)bp->rp;
147154abd99SDavid du Colombier len = BLEN(bp);
148154abd99SDavid du Colombier type = (pkt->type[0]<<8)|pkt->type[1];
149154abd99SDavid du Colombier fx = 0;
150154abd99SDavid du Colombier ep = ðer->f[Ntypes];
151154abd99SDavid du Colombier
152154abd99SDavid du Colombier multi = pkt->d[0] & 1;
153154abd99SDavid du Colombier /* check for valid multicast addresses */
154154abd99SDavid du Colombier if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
155154abd99SDavid du Colombier if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
156154abd99SDavid du Colombier if(fromwire){
157154abd99SDavid du Colombier freeb(bp);
158154abd99SDavid du Colombier bp = 0;
159154abd99SDavid du Colombier }
160154abd99SDavid du Colombier return bp;
161154abd99SDavid du Colombier }
162154abd99SDavid du Colombier }
163154abd99SDavid du Colombier
164154abd99SDavid du Colombier /* is it for me? */
165154abd99SDavid du Colombier tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
166154abd99SDavid du Colombier fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
167154abd99SDavid du Colombier
168154abd99SDavid du Colombier /*
169154abd99SDavid du Colombier * Multiplex the packet to all the connections which want it.
170154abd99SDavid du Colombier * If the packet is not to be used subsequently (fromwire != 0),
171154abd99SDavid du Colombier * attempt to simply pass it into one of the connections, thereby
172154abd99SDavid du Colombier * saving a copy of the data (usual case hopefully).
173154abd99SDavid du Colombier */
174154abd99SDavid du Colombier for(fp = ether->f; fp < ep; fp++){
175154abd99SDavid du Colombier if(f = *fp)
176154abd99SDavid du Colombier if(f->type == type || f->type < 0)
177154abd99SDavid du Colombier if(tome || multi || f->prom){
178154abd99SDavid du Colombier /* Don't want to hear bridged packets */
179154abd99SDavid du Colombier if(f->bridge && !fromwire && !fromme)
180154abd99SDavid du Colombier continue;
181154abd99SDavid du Colombier if(!f->headersonly){
182154abd99SDavid du Colombier if(fromwire && fx == 0)
183154abd99SDavid du Colombier fx = f;
184154abd99SDavid du Colombier else if(xbp = iallocb(len)){
185154abd99SDavid du Colombier memmove(xbp->wp, pkt, len);
186154abd99SDavid du Colombier xbp->wp += len;
1870d0cdc9eSDavid du Colombier if(qpass(f->in, xbp) < 0)
188154abd99SDavid du Colombier ether->soverflows++;
189154abd99SDavid du Colombier }
190154abd99SDavid du Colombier else
191154abd99SDavid du Colombier ether->soverflows++;
192154abd99SDavid du Colombier }
193154abd99SDavid du Colombier else
194154abd99SDavid du Colombier etherrtrace(f, pkt, len);
195154abd99SDavid du Colombier }
196154abd99SDavid du Colombier }
197154abd99SDavid du Colombier
198154abd99SDavid du Colombier if(fx){
1990d0cdc9eSDavid du Colombier if(qpass(fx->in, bp) < 0)
200154abd99SDavid du Colombier ether->soverflows++;
201154abd99SDavid du Colombier return 0;
202154abd99SDavid du Colombier }
203154abd99SDavid du Colombier if(fromwire){
204154abd99SDavid du Colombier freeb(bp);
205154abd99SDavid du Colombier return 0;
206154abd99SDavid du Colombier }
207154abd99SDavid du Colombier
208154abd99SDavid du Colombier return bp;
209154abd99SDavid du Colombier }
210154abd99SDavid du Colombier
211154abd99SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)212154abd99SDavid du Colombier etheroq(Ether* ether, Block* bp)
213154abd99SDavid du Colombier {
214154abd99SDavid du Colombier int len, loopback, s;
215154abd99SDavid du Colombier Etherpkt *pkt;
216154abd99SDavid du Colombier
217154abd99SDavid du Colombier ether->outpackets++;
218154abd99SDavid du Colombier
219154abd99SDavid du Colombier /*
220154abd99SDavid du Colombier * Check if the packet has to be placed back onto the input queue,
221154abd99SDavid du Colombier * i.e. if it's a loopback or broadcast packet or the interface is
222154abd99SDavid du Colombier * in promiscuous mode.
223154abd99SDavid du Colombier * If it's a loopback packet indicate to etheriq that the data isn't
224154abd99SDavid du Colombier * needed and return, etheriq will pass-on or free the block.
225154abd99SDavid du Colombier * To enable bridging to work, only packets that were originated
226154abd99SDavid du Colombier * by this interface are fed back.
227154abd99SDavid du Colombier */
228154abd99SDavid du Colombier pkt = (Etherpkt*)bp->rp;
229154abd99SDavid du Colombier len = BLEN(bp);
230154abd99SDavid du Colombier loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
231154abd99SDavid du Colombier if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
232154abd99SDavid du Colombier s = splhi();
233154abd99SDavid du Colombier etheriq(ether, bp, 0);
234154abd99SDavid du Colombier splx(s);
235154abd99SDavid du Colombier }
236154abd99SDavid du Colombier
237154abd99SDavid du Colombier if(!loopback){
238154abd99SDavid du Colombier qbwrite(ether->oq, bp);
239154abd99SDavid du Colombier if(ether->transmit != nil)
240154abd99SDavid du Colombier ether->transmit(ether);
241154abd99SDavid du Colombier } else
242154abd99SDavid du Colombier freeb(bp);
243154abd99SDavid du Colombier
244154abd99SDavid du Colombier return len;
245154abd99SDavid du Colombier }
246154abd99SDavid du Colombier
247154abd99SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)248154abd99SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
249154abd99SDavid du Colombier {
250154abd99SDavid du Colombier Ether *ether;
251154abd99SDavid du Colombier Block *bp;
252154abd99SDavid du Colombier int nn, onoff;
253154abd99SDavid du Colombier Cmdbuf *cb;
254154abd99SDavid du Colombier
2550d0cdc9eSDavid du Colombier ether = etherxx[chan->dev];
256154abd99SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid) {
257154abd99SDavid du Colombier nn = netifwrite(ether, chan, buf, n);
258154abd99SDavid du Colombier if(nn >= 0)
259154abd99SDavid du Colombier return nn;
260154abd99SDavid du Colombier cb = parsecmd(buf, n);
261154abd99SDavid du Colombier if(strcmp(cb->f[0], "nonblocking") == 0){
262154abd99SDavid du Colombier if(cb->nf <= 1)
263154abd99SDavid du Colombier onoff = 1;
264154abd99SDavid du Colombier else
265154abd99SDavid du Colombier onoff = atoi(cb->f[1]);
266154abd99SDavid du Colombier qnoblock(ether->oq, onoff);
267154abd99SDavid du Colombier free(cb);
268154abd99SDavid du Colombier return n;
269154abd99SDavid du Colombier }
270154abd99SDavid du Colombier free(cb);
271154abd99SDavid du Colombier if(ether->ctl!=nil)
272154abd99SDavid du Colombier return ether->ctl(ether,buf,n);
273154abd99SDavid du Colombier
274154abd99SDavid du Colombier error(Ebadctl);
275154abd99SDavid du Colombier }
276154abd99SDavid du Colombier
277154abd99SDavid du Colombier if(n > ether->maxmtu)
278154abd99SDavid du Colombier error(Etoobig);
279154abd99SDavid du Colombier if(n < ether->minmtu)
280154abd99SDavid du Colombier error(Etoosmall);
281154abd99SDavid du Colombier
282154abd99SDavid du Colombier bp = allocb(n);
283154abd99SDavid du Colombier if(waserror()){
284154abd99SDavid du Colombier freeb(bp);
285154abd99SDavid du Colombier nexterror();
286154abd99SDavid du Colombier }
287154abd99SDavid du Colombier memmove(bp->rp, buf, n);
288154abd99SDavid du Colombier memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
289154abd99SDavid du Colombier poperror();
290154abd99SDavid du Colombier bp->wp += n;
291154abd99SDavid du Colombier
292154abd99SDavid du Colombier return etheroq(ether, bp);
293154abd99SDavid du Colombier }
294154abd99SDavid du Colombier
295154abd99SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)296154abd99SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
297154abd99SDavid du Colombier {
298154abd99SDavid du Colombier Ether *ether;
299154abd99SDavid du Colombier long n;
300154abd99SDavid du Colombier
301154abd99SDavid du Colombier n = BLEN(bp);
302154abd99SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid){
303154abd99SDavid du Colombier if(waserror()) {
304154abd99SDavid du Colombier freeb(bp);
305154abd99SDavid du Colombier nexterror();
306154abd99SDavid du Colombier }
307154abd99SDavid du Colombier n = etherwrite(chan, bp->rp, n, 0);
308154abd99SDavid du Colombier poperror();
309154abd99SDavid du Colombier freeb(bp);
310154abd99SDavid du Colombier return n;
311154abd99SDavid du Colombier }
3120d0cdc9eSDavid du Colombier ether = etherxx[chan->dev];
313154abd99SDavid du Colombier
314154abd99SDavid du Colombier if(n > ether->maxmtu){
315154abd99SDavid du Colombier freeb(bp);
316154abd99SDavid du Colombier error(Etoobig);
317154abd99SDavid du Colombier }
318154abd99SDavid du Colombier if(n < ether->minmtu){
319154abd99SDavid du Colombier freeb(bp);
320154abd99SDavid du Colombier error(Etoosmall);
321154abd99SDavid du Colombier }
322154abd99SDavid du Colombier
323154abd99SDavid du Colombier return etheroq(ether, bp);
324154abd99SDavid du Colombier }
325154abd99SDavid du Colombier
326154abd99SDavid du Colombier static struct {
327154abd99SDavid du Colombier char* type;
328154abd99SDavid du Colombier int (*reset)(Ether*);
329154abd99SDavid du Colombier } cards[MaxEther+1];
330154abd99SDavid du Colombier
331154abd99SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))332154abd99SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
333154abd99SDavid du Colombier {
334154abd99SDavid du Colombier static int ncard;
335154abd99SDavid du Colombier
336154abd99SDavid du Colombier if(ncard == MaxEther)
337154abd99SDavid du Colombier panic("too many ether cards");
338154abd99SDavid du Colombier cards[ncard].type = t;
339154abd99SDavid du Colombier cards[ncard].reset = r;
340154abd99SDavid du Colombier ncard++;
341154abd99SDavid du Colombier }
342154abd99SDavid du Colombier
343154abd99SDavid du Colombier int
parseether(uchar * to,char * from)344154abd99SDavid du Colombier parseether(uchar *to, char *from)
345154abd99SDavid du Colombier {
346154abd99SDavid du Colombier char nip[4];
347154abd99SDavid du Colombier char *p;
348154abd99SDavid du Colombier int i;
349154abd99SDavid du Colombier
350154abd99SDavid du Colombier p = from;
351154abd99SDavid du Colombier for(i = 0; i < Eaddrlen; i++){
352154abd99SDavid du Colombier if(*p == 0)
353154abd99SDavid du Colombier return -1;
354154abd99SDavid du Colombier nip[0] = *p++;
355154abd99SDavid du Colombier if(*p == 0)
356154abd99SDavid du Colombier return -1;
357154abd99SDavid du Colombier nip[1] = *p++;
358154abd99SDavid du Colombier nip[2] = 0;
359154abd99SDavid du Colombier to[i] = strtoul(nip, 0, 16);
360154abd99SDavid du Colombier if(*p == ':')
361154abd99SDavid du Colombier p++;
362154abd99SDavid du Colombier }
363154abd99SDavid du Colombier return 0;
364154abd99SDavid du Colombier }
365154abd99SDavid du Colombier
366154abd99SDavid du Colombier static void
etherreset(void)367154abd99SDavid du Colombier etherreset(void)
368154abd99SDavid du Colombier {
369154abd99SDavid du Colombier Ether *ether;
370154abd99SDavid du Colombier int i, n, ctlrno;
371154abd99SDavid du Colombier char name[KNAMELEN], buf[128];
372154abd99SDavid du Colombier
373154abd99SDavid du Colombier for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
374154abd99SDavid du Colombier if(ether == 0)
375154abd99SDavid du Colombier ether = malloc(sizeof(Ether));
376*7ae8f453SDavid du Colombier if(ether == 0)
377*7ae8f453SDavid du Colombier panic("etherreset: no memory");
378154abd99SDavid du Colombier memset(ether, 0, sizeof(Ether));
379154abd99SDavid du Colombier ether->ctlrno = ctlrno;
380154abd99SDavid du Colombier ether->mbps = 10;
381154abd99SDavid du Colombier ether->minmtu = ETHERMINTU;
382154abd99SDavid du Colombier ether->maxmtu = ETHERMAXTU;
383154abd99SDavid du Colombier
384154abd99SDavid du Colombier if(archether(ctlrno, ether) <= 0)
385154abd99SDavid du Colombier continue;
386154abd99SDavid du Colombier
387154abd99SDavid du Colombier for(n = 0; cards[n].type; n++){
388154abd99SDavid du Colombier if(cistrcmp(cards[n].type, ether->type))
389154abd99SDavid du Colombier continue;
390154abd99SDavid du Colombier for(i = 0; i < ether->nopt; i++){
391154abd99SDavid du Colombier if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
392154abd99SDavid du Colombier if(parseether(ether->ea, ðer->opt[i][3]) == -1)
393154abd99SDavid du Colombier memset(ether->ea, 0, Eaddrlen);
394154abd99SDavid du Colombier }else if(cistrcmp(ether->opt[i], "fullduplex") == 0 ||
395154abd99SDavid du Colombier cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
396154abd99SDavid du Colombier ether->fullduplex = 1;
397154abd99SDavid du Colombier else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
398154abd99SDavid du Colombier ether->mbps = 100;
399154abd99SDavid du Colombier }
400154abd99SDavid du Colombier if(cards[n].reset(ether))
401154abd99SDavid du Colombier break;
402154abd99SDavid du Colombier snprint(name, sizeof(name), "ether%d", ctlrno);
403154abd99SDavid du Colombier
404154abd99SDavid du Colombier if(ether->interrupt != nil)
405154abd99SDavid du Colombier intrenable(Irqlo, ether->irq, ether->interrupt,
406154abd99SDavid du Colombier ether, name);
407154abd99SDavid du Colombier
408ab6ce076SDavid du Colombier i = snprint(buf, sizeof buf,
409ab6ce076SDavid du Colombier "#l%d: %s: %dMbps port %#lux irq %d",
410154abd99SDavid du Colombier ctlrno, ether->type, ether->mbps, ether->port,
411154abd99SDavid du Colombier ether->irq);
412154abd99SDavid du Colombier if(ether->mem)
413ab6ce076SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
414ab6ce076SDavid du Colombier " addr %#lux", PADDR(ether->mem));
415154abd99SDavid du Colombier if(ether->size)
416ab6ce076SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
4179f2e9820SDavid du Colombier " size %#luX", ether->size);
418ab6ce076SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
419ab6ce076SDavid du Colombier ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
420154abd99SDavid du Colombier ether->ea[0], ether->ea[1], ether->ea[2],
421154abd99SDavid du Colombier ether->ea[3], ether->ea[4], ether->ea[5]);
422ab6ce076SDavid du Colombier snprint(buf+i, sizeof buf - i, "\n");
423154abd99SDavid du Colombier print("%s", buf);
424154abd99SDavid du Colombier
425154abd99SDavid du Colombier if(ether->mbps >= 1000)
426154abd99SDavid du Colombier netifinit(ether, name, Ntypes, 4*1024*1024);
427154abd99SDavid du Colombier else if(ether->mbps >= 100)
428154abd99SDavid du Colombier netifinit(ether, name, Ntypes, 1024*1024);
429154abd99SDavid du Colombier else
430154abd99SDavid du Colombier netifinit(ether, name, Ntypes, 65*1024);
431154abd99SDavid du Colombier if(ether->oq == 0)
432154abd99SDavid du Colombier ether->oq = qopen(ether->limit, Qmsg, 0, 0);
433154abd99SDavid du Colombier if(ether->oq == 0)
434154abd99SDavid du Colombier panic("etherreset %s", name);
435154abd99SDavid du Colombier ether->alen = Eaddrlen;
436154abd99SDavid du Colombier memmove(ether->addr, ether->ea, Eaddrlen);
437154abd99SDavid du Colombier memset(ether->bcast, 0xFF, Eaddrlen);
438154abd99SDavid du Colombier
439154abd99SDavid du Colombier etherxx[ctlrno] = ether;
440154abd99SDavid du Colombier ether = 0;
441154abd99SDavid du Colombier break;
442154abd99SDavid du Colombier }
443154abd99SDavid du Colombier }
444154abd99SDavid du Colombier if(ether)
445154abd99SDavid du Colombier free(ether);
446154abd99SDavid du Colombier }
447154abd99SDavid du Colombier
448154abd99SDavid du Colombier static void
ethershutdown(void)449154abd99SDavid du Colombier ethershutdown(void)
450154abd99SDavid du Colombier {
451154abd99SDavid du Colombier Ether *ether;
452154abd99SDavid du Colombier int i;
453154abd99SDavid du Colombier
454154abd99SDavid du Colombier for(i = 0; i < MaxEther; i++){
455154abd99SDavid du Colombier ether = etherxx[i];
456154abd99SDavid du Colombier if(ether == nil)
457154abd99SDavid du Colombier continue;
458154abd99SDavid du Colombier if(ether->shutdown == nil) {
459154abd99SDavid du Colombier print("#l%d: no shutdown function\n", i);
460154abd99SDavid du Colombier continue;
461154abd99SDavid du Colombier }
462154abd99SDavid du Colombier (*ether->shutdown)(ether);
463154abd99SDavid du Colombier }
464154abd99SDavid du Colombier }
465154abd99SDavid du Colombier
466154abd99SDavid du Colombier #define POLY 0xedb88320
467154abd99SDavid du Colombier
468154abd99SDavid du Colombier /* really slow 32 bit crc for ethers */
469154abd99SDavid du Colombier ulong
ethercrc(uchar * p,int len)470154abd99SDavid du Colombier ethercrc(uchar *p, int len)
471154abd99SDavid du Colombier {
472154abd99SDavid du Colombier int i, j;
473154abd99SDavid du Colombier ulong crc, b;
474154abd99SDavid du Colombier
475154abd99SDavid du Colombier crc = 0xffffffff;
476154abd99SDavid du Colombier for(i = 0; i < len; i++){
477154abd99SDavid du Colombier b = *p++;
478154abd99SDavid du Colombier for(j = 0; j < 8; j++){
479154abd99SDavid du Colombier crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
480154abd99SDavid du Colombier b >>= 1;
481154abd99SDavid du Colombier }
482154abd99SDavid du Colombier }
483154abd99SDavid du Colombier return crc;
484154abd99SDavid du Colombier }
485154abd99SDavid du Colombier
486154abd99SDavid du Colombier void
dumpoq(Queue * oq)487154abd99SDavid du Colombier dumpoq(Queue *oq)
488154abd99SDavid du Colombier {
489154abd99SDavid du Colombier if (oq == nil)
490154abd99SDavid du Colombier print("no outq! ");
491154abd99SDavid du Colombier else if (qisclosed(oq))
492154abd99SDavid du Colombier print("outq closed ");
493154abd99SDavid du Colombier else if (qfull(oq))
494154abd99SDavid du Colombier print("outq full ");
495154abd99SDavid du Colombier else
496154abd99SDavid du Colombier print("outq %d ", qlen(oq));
497154abd99SDavid du Colombier }
498154abd99SDavid du Colombier
499154abd99SDavid du Colombier void
dumpnetif(Netif * netif)500154abd99SDavid du Colombier dumpnetif(Netif *netif)
501154abd99SDavid du Colombier {
502154abd99SDavid du Colombier print("netif %s ", netif->name);
503154abd99SDavid du Colombier print("limit %d mbps %d link %d ",
504154abd99SDavid du Colombier netif->limit, netif->mbps, netif->link);
505154abd99SDavid du Colombier print("inpkts %lld outpkts %lld errs %d\n",
506154abd99SDavid du Colombier netif->inpackets, netif->outpackets,
507154abd99SDavid du Colombier netif->crcs + netif->oerrs + netif->frames + netif->overflows +
508154abd99SDavid du Colombier netif->buffs + netif->soverflows);
509154abd99SDavid du Colombier }
510154abd99SDavid du Colombier
511154abd99SDavid du Colombier Dev etherdevtab = {
512154abd99SDavid du Colombier 'l',
513154abd99SDavid du Colombier "ether",
514154abd99SDavid du Colombier
515154abd99SDavid du Colombier etherreset,
516154abd99SDavid du Colombier devinit,
517154abd99SDavid du Colombier ethershutdown,
518154abd99SDavid du Colombier etherattach,
519154abd99SDavid du Colombier etherwalk,
520154abd99SDavid du Colombier etherstat,
521154abd99SDavid du Colombier etheropen,
522154abd99SDavid du Colombier ethercreate,
523154abd99SDavid du Colombier etherclose,
524154abd99SDavid du Colombier etherread,
525154abd99SDavid du Colombier etherbread,
526154abd99SDavid du Colombier etherwrite,
527154abd99SDavid du Colombier etherbwrite,
528154abd99SDavid du Colombier devremove,
529154abd99SDavid du Colombier etherwstat,
530154abd99SDavid du Colombier };
531