1*a81c3ea0SDavid du Colombier #include "u.h"
2*a81c3ea0SDavid du Colombier #include "../port/lib.h"
3*a81c3ea0SDavid du Colombier #include "mem.h"
4*a81c3ea0SDavid du Colombier #include "dat.h"
5*a81c3ea0SDavid du Colombier #include "fns.h"
6*a81c3ea0SDavid du Colombier #include "io.h"
7*a81c3ea0SDavid du Colombier #include "../port/error.h"
8*a81c3ea0SDavid du Colombier
9*a81c3ea0SDavid du Colombier #include "../port/netif.h"
10*a81c3ea0SDavid du Colombier #include "etherif.h"
11*a81c3ea0SDavid du Colombier
12*a81c3ea0SDavid du Colombier extern int archether(unsigned ctlno, Ether *ether);
13*a81c3ea0SDavid du Colombier
14*a81c3ea0SDavid du Colombier static Ether *etherxx[MaxEther];
15*a81c3ea0SDavid du Colombier
16*a81c3ea0SDavid du Colombier Chan*
etherattach(char * spec)17*a81c3ea0SDavid du Colombier etherattach(char* spec)
18*a81c3ea0SDavid du Colombier {
19*a81c3ea0SDavid du Colombier int ctlrno;
20*a81c3ea0SDavid du Colombier char *p;
21*a81c3ea0SDavid du Colombier Chan *chan;
22*a81c3ea0SDavid du Colombier
23*a81c3ea0SDavid du Colombier ctlrno = 0;
24*a81c3ea0SDavid du Colombier if(spec && *spec){
25*a81c3ea0SDavid du Colombier ctlrno = strtoul(spec, &p, 0);
26*a81c3ea0SDavid du Colombier if((ctlrno == 0 && p == spec) || *p != 0)
27*a81c3ea0SDavid du Colombier error(Ebadarg);
28*a81c3ea0SDavid du Colombier if(ctlrno < 0 || ctlrno >= MaxEther)
29*a81c3ea0SDavid du Colombier error(Ebadarg);
30*a81c3ea0SDavid du Colombier }
31*a81c3ea0SDavid du Colombier if(etherxx[ctlrno] == 0)
32*a81c3ea0SDavid du Colombier error(Enodev);
33*a81c3ea0SDavid du Colombier
34*a81c3ea0SDavid du Colombier chan = devattach('l', spec);
35*a81c3ea0SDavid du Colombier if(waserror()){
36*a81c3ea0SDavid du Colombier chanfree(chan);
37*a81c3ea0SDavid du Colombier nexterror();
38*a81c3ea0SDavid du Colombier }
39*a81c3ea0SDavid du Colombier chan->dev = ctlrno;
40*a81c3ea0SDavid du Colombier if(etherxx[ctlrno]->attach)
41*a81c3ea0SDavid du Colombier etherxx[ctlrno]->attach(etherxx[ctlrno]);
42*a81c3ea0SDavid du Colombier poperror();
43*a81c3ea0SDavid du Colombier return chan;
44*a81c3ea0SDavid du Colombier }
45*a81c3ea0SDavid du Colombier
46*a81c3ea0SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)47*a81c3ea0SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
48*a81c3ea0SDavid du Colombier {
49*a81c3ea0SDavid du Colombier return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
50*a81c3ea0SDavid du Colombier }
51*a81c3ea0SDavid du Colombier
52*a81c3ea0SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)53*a81c3ea0SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
54*a81c3ea0SDavid du Colombier {
55*a81c3ea0SDavid du Colombier return netifstat(etherxx[chan->dev], chan, dp, n);
56*a81c3ea0SDavid du Colombier }
57*a81c3ea0SDavid du Colombier
58*a81c3ea0SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)59*a81c3ea0SDavid du Colombier etheropen(Chan* chan, int omode)
60*a81c3ea0SDavid du Colombier {
61*a81c3ea0SDavid du Colombier return netifopen(etherxx[chan->dev], chan, omode);
62*a81c3ea0SDavid du Colombier }
63*a81c3ea0SDavid du Colombier
64*a81c3ea0SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)65*a81c3ea0SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
66*a81c3ea0SDavid du Colombier {
67*a81c3ea0SDavid du Colombier }
68*a81c3ea0SDavid du Colombier
69*a81c3ea0SDavid du Colombier static void
etherclose(Chan * chan)70*a81c3ea0SDavid du Colombier etherclose(Chan* chan)
71*a81c3ea0SDavid du Colombier {
72*a81c3ea0SDavid du Colombier netifclose(etherxx[chan->dev], chan);
73*a81c3ea0SDavid du Colombier }
74*a81c3ea0SDavid du Colombier
75*a81c3ea0SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)76*a81c3ea0SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
77*a81c3ea0SDavid du Colombier {
78*a81c3ea0SDavid du Colombier Ether *ether;
79*a81c3ea0SDavid du Colombier ulong offset = off;
80*a81c3ea0SDavid du Colombier
81*a81c3ea0SDavid du Colombier ether = etherxx[chan->dev];
82*a81c3ea0SDavid du Colombier if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
83*a81c3ea0SDavid du Colombier /*
84*a81c3ea0SDavid du Colombier * With some controllers it is necessary to reach
85*a81c3ea0SDavid du Colombier * into the chip to extract statistics.
86*a81c3ea0SDavid du Colombier */
87*a81c3ea0SDavid du Colombier if(NETTYPE(chan->qid.path) == Nifstatqid)
88*a81c3ea0SDavid du Colombier return ether->ifstat(ether, buf, n, offset);
89*a81c3ea0SDavid du Colombier else if(NETTYPE(chan->qid.path) == Nstatqid)
90*a81c3ea0SDavid du Colombier ether->ifstat(ether, buf, 0, offset);
91*a81c3ea0SDavid du Colombier }
92*a81c3ea0SDavid du Colombier
93*a81c3ea0SDavid du Colombier return netifread(ether, chan, buf, n, offset);
94*a81c3ea0SDavid du Colombier }
95*a81c3ea0SDavid du Colombier
96*a81c3ea0SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)97*a81c3ea0SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
98*a81c3ea0SDavid du Colombier {
99*a81c3ea0SDavid du Colombier return netifbread(etherxx[chan->dev], chan, n, offset);
100*a81c3ea0SDavid du Colombier }
101*a81c3ea0SDavid du Colombier
102*a81c3ea0SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)103*a81c3ea0SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
104*a81c3ea0SDavid du Colombier {
105*a81c3ea0SDavid du Colombier return netifwstat(etherxx[chan->dev], chan, dp, n);
106*a81c3ea0SDavid du Colombier }
107*a81c3ea0SDavid du Colombier
108*a81c3ea0SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)109*a81c3ea0SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
110*a81c3ea0SDavid du Colombier {
111*a81c3ea0SDavid du Colombier int i, n;
112*a81c3ea0SDavid du Colombier Block *bp;
113*a81c3ea0SDavid du Colombier
114*a81c3ea0SDavid du Colombier if(qwindow(f->in) <= 0)
115*a81c3ea0SDavid du Colombier return;
116*a81c3ea0SDavid du Colombier if(len > 58)
117*a81c3ea0SDavid du Colombier n = 58;
118*a81c3ea0SDavid du Colombier else
119*a81c3ea0SDavid du Colombier n = len;
120*a81c3ea0SDavid du Colombier bp = iallocb(64);
121*a81c3ea0SDavid du Colombier if(bp == nil)
122*a81c3ea0SDavid du Colombier return;
123*a81c3ea0SDavid du Colombier memmove(bp->wp, pkt->d, n);
124*a81c3ea0SDavid du Colombier i = TK2MS(MACHP(0)->ticks);
125*a81c3ea0SDavid du Colombier bp->wp[58] = len>>8;
126*a81c3ea0SDavid du Colombier bp->wp[59] = len;
127*a81c3ea0SDavid du Colombier bp->wp[60] = i>>24;
128*a81c3ea0SDavid du Colombier bp->wp[61] = i>>16;
129*a81c3ea0SDavid du Colombier bp->wp[62] = i>>8;
130*a81c3ea0SDavid du Colombier bp->wp[63] = i;
131*a81c3ea0SDavid du Colombier bp->wp += 64;
132*a81c3ea0SDavid du Colombier qpass(f->in, bp);
133*a81c3ea0SDavid du Colombier }
134*a81c3ea0SDavid du Colombier
135*a81c3ea0SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)136*a81c3ea0SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
137*a81c3ea0SDavid du Colombier {
138*a81c3ea0SDavid du Colombier Etherpkt *pkt;
139*a81c3ea0SDavid du Colombier ushort type;
140*a81c3ea0SDavid du Colombier int len, multi, tome, fromme;
141*a81c3ea0SDavid du Colombier Netfile **ep, *f, **fp, *fx;
142*a81c3ea0SDavid du Colombier Block *xbp;
143*a81c3ea0SDavid du Colombier
144*a81c3ea0SDavid du Colombier ether->inpackets++;
145*a81c3ea0SDavid du Colombier
146*a81c3ea0SDavid du Colombier pkt = (Etherpkt*)bp->rp;
147*a81c3ea0SDavid du Colombier len = BLEN(bp);
148*a81c3ea0SDavid du Colombier type = (pkt->type[0]<<8)|pkt->type[1];
149*a81c3ea0SDavid du Colombier fx = 0;
150*a81c3ea0SDavid du Colombier ep = ðer->f[Ntypes];
151*a81c3ea0SDavid du Colombier
152*a81c3ea0SDavid du Colombier multi = pkt->d[0] & 1;
153*a81c3ea0SDavid du Colombier /* check for valid multicast addresses */
154*a81c3ea0SDavid du Colombier if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
155*a81c3ea0SDavid du Colombier ether->prom == 0){
156*a81c3ea0SDavid du Colombier if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
157*a81c3ea0SDavid du Colombier if(fromwire){
158*a81c3ea0SDavid du Colombier freeb(bp);
159*a81c3ea0SDavid du Colombier bp = 0;
160*a81c3ea0SDavid du Colombier }
161*a81c3ea0SDavid du Colombier return bp;
162*a81c3ea0SDavid du Colombier }
163*a81c3ea0SDavid du Colombier }
164*a81c3ea0SDavid du Colombier /* is it for me? */
165*a81c3ea0SDavid du Colombier tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
166*a81c3ea0SDavid du Colombier fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
167*a81c3ea0SDavid du Colombier
168*a81c3ea0SDavid du Colombier /*
169*a81c3ea0SDavid du Colombier * Multiplex the packet to all the connections which want it.
170*a81c3ea0SDavid du Colombier * If the packet is not to be used subsequently (fromwire != 0),
171*a81c3ea0SDavid du Colombier * attempt to simply pass it into one of the connections, thereby
172*a81c3ea0SDavid du Colombier * saving a copy of the data (usual case hopefully).
173*a81c3ea0SDavid du Colombier */
174*a81c3ea0SDavid du Colombier for(fp = ether->f; fp < ep; fp++){
175*a81c3ea0SDavid du Colombier if((f = *fp) != nil && (f->type == type || f->type < 0) &&
176*a81c3ea0SDavid du Colombier (tome || multi || f->prom)){
177*a81c3ea0SDavid du Colombier /* Don't want to hear bridged packets */
178*a81c3ea0SDavid du Colombier if(f->bridge && !fromwire && !fromme)
179*a81c3ea0SDavid du Colombier continue;
180*a81c3ea0SDavid du Colombier if(!f->headersonly){
181*a81c3ea0SDavid du Colombier if(fromwire && fx == 0)
182*a81c3ea0SDavid du Colombier fx = f;
183*a81c3ea0SDavid du Colombier else if(xbp = iallocb(len)){
184*a81c3ea0SDavid du Colombier memmove(xbp->wp, pkt, len);
185*a81c3ea0SDavid du Colombier xbp->wp += len;
186*a81c3ea0SDavid du Colombier if(qpass(f->in, xbp) < 0)
187*a81c3ea0SDavid du Colombier ether->soverflows++;
188*a81c3ea0SDavid du Colombier }
189*a81c3ea0SDavid du Colombier else
190*a81c3ea0SDavid du Colombier ether->soverflows++;
191*a81c3ea0SDavid du Colombier }
192*a81c3ea0SDavid du Colombier else
193*a81c3ea0SDavid du Colombier etherrtrace(f, pkt, len);
194*a81c3ea0SDavid du Colombier }
195*a81c3ea0SDavid du Colombier }
196*a81c3ea0SDavid du Colombier
197*a81c3ea0SDavid du Colombier if(fx){
198*a81c3ea0SDavid du Colombier if(qpass(fx->in, bp) < 0)
199*a81c3ea0SDavid du Colombier ether->soverflows++;
200*a81c3ea0SDavid du Colombier return 0;
201*a81c3ea0SDavid du Colombier }
202*a81c3ea0SDavid du Colombier if(fromwire){
203*a81c3ea0SDavid du Colombier freeb(bp);
204*a81c3ea0SDavid du Colombier return 0;
205*a81c3ea0SDavid du Colombier }
206*a81c3ea0SDavid du Colombier return bp;
207*a81c3ea0SDavid du Colombier }
208*a81c3ea0SDavid du Colombier
209*a81c3ea0SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)210*a81c3ea0SDavid du Colombier etheroq(Ether* ether, Block* bp)
211*a81c3ea0SDavid du Colombier {
212*a81c3ea0SDavid du Colombier int len, loopback, s;
213*a81c3ea0SDavid du Colombier Etherpkt *pkt;
214*a81c3ea0SDavid du Colombier
215*a81c3ea0SDavid du Colombier ether->outpackets++;
216*a81c3ea0SDavid du Colombier
217*a81c3ea0SDavid du Colombier /*
218*a81c3ea0SDavid du Colombier * Check if the packet has to be placed back onto the input queue,
219*a81c3ea0SDavid du Colombier * i.e. if it's a loopback or broadcast packet or the interface is
220*a81c3ea0SDavid du Colombier * in promiscuous mode.
221*a81c3ea0SDavid du Colombier * If it's a loopback packet indicate to etheriq that the data isn't
222*a81c3ea0SDavid du Colombier * needed and return, etheriq will pass-on or free the block.
223*a81c3ea0SDavid du Colombier * To enable bridging to work, only packets that were originated
224*a81c3ea0SDavid du Colombier * by this interface are fed back.
225*a81c3ea0SDavid du Colombier */
226*a81c3ea0SDavid du Colombier pkt = (Etherpkt*)bp->rp;
227*a81c3ea0SDavid du Colombier len = BLEN(bp);
228*a81c3ea0SDavid du Colombier loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
229*a81c3ea0SDavid du Colombier if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
230*a81c3ea0SDavid du Colombier s = splhi();
231*a81c3ea0SDavid du Colombier etheriq(ether, bp, 0);
232*a81c3ea0SDavid du Colombier splx(s);
233*a81c3ea0SDavid du Colombier }
234*a81c3ea0SDavid du Colombier
235*a81c3ea0SDavid du Colombier if(!loopback){
236*a81c3ea0SDavid du Colombier qbwrite(ether->oq, bp);
237*a81c3ea0SDavid du Colombier if(ether->transmit != nil)
238*a81c3ea0SDavid du Colombier ether->transmit(ether);
239*a81c3ea0SDavid du Colombier } else
240*a81c3ea0SDavid du Colombier freeb(bp);
241*a81c3ea0SDavid du Colombier
242*a81c3ea0SDavid du Colombier return len;
243*a81c3ea0SDavid du Colombier }
244*a81c3ea0SDavid du Colombier
245*a81c3ea0SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)246*a81c3ea0SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
247*a81c3ea0SDavid du Colombier {
248*a81c3ea0SDavid du Colombier Ether *ether;
249*a81c3ea0SDavid du Colombier Block *bp;
250*a81c3ea0SDavid du Colombier int nn, onoff;
251*a81c3ea0SDavid du Colombier Cmdbuf *cb;
252*a81c3ea0SDavid du Colombier
253*a81c3ea0SDavid du Colombier ether = etherxx[chan->dev];
254*a81c3ea0SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid) {
255*a81c3ea0SDavid du Colombier nn = netifwrite(ether, chan, buf, n);
256*a81c3ea0SDavid du Colombier if(nn >= 0)
257*a81c3ea0SDavid du Colombier return nn;
258*a81c3ea0SDavid du Colombier cb = parsecmd(buf, n);
259*a81c3ea0SDavid du Colombier if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
260*a81c3ea0SDavid du Colombier if(cb->nf <= 1)
261*a81c3ea0SDavid du Colombier onoff = 1;
262*a81c3ea0SDavid du Colombier else
263*a81c3ea0SDavid du Colombier onoff = atoi(cb->f[1]);
264*a81c3ea0SDavid du Colombier qnoblock(ether->oq, onoff);
265*a81c3ea0SDavid du Colombier free(cb);
266*a81c3ea0SDavid du Colombier return n;
267*a81c3ea0SDavid du Colombier }
268*a81c3ea0SDavid du Colombier free(cb);
269*a81c3ea0SDavid du Colombier if(ether->ctl!=nil)
270*a81c3ea0SDavid du Colombier return ether->ctl(ether,buf,n);
271*a81c3ea0SDavid du Colombier
272*a81c3ea0SDavid du Colombier error(Ebadctl);
273*a81c3ea0SDavid du Colombier }
274*a81c3ea0SDavid du Colombier
275*a81c3ea0SDavid du Colombier if(n > ether->maxmtu)
276*a81c3ea0SDavid du Colombier error(Etoobig);
277*a81c3ea0SDavid du Colombier if(n < ether->minmtu)
278*a81c3ea0SDavid du Colombier error(Etoosmall);
279*a81c3ea0SDavid du Colombier
280*a81c3ea0SDavid du Colombier bp = allocb(n);
281*a81c3ea0SDavid du Colombier if(waserror()){
282*a81c3ea0SDavid du Colombier freeb(bp);
283*a81c3ea0SDavid du Colombier nexterror();
284*a81c3ea0SDavid du Colombier }
285*a81c3ea0SDavid du Colombier memmove(bp->rp, buf, n);
286*a81c3ea0SDavid du Colombier memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
287*a81c3ea0SDavid du Colombier poperror();
288*a81c3ea0SDavid du Colombier bp->wp += n;
289*a81c3ea0SDavid du Colombier
290*a81c3ea0SDavid du Colombier return etheroq(ether, bp);
291*a81c3ea0SDavid du Colombier }
292*a81c3ea0SDavid du Colombier
293*a81c3ea0SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)294*a81c3ea0SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
295*a81c3ea0SDavid du Colombier {
296*a81c3ea0SDavid du Colombier Ether *ether;
297*a81c3ea0SDavid du Colombier long n;
298*a81c3ea0SDavid du Colombier
299*a81c3ea0SDavid du Colombier n = BLEN(bp);
300*a81c3ea0SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid){
301*a81c3ea0SDavid du Colombier if(waserror()) {
302*a81c3ea0SDavid du Colombier freeb(bp);
303*a81c3ea0SDavid du Colombier nexterror();
304*a81c3ea0SDavid du Colombier }
305*a81c3ea0SDavid du Colombier n = etherwrite(chan, bp->rp, n, 0);
306*a81c3ea0SDavid du Colombier poperror();
307*a81c3ea0SDavid du Colombier freeb(bp);
308*a81c3ea0SDavid du Colombier return n;
309*a81c3ea0SDavid du Colombier }
310*a81c3ea0SDavid du Colombier ether = etherxx[chan->dev];
311*a81c3ea0SDavid du Colombier
312*a81c3ea0SDavid du Colombier if(n > ether->maxmtu){
313*a81c3ea0SDavid du Colombier freeb(bp);
314*a81c3ea0SDavid du Colombier error(Etoobig);
315*a81c3ea0SDavid du Colombier }
316*a81c3ea0SDavid du Colombier if(n < ether->minmtu){
317*a81c3ea0SDavid du Colombier freeb(bp);
318*a81c3ea0SDavid du Colombier error(Etoosmall);
319*a81c3ea0SDavid du Colombier }
320*a81c3ea0SDavid du Colombier
321*a81c3ea0SDavid du Colombier return etheroq(ether, bp);
322*a81c3ea0SDavid du Colombier }
323*a81c3ea0SDavid du Colombier
324*a81c3ea0SDavid du Colombier static struct {
325*a81c3ea0SDavid du Colombier char* type;
326*a81c3ea0SDavid du Colombier int (*reset)(Ether*);
327*a81c3ea0SDavid du Colombier } cards[MaxEther+1];
328*a81c3ea0SDavid du Colombier
329*a81c3ea0SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))330*a81c3ea0SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
331*a81c3ea0SDavid du Colombier {
332*a81c3ea0SDavid du Colombier static int ncard;
333*a81c3ea0SDavid du Colombier
334*a81c3ea0SDavid du Colombier if(ncard == MaxEther)
335*a81c3ea0SDavid du Colombier panic("too many ether cards");
336*a81c3ea0SDavid du Colombier cards[ncard].type = t;
337*a81c3ea0SDavid du Colombier cards[ncard].reset = r;
338*a81c3ea0SDavid du Colombier ncard++;
339*a81c3ea0SDavid du Colombier }
340*a81c3ea0SDavid du Colombier
341*a81c3ea0SDavid du Colombier int
parseether(uchar * to,char * from)342*a81c3ea0SDavid du Colombier parseether(uchar *to, char *from)
343*a81c3ea0SDavid du Colombier {
344*a81c3ea0SDavid du Colombier char nip[4];
345*a81c3ea0SDavid du Colombier char *p;
346*a81c3ea0SDavid du Colombier int i;
347*a81c3ea0SDavid du Colombier
348*a81c3ea0SDavid du Colombier p = from;
349*a81c3ea0SDavid du Colombier for(i = 0; i < Eaddrlen; i++){
350*a81c3ea0SDavid du Colombier if(*p == 0)
351*a81c3ea0SDavid du Colombier return -1;
352*a81c3ea0SDavid du Colombier nip[0] = *p++;
353*a81c3ea0SDavid du Colombier if(*p == 0)
354*a81c3ea0SDavid du Colombier return -1;
355*a81c3ea0SDavid du Colombier nip[1] = *p++;
356*a81c3ea0SDavid du Colombier nip[2] = 0;
357*a81c3ea0SDavid du Colombier to[i] = strtoul(nip, 0, 16);
358*a81c3ea0SDavid du Colombier if(*p == ':')
359*a81c3ea0SDavid du Colombier p++;
360*a81c3ea0SDavid du Colombier }
361*a81c3ea0SDavid du Colombier return 0;
362*a81c3ea0SDavid du Colombier }
363*a81c3ea0SDavid du Colombier
364*a81c3ea0SDavid du Colombier static void
etherreset(void)365*a81c3ea0SDavid du Colombier etherreset(void)
366*a81c3ea0SDavid du Colombier {
367*a81c3ea0SDavid du Colombier Ether *ether;
368*a81c3ea0SDavid du Colombier int i, n, ctlrno, subirq;
369*a81c3ea0SDavid du Colombier char name[KNAMELEN], buf[128];
370*a81c3ea0SDavid du Colombier
371*a81c3ea0SDavid du Colombier for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
372*a81c3ea0SDavid du Colombier if(ether == 0)
373*a81c3ea0SDavid du Colombier ether = malloc(sizeof(Ether));
374*a81c3ea0SDavid du Colombier memset(ether, 0, sizeof(Ether));
375*a81c3ea0SDavid du Colombier ether->ctlrno = ctlrno;
376*a81c3ea0SDavid du Colombier ether->mbps = 10;
377*a81c3ea0SDavid du Colombier ether->minmtu = ETHERMINTU;
378*a81c3ea0SDavid du Colombier ether->maxmtu = ETHERMAXTU;
379*a81c3ea0SDavid du Colombier
380*a81c3ea0SDavid du Colombier if(archether(ctlrno, ether) <= 0)
381*a81c3ea0SDavid du Colombier continue;
382*a81c3ea0SDavid du Colombier
383*a81c3ea0SDavid du Colombier for(n = 0; cards[n].type; n++){
384*a81c3ea0SDavid du Colombier if(cistrcmp(cards[n].type, ether->type))
385*a81c3ea0SDavid du Colombier continue;
386*a81c3ea0SDavid du Colombier for(i = 0; i < ether->nopt; i++)
387*a81c3ea0SDavid du Colombier if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
388*a81c3ea0SDavid du Colombier if(parseether(ether->ea,
389*a81c3ea0SDavid du Colombier ðer->opt[i][3]) == -1)
390*a81c3ea0SDavid du Colombier memset(ether->ea, 0, Eaddrlen);
391*a81c3ea0SDavid du Colombier } else if(cistrcmp(ether->opt[i],
392*a81c3ea0SDavid du Colombier "100BASE-TXFD") == 0)
393*a81c3ea0SDavid du Colombier ether->mbps = 100;
394*a81c3ea0SDavid du Colombier if(cards[n].reset(ether))
395*a81c3ea0SDavid du Colombier break;
396*a81c3ea0SDavid du Colombier snprint(name, sizeof(name), "ether%d", ctlrno);
397*a81c3ea0SDavid du Colombier
398*a81c3ea0SDavid du Colombier subirq = pcisubirq(ether->tbdf);
399*a81c3ea0SDavid du Colombier if(ether->interrupt != nil && ether->irq >= 0)
400*a81c3ea0SDavid du Colombier intrenable(ether->irq, ether->interrupt, ether, subirq);
401*a81c3ea0SDavid du Colombier
402*a81c3ea0SDavid du Colombier i = snprint(buf, sizeof buf,
403*a81c3ea0SDavid du Colombier "#l%d: %s: %dMbps port %#lux irq %d.%d",
404*a81c3ea0SDavid du Colombier ctlrno, ether->type, ether->mbps, ether->port,
405*a81c3ea0SDavid du Colombier ether->irq, subirq);
406*a81c3ea0SDavid du Colombier if(ether->mem)
407*a81c3ea0SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
408*a81c3ea0SDavid du Colombier " addr %#p", PADDR(ether->mem));
409*a81c3ea0SDavid du Colombier if(ether->size)
410*a81c3ea0SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
411*a81c3ea0SDavid du Colombier " size %#luX", ether->size);
412*a81c3ea0SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
413*a81c3ea0SDavid du Colombier ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
414*a81c3ea0SDavid du Colombier ether->ea[0], ether->ea[1], ether->ea[2],
415*a81c3ea0SDavid du Colombier ether->ea[3], ether->ea[4], ether->ea[5]);
416*a81c3ea0SDavid du Colombier snprint(buf+i, sizeof buf - i, "\n");
417*a81c3ea0SDavid du Colombier iprint("%s", buf); /* it may be too early for print */
418*a81c3ea0SDavid du Colombier
419*a81c3ea0SDavid du Colombier if(ether->mbps >= 1000)
420*a81c3ea0SDavid du Colombier netifinit(ether, name, Ntypes, 4*1024*1024);
421*a81c3ea0SDavid du Colombier else if(ether->mbps >= 100)
422*a81c3ea0SDavid du Colombier netifinit(ether, name, Ntypes, 1024*1024);
423*a81c3ea0SDavid du Colombier else
424*a81c3ea0SDavid du Colombier netifinit(ether, name, Ntypes, 65*1024);
425*a81c3ea0SDavid du Colombier if(ether->oq == 0)
426*a81c3ea0SDavid du Colombier ether->oq = qopen(ether->limit, Qmsg, 0, 0);
427*a81c3ea0SDavid du Colombier if(ether->oq == 0)
428*a81c3ea0SDavid du Colombier panic("etherreset %s", name);
429*a81c3ea0SDavid du Colombier ether->alen = Eaddrlen;
430*a81c3ea0SDavid du Colombier memmove(ether->addr, ether->ea, Eaddrlen);
431*a81c3ea0SDavid du Colombier memset(ether->bcast, 0xFF, Eaddrlen);
432*a81c3ea0SDavid du Colombier
433*a81c3ea0SDavid du Colombier etherxx[ctlrno] = ether;
434*a81c3ea0SDavid du Colombier ether = 0;
435*a81c3ea0SDavid du Colombier break;
436*a81c3ea0SDavid du Colombier }
437*a81c3ea0SDavid du Colombier }
438*a81c3ea0SDavid du Colombier if(ether)
439*a81c3ea0SDavid du Colombier free(ether);
440*a81c3ea0SDavid du Colombier }
441*a81c3ea0SDavid du Colombier
442*a81c3ea0SDavid du Colombier static void
ethershutdown(void)443*a81c3ea0SDavid du Colombier ethershutdown(void)
444*a81c3ea0SDavid du Colombier {
445*a81c3ea0SDavid du Colombier Ether *ether;
446*a81c3ea0SDavid du Colombier int i;
447*a81c3ea0SDavid du Colombier
448*a81c3ea0SDavid du Colombier for(i = 0; i < MaxEther; i++){
449*a81c3ea0SDavid du Colombier ether = etherxx[i];
450*a81c3ea0SDavid du Colombier if(ether == nil)
451*a81c3ea0SDavid du Colombier continue;
452*a81c3ea0SDavid du Colombier if(ether->shutdown == nil) {
453*a81c3ea0SDavid du Colombier print("#l%d: no shutdown function\n", i);
454*a81c3ea0SDavid du Colombier continue;
455*a81c3ea0SDavid du Colombier }
456*a81c3ea0SDavid du Colombier (*ether->shutdown)(ether);
457*a81c3ea0SDavid du Colombier }
458*a81c3ea0SDavid du Colombier }
459*a81c3ea0SDavid du Colombier
460*a81c3ea0SDavid du Colombier
461*a81c3ea0SDavid du Colombier #define POLY 0xedb88320
462*a81c3ea0SDavid du Colombier
463*a81c3ea0SDavid du Colombier /* really slow 32 bit crc for ethers */
464*a81c3ea0SDavid du Colombier ulong
ethercrc(uchar * p,int len)465*a81c3ea0SDavid du Colombier ethercrc(uchar *p, int len)
466*a81c3ea0SDavid du Colombier {
467*a81c3ea0SDavid du Colombier int i, j;
468*a81c3ea0SDavid du Colombier ulong crc, b;
469*a81c3ea0SDavid du Colombier
470*a81c3ea0SDavid du Colombier crc = 0xffffffff;
471*a81c3ea0SDavid du Colombier for(i = 0; i < len; i++){
472*a81c3ea0SDavid du Colombier b = *p++;
473*a81c3ea0SDavid du Colombier for(j = 0; j < 8; j++){
474*a81c3ea0SDavid du Colombier crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
475*a81c3ea0SDavid du Colombier b >>= 1;
476*a81c3ea0SDavid du Colombier }
477*a81c3ea0SDavid du Colombier }
478*a81c3ea0SDavid du Colombier return crc;
479*a81c3ea0SDavid du Colombier }
480*a81c3ea0SDavid du Colombier
481*a81c3ea0SDavid du Colombier void
dumpoq(Queue * oq)482*a81c3ea0SDavid du Colombier dumpoq(Queue *oq)
483*a81c3ea0SDavid du Colombier {
484*a81c3ea0SDavid du Colombier if (oq == nil)
485*a81c3ea0SDavid du Colombier print("no outq! ");
486*a81c3ea0SDavid du Colombier else if (qisclosed(oq))
487*a81c3ea0SDavid du Colombier print("outq closed ");
488*a81c3ea0SDavid du Colombier else if (qfull(oq))
489*a81c3ea0SDavid du Colombier print("outq full ");
490*a81c3ea0SDavid du Colombier else
491*a81c3ea0SDavid du Colombier print("outq %d ", qlen(oq));
492*a81c3ea0SDavid du Colombier }
493*a81c3ea0SDavid du Colombier
494*a81c3ea0SDavid du Colombier void
dumpnetif(Netif * netif)495*a81c3ea0SDavid du Colombier dumpnetif(Netif *netif)
496*a81c3ea0SDavid du Colombier {
497*a81c3ea0SDavid du Colombier print("netif %s ", netif->name);
498*a81c3ea0SDavid du Colombier print("limit %d mbps %d link %d ",
499*a81c3ea0SDavid du Colombier netif->limit, netif->mbps, netif->link);
500*a81c3ea0SDavid du Colombier print("inpkts %lld outpkts %lld errs %d\n",
501*a81c3ea0SDavid du Colombier netif->inpackets, netif->outpackets,
502*a81c3ea0SDavid du Colombier netif->crcs + netif->oerrs + netif->frames + netif->overflows +
503*a81c3ea0SDavid du Colombier netif->buffs + netif->soverflows);
504*a81c3ea0SDavid du Colombier }
505*a81c3ea0SDavid du Colombier
506*a81c3ea0SDavid du Colombier Dev etherdevtab = {
507*a81c3ea0SDavid du Colombier 'l',
508*a81c3ea0SDavid du Colombier "ether",
509*a81c3ea0SDavid du Colombier
510*a81c3ea0SDavid du Colombier etherreset,
511*a81c3ea0SDavid du Colombier devinit,
512*a81c3ea0SDavid du Colombier ethershutdown,
513*a81c3ea0SDavid du Colombier etherattach,
514*a81c3ea0SDavid du Colombier etherwalk,
515*a81c3ea0SDavid du Colombier etherstat,
516*a81c3ea0SDavid du Colombier etheropen,
517*a81c3ea0SDavid du Colombier ethercreate,
518*a81c3ea0SDavid du Colombier etherclose,
519*a81c3ea0SDavid du Colombier etherread,
520*a81c3ea0SDavid du Colombier etherbread,
521*a81c3ea0SDavid du Colombier etherwrite,
522*a81c3ea0SDavid du Colombier etherbwrite,
523*a81c3ea0SDavid du Colombier devremove,
524*a81c3ea0SDavid du Colombier etherwstat,
525*a81c3ea0SDavid du Colombier };
526