#ifndef __RNDIS_H__ #define __RNDIS_H__ #include #include "util/boostthread.h" #include "util/process.h" #include "vectorutils.h" #include // rndis: // perl /Users/itsme/cvsprj/secphone/trunk/scripts/parseutlog.pl -v ~/cvsprj/xda-devtools/itsutils/comm/UTLog-diamondwj.utl // // struct { // uint32_t type; // uint32_t totallen // // for type 1: // uint32_t hdrlen; // uint32_t payloadlen; // uint32_t nuls[7]; // uint8_t etherpkt[0]; // } // ~/gitprj/repos/linux-2.6/drivers/usb/gadget/rndis.h // ~/gitprj/repos/synce/usb-rndis-ng/src/rndis.h // ~/sources/wince500/PUBLIC/COMMON/OAK/DRIVERS/ETHDBG/RNDISMINI/rndis.h // ~/sources/wince500/PUBLIC/COMMON/DDK/INC/ntddndis.h // todo: only packets go via bulk, // the other control packets via controlwrite(0x21, 0, 0, 0, data) // answer via controlread(0xa1, 1, 0, 0, 0x10) // // todo: add interface to retrieve packets from controlread, and dispatch to the right request class rndis_protocol : public process { class request { // boost::mutex _mtx; // boost::condition _cond; // bool _result; int _id; // ByteVector _reply; public: request(int id) : /*_result(false),*/ _id(id) { } int id() const { return _id; } // const ByteVector& reply() const { return _reply; } // void wait() // { // boost::mutex::scoped_lock lock(_mtx); // while (!_result) // _cond.wait(lock); // } // void setresult(const ByteVector& reply) // { // boost::mutex::scoped_lock lock(_mtx); // _reply= reply; // _result= true; // _cond.notify_one(); // } // bool haveresult() const { return _result; } }; typedef boost::shared_ptr request_ptr; typedef std::map requestmap_t; //typedef std::map requesttypemap_t; boost::mutex _mtx; requestmap_t _reqlist; usbdev& _ph; int _curid; boost::mutex _qmtx; boost::condition _qcond; std::deque _q; public: enum { OID_GEN_SUPPORTED_LIST=0x00010101, OID_GEN_MAXIMUM_LOOKAHEAD=0x00010105, OID_GEN_MAXIMUM_FRAME_SIZE=0x00010106, OID_GEN_LINK_SPEED=0x00010107, OID_GEN_VENDOR_ID=0x0001010c, OID_GEN_CURRENT_PACKET_FILTER=0x0001010e, OID_GEN_CURRENT_LOOKAHEAD=0x0001010f, OID_GEN_MAC_OPTIONS=0x00010113, OID_GEN_MEDIA_CONNECT_STATUS=0x00010114, OID_GEN_MAXIMUM_SEND_PACKETS=0x00010115, OID_GEN_VENDOR_DRIVER_VERSION=0x00010116, OID_802_3_PERMANENT_ADDRESS=0x01010101, OID_802_3_CURRENT_ADDRESS=0x01010102, OID_802_3_MULTICAST_LIST=0x01010103, OID_802_3_MAXIMUM_LIST_SIZE=0x01010104, }; enum { RNDIS_COMPLETE = 0x80000000 }; enum { REMOTE_NDIS_PACKET_MSG = 1, REMOTE_NDIS_INITIALIZE_MSG = 2, REMOTE_NDIS_INITIALIZE_CMPLT = RNDIS_COMPLETE|2, // 3: HALT REMOTE_NDIS_QUERY_MSG = 4, REMOTE_NDIS_QUERY_CMPLT = RNDIS_COMPLETE|4, REMOTE_NDIS_SET_MSG = 5, REMOTE_NDIS_SET_CMPLT = RNDIS_COMPLETE|5, // 6: RESET // 7: INDICATE STATUS // 8: KEEPALIVE }; rndis_protocol(usbdev& ph) : _ph(ph), _curid(0) { start(); } virtual ~rndis_protocol() { stop(); } virtual const char*name() { return "rndis"; } virtual void service() { ByteVector pkt(4096); size_t rc= _ph.bulkread(&pkt.front(), &pkt.front()+pkt.size()); pkt.resize(rc); if (pkt.size()<44) { printf("short rndis msg: %s\n", hexdump(pkt).c_str()); return; } uint32_t pkttype; uint32_t pktlen; uint32_t ofs; uint32_t len; bufunpack2(pkt, "VVVV", &pkttype, &pktlen, &ofs, &len); if (pkttype!=REMOTE_NDIS_PACKET_MSG) { printf("unknown type msg: %s\n", hexdump(pkt).c_str()); return; } if (ofs!=0x24) { printf("ofs != 24: %x\n",ofs); } boost::mutex::scoped_lock lock(_qmtx); _q.push_back(ByteVector(&pkt.front()+ofs+8, &pkt.front()+ofs+8+len)); _qcond.notify_one(); } void register_request(int type, request_ptr req) { boost::mutex::scoped_lock lock(_mtx); _reqlist.insert(requestmap_t::value_type(req->id(), req)); } request_ptr rndis_send_request(int req, int reply, const ByteVector& v) { request_ptr rr= request_ptr(new request(_curid++)); register_request(reply, rr); _ph.controlwrite(0x21, 0, 0, 0, bufpack("VVVB", req, v.size()+3*sizeof(uint32_t), rr->id(), &v)); return rr; } void rndis_init() { fprintf(stderr,"sending init req\n"); request_ptr req= rndis_send_request(REMOTE_NDIS_INITIALIZE_MSG, REMOTE_NDIS_INITIALIZE_CMPLT, bufpack("VVV", 1, 0, 0x4000)); fprintf(stderr,"waiting for init answer\n"); //req->wait(); ByteVector v(0x1000); _ph.controlread(0xa1, 1, 0, 0, v); // if (req->haveresult()) { // fprintf(stderr,"have init answer\n"); // ByteVector v= req->reply(); struct { int32_t id; uint32_t status; uint32_t vmajor; uint32_t vminor; uint32_t flags; uint32_t medium; uint32_t maxppm; uint32_t mtu; uint32_t align; uint32_t afofs; uint32_t afsize; } hdr; uint32_t replytype; uint32_t replylen; bufunpack2(v, "VVVVVVVVVVVVV", &replytype, &replylen, &hdr.id, &hdr.status, &hdr.vmajor, &hdr.vminor, &hdr.flags, &hdr.medium, &hdr.maxppm, &hdr.mtu, &hdr.align, &hdr.afofs, &hdr.afsize); if (replylen!=v.size()) printf("ERROR: replylen mismatch: %x iso %x\n", replylen, (int)v.size()); if (replytype!=REMOTE_NDIS_INITIALIZE_CMPLT) printf("ERROR: replytype mismatch: %x iso %x\n", replytype, REMOTE_NDIS_INITIALIZE_CMPLT); if (req->id()!=hdr.id) printf("ERROR: ID mismatch: %02x iso %02x\n", hdr.id, req->id()); printf("INIT->stat=%d, v%d.%d, f%x, m%d, %dppm, mtu=%d, a=%d, a:ofs/size=%x,%x\n", hdr.status, hdr.vmajor, hdr.vminor, hdr.flags, hdr.medium, hdr.maxppm, hdr.mtu, hdr.align, hdr.afofs, hdr.afsize); // } // else { // fprintf(stderr,"don't have init answer\n"); // } } ByteVector rndis_query(uint32_t oid, size_t len) { ByteVector rqv= bufpack("VVVV", oid, len, 0x14, 0); rqv.resize(rqv.size()+len); request_ptr req= rndis_send_request(REMOTE_NDIS_QUERY_MSG, REMOTE_NDIS_QUERY_CMPLT, rqv); //req->wait(); ByteVector v(0x1000); _ph.controlread(0xa1, 1, 0, 0, v); // if (req->haveresult()) { // ByteVector v= req->reply(); struct { int32_t id; uint32_t status; uint32_t len; uint32_t ofs; } hdr; uint32_t replytype; uint32_t replylen; bufunpack2(v, "VVVVVV", &replytype, &replylen, &hdr.id, &hdr.status, &hdr.len, &hdr.ofs); if (replylen!=v.size()) printf("ERROR: replylen mismatch: %x iso %x\n", replylen, (int)v.size()); if (replytype!=REMOTE_NDIS_QUERY_CMPLT) printf("ERROR: replytype mismatch: %x iso %x\n", replytype, REMOTE_NDIS_QUERY_CMPLT); if (req->id()!=hdr.id) printf("ERROR: ID mismatch: %02x iso %02x\n", hdr.id, req->id()); if (hdr.status) { fprintf(stderr,"query(%08x) -> status=%08x\n", oid, hdr.status); return ByteVector(); } if (hdr.ofs!=0x10) { fprintf(stderr,"query(%08x) -> ofs=%08x\n", oid, hdr.ofs); } if (hdr.len!=v.size()-hdr.ofs-8) { fprintf(stderr,"query(%08x) len mismatch -> hlen=%08x, dlen=%08x\n", oid, hdr.len, (int)v.size()-hdr.ofs-8); } return ByteVector(&v.front()+hdr.ofs+8, &v.front()+hdr.ofs+8+hdr.len); // } // else { // fprintf(stderr,"query(%08x): no result\n", oid); // return ByteVector(); // } } uint32_t rndis_query_u32(uint32_t oid) { ByteVector v= rndis_query(oid, sizeof(uint32_t)); return v.size()>=sizeof(uint32_t) ? BV_GetDword(v) : 0; } uint16_t rndis_query_u16(uint32_t oid) { ByteVector v= rndis_query(oid, sizeof(uint16_t)); return v.size()>=sizeof(uint16_t) ? BV_GetWord(v) : 0; } void rndis_query(uint32_t oid, std::string& s) { ByteVector v= rndis_query(oid, 64); s= BV_GetString(v, v.size()); } void rndis_query(uint32_t oid, DwordVector& vw) { ByteVector v= rndis_query(oid, 0); vw.resize(v.size()/sizeof(uint32_t)); memcpy(&vw.front(), &v.front(), vw.size()*sizeof(uint32_t)); } void rndis_query(uint32_t oid, ByteVector& v) { v= rndis_query(oid, v.size()); } void rndis_set(uint32_t oid, uint32_t value) { request_ptr req= rndis_send_request(REMOTE_NDIS_SET_MSG, REMOTE_NDIS_SET_CMPLT, bufpack("VVVVV", oid, sizeof(uint32_t), 0x14, 0, value)); //req->wait(); ByteVector v(0x1000); _ph.controlread(0xa1, 1, 0, 0, v); // if (req->haveresult()) { // ByteVector v= req->reply(); struct { int32_t id; uint32_t status; } hdr; uint32_t replytype; uint32_t replylen; bufunpack2(v, "VVVV", &replytype, &replylen, &hdr.id, &hdr.status); if (replylen!=v.size()) printf("ERROR: replylen mismatch: %x iso %x\n", replylen, (int)v.size()); if (replytype!=REMOTE_NDIS_SET_CMPLT) printf("ERROR: replytype mismatch: %x iso %x\n", replytype, REMOTE_NDIS_SET_CMPLT); if (req->id()!=hdr.id) printf("ERROR: ID mismatch: %02x iso %02x\n", hdr.id, req->id()); if (hdr.status) { fprintf(stderr,"set(%08x) -> status=%08x\n", oid, hdr.status); } // } // else { // fprintf(stderr,"set(%08x): no result\n", oid); // } } size_t rndis_send_packet(const ByteVector &pkt) { ByteVector rndispkt= bufpack("VVVVz28B", REMOTE_NDIS_PACKET_MSG, pkt.size()+0x2c, 0x24, pkt.size(), &pkt); return _ph.bulkwrite(&rndispkt.front(), &rndispkt.front()+rndispkt.size()); } size_t rndis_read_packet(ByteVector& pkt) { boost::mutex::scoped_lock lock(_qmtx); while (_q.empty()) _qcond.wait(lock); pkt= _q.front(); _q.pop_front(); return pkt.size(); } }; #endif