nusb/ether: add RNDIS support (tested on Nexus 5)
This commit is contained in:
parent
0f98415f99
commit
99c0abc76d
5 changed files with 191 additions and 8 deletions
|
@ -162,14 +162,15 @@ Without specifying the
|
||||||
option, the device is assumed to be a CDC compliant ethernet
|
option, the device is assumed to be a CDC compliant ethernet
|
||||||
communication device. Other devices might require setting an
|
communication device. Other devices might require setting an
|
||||||
explicit
|
explicit
|
||||||
.IR ethertype
|
.IR ethertype ,
|
||||||
such as
|
such as
|
||||||
|
.BR rndis ,
|
||||||
.BR smsc ,
|
.BR smsc ,
|
||||||
.B a88772
|
.BR a88772
|
||||||
or
|
or
|
||||||
.B a88178
|
.BR a88178
|
||||||
see
|
(see
|
||||||
.IR nusbrc (8).
|
.IR nusbrc (8)).
|
||||||
On devices that support it, the mac address can be set using
|
On devices that support it, the mac address can be set using
|
||||||
the
|
the
|
||||||
.B -a
|
.B -a
|
||||||
|
|
|
@ -20,6 +20,8 @@ if(! nusb/usbd)
|
||||||
nusb/ether -t aue $etherargs $1 &
|
nusb/ether -t aue $etherargs $1 &
|
||||||
case 0bda8150
|
case 0bda8150
|
||||||
nusb/ether -t url $etherargs $1 &
|
nusb/ether -t url $etherargs $1 &
|
||||||
|
case 18d14ee3
|
||||||
|
nusb/ether -t rndis $etherargs $1 &
|
||||||
case *
|
case *
|
||||||
switch($4){
|
switch($4){
|
||||||
case *03
|
case *03
|
||||||
|
|
|
@ -763,6 +763,7 @@ extern int a88772init(Dev *);
|
||||||
extern int smscinit(Dev *);
|
extern int smscinit(Dev *);
|
||||||
extern int cdcinit(Dev *);
|
extern int cdcinit(Dev *);
|
||||||
extern int urlinit(Dev *);
|
extern int urlinit(Dev *);
|
||||||
|
extern int rndisinit(Dev *);
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -772,8 +773,9 @@ static struct {
|
||||||
"smsc", smscinit,
|
"smsc", smscinit,
|
||||||
"a88178", a88178init,
|
"a88178", a88178init,
|
||||||
"a88772", a88772init,
|
"a88772", a88772init,
|
||||||
"aue", aueinit,
|
"aue", aueinit,
|
||||||
"url", urlinit,
|
"url", urlinit,
|
||||||
|
"rndis", rndisinit,
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -5,7 +5,7 @@ LIB=../lib/usb.a$O
|
||||||
|
|
||||||
TARG=ether
|
TARG=ether
|
||||||
HFILES=
|
HFILES=
|
||||||
OFILES=ether.$O cdc.$O smsc.$O asix.$O aue.$O url.$O
|
OFILES=ether.$O cdc.$O smsc.$O asix.$O aue.$O url.$O rndis.$O
|
||||||
|
|
||||||
</sys/src/cmd/mkone
|
</sys/src/cmd/mkone
|
||||||
|
|
||||||
|
|
178
sys/src/cmd/nusb/ether/rndis.c
Normal file
178
sys/src/cmd/nusb/ether/rndis.c
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
|
||||||
|
#include "usb.h"
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
static uchar minit[24] = {
|
||||||
|
2, 0, 0, 0, /* type = 2 (init) */
|
||||||
|
24, 0, 0, 0, /* len = 24 */
|
||||||
|
0, 0, 0, 0, /* rid = 1 */
|
||||||
|
1, 0, 0, 0, /* vmajor = 1 */
|
||||||
|
1, 0, 0, 0, /* vminor = 1 */
|
||||||
|
0, 0, 0, 0, /* max xfer */
|
||||||
|
};
|
||||||
|
static uchar mgetmac[28] = {
|
||||||
|
4, 0, 0, 0, /* type = 4 (query) */
|
||||||
|
28, 0, 0, 0, /* len = 28 */
|
||||||
|
0, 0, 0, 0, /* rid = 2 */
|
||||||
|
1, 1, 1, 1, /* oid = get "permanent address" */
|
||||||
|
0, 0, 0, 0, /* buflen = 0 */
|
||||||
|
0, 0, 0, 0, /* bufoff = 0 */
|
||||||
|
0, 0, 0, 0, /* reserved = 0 */
|
||||||
|
};
|
||||||
|
static uchar mfilter[32] = {
|
||||||
|
5, 0, 0, 0, /* type = 5 (set) */
|
||||||
|
32, 0, 0, 0, /* len = 32 */
|
||||||
|
0, 0, 0, 0, /* rid = 3 */
|
||||||
|
14, 1, 1, 0, /* oid = "current filter" */
|
||||||
|
4, 0, 0, 0, /* buflen = 4 */
|
||||||
|
20, 0, 0, 0, /* bufoff = 20 (8+20=28) */
|
||||||
|
0, 0, 0, 0, /* reserved = 0 */
|
||||||
|
12, 0, 0, 0, /* filter = all multicast + broadcast */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
rndisout(Dev *d, int id, uchar *msg, int sz)
|
||||||
|
{
|
||||||
|
return usbcmd(d, Rh2d|Rclass|Riface, Rgetstatus, 0, id, msg, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rndisin(Dev *d, int id, uchar *buf, int sz)
|
||||||
|
{
|
||||||
|
int r, status;
|
||||||
|
for(;;){
|
||||||
|
if((r = usbcmd(d, Rd2h|Rclass|Riface, Rclearfeature, 0, id, buf, sz)) >= 16){
|
||||||
|
if((status = GET4(buf+12)) != 0){
|
||||||
|
werrstr("status 0x%02x", status);
|
||||||
|
r = -1;
|
||||||
|
}else if(GET4(buf) == 7) /* ignore status messages */
|
||||||
|
continue;
|
||||||
|
}else if(r > 0){
|
||||||
|
werrstr("short recv: %d", r);
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rndisreceive(Dev *ep)
|
||||||
|
{
|
||||||
|
Block *b;
|
||||||
|
int n, len;
|
||||||
|
int doff, dlen;
|
||||||
|
|
||||||
|
b = allocb(Maxpkt);
|
||||||
|
if((n = read(ep->dfd, b->rp, b->lim - b->base)) >= 0){
|
||||||
|
if(n < 44)
|
||||||
|
werrstr("short packet: %d bytes", n);
|
||||||
|
else if(GET4(b->rp) != 1)
|
||||||
|
werrstr("not a network packet: type 0x%08ux", GET4(b->wp));
|
||||||
|
else{
|
||||||
|
doff = GET4(b->rp+8);
|
||||||
|
dlen = GET4(b->rp+12);
|
||||||
|
if((len = GET4(b->rp+4)) != n || 8+doff+dlen > len || dlen < Ehdrsz)
|
||||||
|
werrstr("bad packet: doff %d, dlen %d, len %d", doff, dlen, len);
|
||||||
|
else{
|
||||||
|
b->rp += 8 + doff;
|
||||||
|
b->wp = b->rp + dlen;
|
||||||
|
|
||||||
|
etheriq(b, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeb(b);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rndistransmit(Dev *ep, Block *b)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
uchar *req;
|
||||||
|
|
||||||
|
n = BLEN(b);
|
||||||
|
if((req = malloc(44 + n)) != nil){
|
||||||
|
PUT4(req, 1); /* type = 1 (packet) */
|
||||||
|
PUT4(req+4, 44+n); /* len */
|
||||||
|
PUT4(req+8, 44-8); /* data offset */
|
||||||
|
PUT4(req+12, n); /* data length */
|
||||||
|
memset(req+16, 0, 7*4);
|
||||||
|
memcpy(req+44, b->rp, n);
|
||||||
|
write(ep->dfd, req, 44+n);
|
||||||
|
free(req);
|
||||||
|
}
|
||||||
|
freeb(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rndisinit(Dev *d)
|
||||||
|
{
|
||||||
|
uchar res[128];
|
||||||
|
int r, i, off, sz;
|
||||||
|
Ep *ep;
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
for(i = 0; i < nelem(d->usb->ep); i++){
|
||||||
|
if((ep = d->usb->ep[i]) == nil)
|
||||||
|
continue;
|
||||||
|
if(ep->iface->csp == 0x000301e0)
|
||||||
|
r = 1;
|
||||||
|
}
|
||||||
|
if(!r){
|
||||||
|
werrstr("no rndis found");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize */
|
||||||
|
PUT4(minit+20, 1580); /* max xfer = 1580 */
|
||||||
|
if(rndisout(d, 0, minit, sizeof(minit)) < 0)
|
||||||
|
werrstr("init: %r");
|
||||||
|
else if((r = rndisin(d, 0, res, sizeof(res))) < 0)
|
||||||
|
werrstr("init: %r");
|
||||||
|
else if(GET4(res) != 0x80000002 || r < 52)
|
||||||
|
werrstr("not an init response: type 0x%08ux, len %d", GET4(res), r);
|
||||||
|
/* check the type */
|
||||||
|
else if((r = GET4(res+24)) != 1)
|
||||||
|
werrstr("not a connectionless device: %d", r);
|
||||||
|
else if((r = GET4(res+28)) != 0)
|
||||||
|
werrstr("not a 802.3 device: %d", r);
|
||||||
|
else{
|
||||||
|
/* get mac address */
|
||||||
|
if(rndisout(d, 0, mgetmac, sizeof(mgetmac)) < 0)
|
||||||
|
werrstr("send getmac: %r");
|
||||||
|
else if((r = rndisin(d, 0, res, sizeof(res))) < 0)
|
||||||
|
werrstr("recv getmac: %r");
|
||||||
|
else if(GET4(res) != 0x80000004 || r < 24)
|
||||||
|
werrstr("not a query response: type 0x%08ux, len %d", GET4(res), r);
|
||||||
|
else {
|
||||||
|
sz = GET4(res+16);
|
||||||
|
off = GET4(res+20);
|
||||||
|
if(8+off+sz > r || sz != 6)
|
||||||
|
werrstr("invalid mac: off %d, sz %d, len %d", off, sz, r);
|
||||||
|
else{
|
||||||
|
memcpy(macaddr, res+8+off, 6);
|
||||||
|
/* set the filter */
|
||||||
|
if(rndisout(d, 0, mfilter, sizeof(mfilter)) < 0)
|
||||||
|
werrstr("send filter: %r");
|
||||||
|
else if(rndisin(d, 0, res, sizeof(res)) < 0)
|
||||||
|
werrstr("recv filter: %r");
|
||||||
|
else if(GET4(res) != 0x80000005)
|
||||||
|
werrstr("not a filter response: type 0x%08ux", GET4(res));
|
||||||
|
else{
|
||||||
|
epreceive = rndisreceive;
|
||||||
|
eptransmit = rndistransmit;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
Loading…
Reference in a new issue