1 /*
2 * Kernel proxy for usb ethernet device
3 */
4
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "ureg.h"
12 #include "../port/error.h"
13 #include "../port/netif.h"
14
15 #include "etherif.h"
16 #include "../ip/ip.h"
17
18 #define GET4(p) ((p)[3]<<24 | (p)[2]<<16 | (p)[1]<<8 | (p)[0])
19 #define PUT4(p, v) ((p)[0] = (v), (p)[1] = (v)>>8, \
20 (p)[2] = (v)>>16, (p)[3] = (v)>>24)
21 #define dprint if(debug) print
22 #define ddump if(0) dump
23
24 static int debug = 0;
25
26 enum {
27 Bind = 0,
28 Unbind,
29
30 SmscRxerror = 0x8000,
31 SmscTxfirst = 0x2000,
32 SmscTxlast = 0x1000,
33 Lan78Rxerror = 0x00400000,
34 Lan78Txfcs = 1<<22,
35 };
36
37 typedef struct Ctlr Ctlr;
38 typedef struct Udev Udev;
39
40 typedef int (Unpackfn)(Ether*, Block*);
41 typedef void (Transmitfn)(Ctlr*, Block*);
42
43 struct Ctlr {
44 Ether* edev;
45 Udev* udev;
46 Chan* inchan;
47 Chan* outchan;
48 char* buf;
49 int bufsize;
50 int maxpkt;
51 uint rxbuf;
52 uint rxpkt;
53 uint txbuf;
54 uint txpkt;
55 QLock;
56 };
57
58 struct Udev {
59 char *name;
60 Unpackfn *unpack;
61 Transmitfn *transmit;
62 };
63
64 static Cmdtab cmds[] = {
65 { Bind, "bind", 7, },
66 { Unbind, "unbind", 0, },
67 };
68
69 static Unpackfn unpackcdc, unpackasix, unpacksmsc, unpacklan78;
70 static Transmitfn transmitcdc, transmitasix, transmitsmsc, transmitlan78;
71
72 static Udev udevtab[] = {
73 { "cdc", unpackcdc, transmitcdc, },
74 { "asix", unpackasix, transmitasix, },
75 { "smsc", unpacksmsc, transmitsmsc, },
76 { "lan78xx", unpacklan78, transmitlan78, },
77 { nil },
78 };
79
80 static char nullea[Eaddrlen];
81
82 static void
dump(int c,Block * b)83 dump(int c, Block *b)
84 {
85 int s, i;
86
87 s = splhi();
88 print("%c%ld:", c, BLEN(b));
89 for(i = 0; i < 32; i++)
90 print(" %2.2ux", b->rp[i]);
91 print("\n");
92 splx(s);
93 }
94
95 static int
unpack(Ether * edev,Block * b,int m)96 unpack(Ether *edev, Block *b, int m)
97 {
98 Block *nb;
99 Ctlr *ctlr;
100
101 ctlr = edev->ctlr;
102 ddump('?', b);
103 if(m == BLEN(b)){
104 etheriq(edev, b, 1);
105 ctlr->rxpkt++;
106 return 1;
107 }
108 nb = iallocb(m);
109 if(nb != nil){
110 memmove(nb->wp, b->rp, m);
111 nb->wp += m;
112 etheriq(edev, nb, 1);
113 ctlr->rxpkt++;
114 }else
115 edev->soverflows++;
116 b->rp += m;
117 return 0;
118 }
119
120 static int
unpackcdc(Ether * edev,Block * b)121 unpackcdc(Ether *edev, Block *b)
122 {
123 int m;
124
125 m = BLEN(b);
126 if(m < 6)
127 return -1;
128 return unpack(edev, b, m);
129 }
130
131 static int
unpackasix(Ether * edev,Block * b)132 unpackasix(Ether *edev, Block *b)
133 {
134 ulong hd;
135 int m;
136 uchar *wp;
137
138 if(BLEN(b) < 4)
139 return -1;
140 hd = GET4(b->rp);
141 b->rp += 4;
142 m = hd & 0xFFFF;
143 hd >>= 16;
144 if(m != (~hd & 0xFFFF))
145 return -1;
146 m = ROUND(m, 2);
147 if(m < 6 || m > BLEN(b))
148 return -1;
149 if((wp = b->rp + m) != b->wp && b->wp - wp < 4)
150 b->wp = wp;
151 return unpack(edev, b, m);
152 }
153
154 static int
unpacksmsc(Ether * edev,Block * b)155 unpacksmsc(Ether *edev, Block *b)
156 {
157 ulong hd;
158 int m;
159
160 ddump('@', b);
161 if(BLEN(b) < 4)
162 return -1;
163 hd = GET4(b->rp);
164 b->rp += 4;
165 m = hd >> 16;
166 if(m < 6 || m > BLEN(b))
167 return -1;
168 if(BLEN(b) - m < 4)
169 b->wp = b->rp + m;
170 if(hd & SmscRxerror){
171 edev->frames++;
172 b->rp += m;
173 if(BLEN(b) == 0){
174 freeb(b);
175 return 1;
176 }
177 }else if(unpack(edev, b, m) == 1)
178 return 1;
179 if((m &= 3) != 0)
180 b->rp += 4 - m;
181 return 0;
182 }
183
184 static int
unpacklan78(Ether * edev,Block * b)185 unpacklan78(Ether *edev, Block *b)
186 {
187 ulong hd;
188 int m;
189
190 if(BLEN(b) < 10)
191 return -1;
192 hd = GET4(b->rp);
193 b->rp += 10;
194 m = hd & 0x3FFF;
195 if(m < 6 || m > BLEN(b))
196 return -1;
197 if(hd & Lan78Rxerror){
198 edev->frames++;
199 b->rp += m;
200 if(BLEN(b) == 0){
201 freeb(b);
202 return 1;
203 }
204 }else if(unpack(edev, b, m) == 1)
205 return 1;
206 if(BLEN(b) > 0)
207 b->rp = (uchar*)((((uintptr)b->rp)+3)&~3);
208 return 0;
209 }
210
211 static void
transmit(Ctlr * ctlr,Block * b)212 transmit(Ctlr *ctlr, Block *b)
213 {
214 Chan *c;
215
216 ddump('!', b);
217 c = ctlr->outchan;
218 devtab[c->type]->bwrite(c, b, 0);
219 }
220
221 static void
transmitcdc(Ctlr * ctlr,Block * b)222 transmitcdc(Ctlr *ctlr, Block *b)
223 {
224 transmit(ctlr, b);
225 }
226
227 static void
transmitasix(Ctlr * ctlr,Block * b)228 transmitasix(Ctlr *ctlr, Block *b)
229 {
230 int n;
231
232 n = BLEN(b) & 0xFFFF;
233 n |= ~n << 16;
234 b = padblock(b, 4);
235 PUT4(b->rp, n);
236 if(BLEN(b) % ctlr->maxpkt == 0){
237 b = padblock(b, -4);
238 PUT4(b->wp, 0xFFFF0000);
239 b->wp += 4;
240 }
241 transmit(ctlr, b);
242 }
243
244 static void
transmitsmsc(Ctlr * ctlr,Block * b)245 transmitsmsc(Ctlr *ctlr, Block *b)
246 {
247 int n;
248
249 n = BLEN(b) & 0x7FF;
250 b = padblock(b, 8);
251 PUT4(b->rp, n | SmscTxfirst | SmscTxlast);
252 PUT4(b->rp+4, n);
253 transmit(ctlr, b);
254 }
255
256 static void
transmitlan78(Ctlr * ctlr,Block * b)257 transmitlan78(Ctlr *ctlr, Block *b)
258 {
259 int n;
260
261 n = BLEN(b) & 0xFFFFF;
262 b = padblock(b, 8);
263 PUT4(b->rp, n | Lan78Txfcs);
264 PUT4(b->rp+4, n);
265 transmit(ctlr, b);
266 }
267
268 static void
etherusbproc(void * a)269 etherusbproc(void *a)
270 {
271 Ether *edev;
272 Ctlr *ctlr;
273 Chan *c;
274 Block *b;
275
276 edev = a;
277 ctlr = edev->ctlr;
278 c = ctlr->inchan;
279 b = nil;
280 if(waserror()){
281 print("etherusbproc: error exit %s\n", up->errstr);
282 pexit(up->errstr, 1);
283 return;
284 }
285 for(;;){
286 if(b == nil){
287 b = devtab[c->type]->bread(c, ctlr->bufsize, 0);
288 ctlr->rxbuf++;
289 }
290 switch(ctlr->udev->unpack(edev, b)){
291 case -1:
292 edev->buffs++;
293 freeb(b);
294 /* fall through */
295 case 1:
296 b = nil;
297 break;
298 }
299 }
300 }
301
302 /*
303 * bind type indev outdev mac bufsize maxpkt
304 */
305 static void
bind(Ctlr * ctlr,Udev * udev,Cmdbuf * cb)306 bind(Ctlr *ctlr, Udev *udev, Cmdbuf *cb)
307 {
308 Chan *inchan, *outchan;
309 char *buf;
310 uint bufsize, maxpkt;
311 uchar ea[Eaddrlen];
312
313 qlock(ctlr);
314 inchan = outchan = nil;
315 buf = nil;
316 if(waserror()){
317 free(buf);
318 if(inchan)
319 cclose(inchan);
320 if(outchan)
321 cclose(outchan);
322 qunlock(ctlr);
323 nexterror();
324 }
325 if(ctlr->buf != nil)
326 cmderror(cb, "already bound to a device");
327 maxpkt = strtol(cb->f[6], 0, 0);
328 if(maxpkt < 8 || maxpkt > 512)
329 cmderror(cb, "bad maxpkt");
330 bufsize = strtol(cb->f[5], 0, 0);
331 if(bufsize < maxpkt || bufsize > 32*1024)
332 cmderror(cb, "bad bufsize");
333 buf = smalloc(bufsize);
334 inchan = namec(cb->f[2], Aopen, OREAD, 0);
335 outchan = namec(cb->f[3], Aopen, OWRITE, 0);
336 assert(inchan != nil && outchan != nil);
337 if(parsemac(ea, cb->f[4], Eaddrlen) != Eaddrlen)
338 cmderror(cb, "bad etheraddr");
339 if(memcmp(ctlr->edev->ea, nullea, Eaddrlen) == 0)
340 memmove(ctlr->edev->ea, ea, Eaddrlen);
341 else if(memcmp(ctlr->edev->ea, ea, Eaddrlen) != 0)
342 cmderror(cb, "wrong ether address");
343 ctlr->buf = buf;
344 ctlr->inchan = inchan;
345 ctlr->outchan = outchan;
346 ctlr->bufsize = bufsize;
347 ctlr->maxpkt = maxpkt;
348 ctlr->udev = udev;
349 kproc("etherusb", etherusbproc, ctlr->edev);
350 memmove(ctlr->edev->addr, ea, Eaddrlen);
351 print("\netherusb %s: %E\n", udev->name, ctlr->edev->addr);
352 poperror();
353 qunlock(ctlr);
354 }
355
356 static void
unbind(Ctlr * ctlr)357 unbind(Ctlr *ctlr)
358 {
359 qlock(ctlr);
360 if(ctlr->buf != nil){
361 free(ctlr->buf);
362 ctlr->buf = nil;
363 if(ctlr->inchan)
364 cclose(ctlr->inchan);
365 if(ctlr->outchan)
366 cclose(ctlr->outchan);
367 ctlr->inchan = ctlr->outchan = nil;
368 }
369 qunlock(ctlr);
370 }
371
372 static long
etherusbifstat(Ether * edev,void * a,long n,ulong offset)373 etherusbifstat(Ether* edev, void* a, long n, ulong offset)
374 {
375 Ctlr *ctlr;
376 char *p;
377 int l;
378
379 ctlr = edev->ctlr;
380 p = malloc(READSTR);
381 l = 0;
382
383 l += snprint(p+l, READSTR-l, "rxbuf: %ud\n", ctlr->rxbuf);
384 l += snprint(p+l, READSTR-l, "rxpkt: %ud\n", ctlr->rxpkt);
385 l += snprint(p+l, READSTR-l, "txbuf: %ud\n", ctlr->txbuf);
386 l += snprint(p+l, READSTR-l, "txpkt: %ud\n", ctlr->txpkt);
387 USED(l);
388
389 n = readstr(offset, a, n, p);
390 free(p);
391 return n;
392 }
393
394 static void
etherusbtransmit(Ether * edev)395 etherusbtransmit(Ether *edev)
396 {
397 Ctlr *ctlr;
398 Block *b;
399
400 ctlr = edev->ctlr;
401 while((b = qget(edev->oq)) != nil){
402 ctlr->txpkt++;
403 if(ctlr->buf == nil)
404 freeb(b);
405 else{
406 ctlr->udev->transmit(ctlr, b);
407 ctlr->txbuf++;
408 }
409 }
410 }
411
412 static long
etherusbctl(Ether * edev,void * buf,long n)413 etherusbctl(Ether* edev, void* buf, long n)
414 {
415 Ctlr *ctlr;
416 Cmdbuf *cb;
417 Cmdtab *ct;
418 Udev *udev;
419
420 if((ctlr = edev->ctlr) == nil)
421 error(Enonexist);
422
423 cb = parsecmd(buf, n);
424 if(waserror()){
425 free(cb);
426 nexterror();
427 }
428 ct = lookupcmd(cb, cmds, nelem(cmds));
429 switch(ct->index){
430 case Bind:
431 for(udev = udevtab; udev->name; udev++)
432 if(strcmp(cb->f[1], udev->name) == 0)
433 break;
434 if(udev->name == nil)
435 cmderror(cb, "unknown etherusb type");
436 bind(ctlr, udev, cb);
437 break;
438 case Unbind:
439 unbind(ctlr);
440 break;
441 default:
442 cmderror(cb, "unknown etherusb control message");
443 }
444 poperror();
445 free(cb);
446 return n;
447 }
448
449 static void
etherusbmulticast(void *,uchar *,int)450 etherusbmulticast(void*, uchar*, int)
451 {
452 /* nothing to do, we allow all multicast packets in */
453 }
454
455 static void
etherusbshutdown(Ether *)456 etherusbshutdown(Ether*)
457 {
458 }
459
460 static void
etherusbattach(Ether * edev)461 etherusbattach(Ether* edev)
462 {
463 Ctlr *ctlr;
464
465 ctlr = edev->ctlr;
466 if(ctlr->edev == 0){
467 /*
468 * Don't let boot process access etherusb until
469 * usbether driver has assigned an address.
470 */
471 if(up->pid == 1 && strcmp(up->text, "boot") == 0)
472 while(memcmp(edev->ea, nullea, Eaddrlen) == 0)
473 tsleep(&up->sleep, return0, 0, 100);
474 ctlr->edev = edev;
475 }
476 }
477
478 static int
etherusbpnp(Ether * edev)479 etherusbpnp(Ether* edev)
480 {
481 Ctlr *ctlr;
482
483 ctlr = malloc(sizeof(Ctlr));
484 edev->ctlr = ctlr;
485 edev->irq = -1;
486 edev->mbps = 100; /* TODO: get this from usbether */
487
488 /*
489 * Linkage to the generic ethernet driver.
490 */
491 edev->attach = etherusbattach;
492 edev->transmit = etherusbtransmit;
493 edev->interrupt = nil;
494 edev->ifstat = etherusbifstat;
495 edev->ctl = etherusbctl;
496
497 edev->arg = edev;
498 /* TODO: promiscuous, multicast (for ipv6), shutdown (for reboot) */
499 // edev->promiscuous = etherusbpromiscuous;
500 edev->shutdown = etherusbshutdown;
501 edev->multicast = etherusbmulticast;
502
503 return 0;
504 }
505
506 void
etherusblink(void)507 etherusblink(void)
508 {
509 addethercard("usb", etherusbpnp);
510 }
511