Files
HoRNDIS/HoRNDIS.h

330 lines
11 KiB
C++

/* HoRNDIS.h
* Declaration of IOKit-derived classes
* HoRNDIS, a RNDIS driver for Mac OS X
*
* Copyright (c) 2012 Joshua Wise.
*
* IOKit examples from Apple's USBCDCEthernet.cpp; not much of that code remains.
*
* RNDIS logic is from linux/drivers/net/usb/rndis_host.c, which is:
*
* Copyright (c) 2005 David Brownell.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <machine/limits.h> /* UINT_MAX */
#include <libkern/OSByteOrder.h>
#include <libkern/OSTypes.h>
#include <IOKit/network/IOEthernetController.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IOGatedOutputQueue.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/assert.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOMessage.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/usb/IOUSBBus.h>
#include <IOKit/usb/IOUSBNub.h>
#include <IOKit/usb/IOUSBDevice.h>
#include <IOKit/usb/IOUSBPipe.h>
#include <IOKit/usb/USB.h>
#include <IOKit/usb/IOUSBInterface.h>
#include <UserNotification/KUNCUserNotifications.h>
extern "C"
{
#include <sys/param.h>
#include <sys/mbuf.h>
}
#define cpu_to_le32(x) (uint32_t)OSSwapHostToLittleInt32(x)
#define le32_to_cpu(x) (uint32_t)OSSwapLittleToHostInt32(x)
#define TRANSMIT_QUEUE_SIZE 256
#define MAX_BLOCK_SIZE PAGE_SIZE
#define kPipeStalled 1
#define N_OUT_BUFS 16
#define OUT_BUF_MAX_TRIES 10 /* 50ms total */
#define OUT_BUF_WAIT_TIME 5000000 /* ns */
#define MAX_MTU 1536
/***** RNDIS definitions -- from linux/include/linux/usb/rndis_host.h ****/
#define RNDIS_CMD_BUF_SZ 1052
struct rndis_msg_hdr {
uint32_t msg_type;
uint32_t msg_len;
uint32_t request_id;
uint32_t status;
} __attribute__((packed));
struct rndis_data_hdr {
uint32_t msg_type;
uint32_t msg_len;
uint32_t data_offset;
uint32_t data_len;
uint32_t oob_data_offset;
uint32_t oob_data_len;
uint32_t num_oob;
uint32_t packet_data_offset;
uint32_t packet_data_len;
uint32_t vc_handle;
uint32_t reserved;
} __attribute__((packed));
struct rndis_query {
uint32_t msg_type;
uint32_t msg_len;
uint32_t request_id;
uint32_t oid;
uint32_t len;
uint32_t offset;
uint32_t handle;
} __attribute__((packed));
struct rndis_query_c {
uint32_t msg_type;
uint32_t msg_len;
uint32_t request_id;
uint32_t status;
uint32_t len;
uint32_t offset;
} __attribute__((packed));
struct rndis_init {
uint32_t msg_type;
uint32_t msg_len;
uint32_t request_id;
uint32_t major_version;
uint32_t minor_version;
uint32_t mtu;
} __attribute__((packed));
struct rndis_init_c {
uint32_t msg_type;
uint32_t msg_len;
uint32_t request_id;
uint32_t status;
uint32_t major_version;
uint32_t minor_version;
uint32_t device_flags;
uint32_t medium;
uint32_t max_packets_per_message;
uint32_t mtu;
uint32_t packet_alignment;
uint32_t af_list_offset;
uint32_t af_list_size;
} __attribute__((packed));
struct rndis_set {
uint32_t msg_type;
uint32_t msg_len;
uint32_t request_id;
uint32_t oid;
uint32_t len;
uint32_t offset;
uint32_t handle;
} __attribute__((packed));
struct rndis_set_c {
uint32_t msg_type;
uint32_t msg_len;
uint32_t request_id;
uint32_t status;
} __attribute__((packed));
#define RNDIS_MSG_COMPLETION cpu_to_le32(0x80000000)
#define RNDIS_MSG_PACKET cpu_to_le32(0x00000001) /* 1-N packets */
#define RNDIS_MSG_INIT cpu_to_le32(0x00000002)
#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_HALT cpu_to_le32(0x00000003)
#define RNDIS_MSG_QUERY cpu_to_le32(0x00000004)
#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_SET cpu_to_le32(0x00000005)
#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_RESET cpu_to_le32(0x00000006)
#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_INDICATE cpu_to_le32(0x00000007)
#define RNDIS_MSG_KEEPALIVE cpu_to_le32(0x00000008)
#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
#define RNDIS_STATUS_SUCCESS cpu_to_le32(0x00000000)
#define RNDIS_STATUS_FAILURE cpu_to_le32(0xc0000001)
#define RNDIS_STATUS_INVALID_DATA cpu_to_le32(0xc0010015)
#define RNDIS_STATUS_NOT_SUPPORTED cpu_to_le32(0xc00000bb)
#define RNDIS_STATUS_MEDIA_CONNECT cpu_to_le32(0x4001000b)
#define RNDIS_STATUS_MEDIA_DISCONNECT cpu_to_le32(0x4001000c)
#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION cpu_to_le32(0x40010012)
#define RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED cpu_to_le32(0x00000000)
#define RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN cpu_to_le32(0x00000001)
#define RNDIS_PHYSICAL_MEDIUM_CABLE_MODEM cpu_to_le32(0x00000002)
#define RNDIS_PHYSICAL_MEDIUM_PHONE_LINE cpu_to_le32(0x00000003)
#define RNDIS_PHYSICAL_MEDIUM_POWER_LINE cpu_to_le32(0x00000004)
#define RNDIS_PHYSICAL_MEDIUM_DSL cpu_to_le32(0x00000005)
#define RNDIS_PHYSICAL_MEDIUM_FIBRE_CHANNEL cpu_to_le32(0x00000006)
#define RNDIS_PHYSICAL_MEDIUM_1394 cpu_to_le32(0x00000007)
#define RNDIS_PHYSICAL_MEDIUM_WIRELESS_WAN cpu_to_le32(0x00000008)
#define RNDIS_PHYSICAL_MEDIUM_MAX cpu_to_le32(0x00000009)
#define OID_802_3_PERMANENT_ADDRESS cpu_to_le32(0x01010101)
#define OID_GEN_MAXIMUM_FRAME_SIZE cpu_to_le32(0x00010106)
#define OID_GEN_CURRENT_PACKET_FILTER cpu_to_le32(0x0001010e)
#define OID_GEN_PHYSICAL_MEDIUM cpu_to_le32(0x00010202)
/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
#define RNDIS_PACKET_TYPE_DIRECTED cpu_to_le32(0x00000001)
#define RNDIS_PACKET_TYPE_MULTICAST cpu_to_le32(0x00000002)
#define RNDIS_PACKET_TYPE_ALL_MULTICAST cpu_to_le32(0x00000004)
#define RNDIS_PACKET_TYPE_BROADCAST cpu_to_le32(0x00000008)
#define RNDIS_PACKET_TYPE_SOURCE_ROUTING cpu_to_le32(0x00000010)
#define RNDIS_PACKET_TYPE_PROMISCUOUS cpu_to_le32(0x00000020)
#define RNDIS_PACKET_TYPE_SMT cpu_to_le32(0x00000040)
#define RNDIS_PACKET_TYPE_ALL_LOCAL cpu_to_le32(0x00000080)
#define RNDIS_PACKET_TYPE_GROUP cpu_to_le32(0x00001000)
#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL cpu_to_le32(0x00002000)
#define RNDIS_PACKET_TYPE_FUNCTIONAL cpu_to_le32(0x00004000)
#define RNDIS_PACKET_TYPE_MAC_FRAME cpu_to_le32(0x00008000)
/* default filter used with RNDIS devices */
#define RNDIS_DEFAULT_FILTER ( \
RNDIS_PACKET_TYPE_DIRECTED | \
RNDIS_PACKET_TYPE_BROADCAST | \
RNDIS_PACKET_TYPE_ALL_MULTICAST | \
RNDIS_PACKET_TYPE_PROMISCUOUS)
#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
/***** Actual class definitions *****/
typedef struct {
bool inuse;
IOBufferMemoryDescriptor *mdp;
void *buf;
IOUSBCompletion comp;
} pipebuf_t;
class HoRNDIS : public IOEthernetController {
OSDeclareDefaultStructors(HoRNDIS); // Constructor & Destructor stuff
private:
bool fTerminate; // being terminated now (i.e., device being unplugged)
IOEthernetInterface *fNetworkInterface;
IONetworkStats *fpNetStats;
OSDictionary *fMediumDict;
bool fNetifEnabled;
bool fDataDead;
IOUSBInterface *fCommInterface;
IOUSBInterface *fDataInterface;
IOUSBPipe *fInPipe;
IOUSBPipe *fOutPipe;
IOLock *xid_lock;
uint32_t xid;
uint32_t mtu;
IOLock *outbuf_lock;
pipebuf_t outbufs[N_OUT_BUFS];
static void dataWriteComplete(void *obj, void *param, IOReturn ior, UInt32 remaining);
pipebuf_t inbuf;
static void dataReadComplete(void *obj, void *param, IOReturn ior, UInt32 remaining);
bool rndisInit();
int rndisCommand(struct rndis_msg_hdr *buf, int buflen);
int rndisQuery(void *buf, uint32_t oid, uint32_t in_len, void **reply, int *reply_len);
bool rndisSetPacketFilter(uint32_t filter);
bool openInterfaces();
int ctrlclass, ctrlsubclass, ctrlprotocol, ctrlconfig;
/* The capitalization, of course, is inconsistent, because that's
* just how it came from the APIs that they wrap. Blame Apple, not
* me. */
static IOService *waitForMatchingUSBInterface(uint32_t cl, uint32_t subcl, uint32_t proto);
IOUSBInterface *FindNextMatchingInterface(IOUSBInterface *intf, uint32_t cl, uint32_t subcl, uint32_t proto);
bool createMediumTables(void);
bool allocateResources(void);
void releaseResources(void);
bool createNetworkInterface(void);
UInt32 outputPacket(mbuf_t pkt, void *param);
IOReturn clearPipeStall(IOUSBPipe *thePipe);
void receivePacket(void *packet, UInt32 size);
IOWorkLoop *workloop;
public:
IOUSBDevice *fpDevice;
IOUSBInterface *fpInterface;
// IOKit overrides
virtual bool init(OSDictionary *properties = 0);
virtual bool start(IOService *provider);
virtual void stop(IOService *provider);
virtual bool createWorkLoop();
virtual IOWorkLoop *getWorkLoop() const;
virtual IOReturn message(UInt32 type, IOService *provider, void *argument = 0);
virtual IOService *probe(IOService *provider, SInt32 *score);
// IOEthernetController overrides
virtual IOReturn enable(IONetworkInterface *netif);
virtual IOReturn disable(IONetworkInterface *netif);
virtual IOReturn getPacketFilters(const OSSymbol *group, UInt32 *filters ) const;
virtual IOReturn getMaxPacketSize(UInt32 * maxSize) const;
virtual IOReturn selectMedium(const IONetworkMedium *medium);
virtual IOReturn getHardwareAddress(IOEthernetAddress *addr);
virtual IOReturn setPromiscuousMode(bool active);
virtual IOOutputQueue *createOutputQueue(void);
virtual bool configureInterface(IONetworkInterface *netif);
virtual IONetworkInterface *createInterface();
};
/* If there are other ways to get access to a device, we probably want them here. */
class HoRNDISUSBDevice : public HoRNDIS {
OSDeclareDefaultStructors(HoRNDISUSBDevice);
public:
virtual bool start(IOService *provider);
};
class HoRNDISInterface : public IOEthernetInterface {
OSDeclareDefaultStructors(HoRNDISInterface);
int maxmtu;
public:
virtual bool init(IONetworkController * controller, int mtu);
virtual bool setMaxTransferUnit(UInt32 mtu);
};