Skip to content
This repository
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 314 lines (264 sloc) 10.534 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
/* 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)(x))
#define le32_to_cpu(x) ((uint32_t)(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;

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 createMediumTables(void);
bool allocateResources(void);
void releaseResources(void);
bool openInterfaces();
bool createNetworkInterface(void);
UInt32 outputPacket(mbuf_t pkt, void *param);
IOReturn clearPipeStall(IOUSBPipe *thePipe);
void receivePacket(void *packet, UInt32 size);

public:
IOUSBDevice *fpDevice;

// IOKit overrides
virtual bool init(OSDictionary *properties = 0);
virtual bool start(IOService *provider);
virtual void stop(IOService *provider);
virtual IOReturn message(UInt32 type, IOService *provider, void *argument = 0);

// 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 HoRNDISUSBInterface : public HoRNDIS {
OSDeclareDefaultStructors(HoRNDISUSBInterface);
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);
};
Something went wrong with that request. Please try again.