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