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