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