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