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