Skip to content

Commit

Permalink
[rndis] Add generic RNDIS device abstraction
Browse files Browse the repository at this point in the history
RNDIS provides an abstraction of a network device on top of a generic
packet transmission mechanism.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Dec 18, 2014
1 parent c86b222 commit 1d2b7c9
Show file tree
Hide file tree
Showing 4 changed files with 1,204 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/include/ipxe/errfile.h
Expand Up @@ -227,6 +227,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_ping ( ERRFILE_NET | 0x003a0000 )
#define ERRFILE_dhcpv6 ( ERRFILE_NET | 0x003b0000 )
#define ERRFILE_nfs_uri ( ERRFILE_NET | 0x003c0000 )
#define ERRFILE_rndis ( ERRFILE_NET | 0x003d0000 )

#define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 )
Expand Down
11 changes: 5 additions & 6 deletions src/include/ipxe/netdevice.h
Expand Up @@ -36,13 +36,12 @@ struct device;

/** Maximum length of a link-layer header
*
* The longest currently-supported link-layer header is for 802.11: a
* 24-byte frame header plus an 8-byte 802.3 LLC/SNAP header, plus a
* possible 4-byte VLAN header. (The IPoIB link-layer pseudo-header
* doesn't actually include link-layer addresses; see ipoib.c for
* details.)
* The longest currently-supported link-layer header is for RNDIS: an
* 8-byte RNDIS header, a 32-byte RNDIS packet message header, a
* 14-byte Ethernet header and a possible 4-byte VLAN header. Round
* up to 64 bytes.
*/
#define MAX_LL_HEADER_LEN 36
#define MAX_LL_HEADER_LEN 64

/** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 16
Expand Down
348 changes: 348 additions & 0 deletions src/include/ipxe/rndis.h
@@ -0,0 +1,348 @@
#ifndef _IPXE_RNDIS_H
#define _IPXE_RNDIS_H

/** @file
*
* Remote Network Driver Interface Specification
*
*/

FILE_LICENCE ( GPL2_OR_LATER );

#include <stdint.h>
#include <ipxe/netdevice.h>
#include <ipxe/iobuf.h>

/** Maximum time to wait for a transaction to complete
*
* This is a policy decision.
*/
#define RNDIS_MAX_WAIT_MS 1000

/** RNDIS message header */
struct rndis_header {
/** Message type */
uint32_t type;
/** Message length */
uint32_t len;
} __attribute__ (( packed ));

/** RNDIS initialise message */
#define RNDIS_INITIALIZE_MSG 0x00000002UL

/** RNDIS initialise message */
struct rndis_initialize_message {
/** Request ID */
uint32_t id;
/** Major version */
uint32_t major;
/** Minor version */
uint32_t minor;
/** Maximum transfer size */
uint32_t mtu;
} __attribute__ (( packed ));

/** RNDIS initialise completion */
#define RNDIS_INITIALISE_CMPLT 0x80000002UL

/** RNDIS initialise completion */
struct rndis_initialise_completion {
/** Request ID */
uint32_t id;
/** Status */
uint32_t status;
/** Major version */
uint32_t major;
/** Minor version */
uint32_t minor;
/** Device flags */
uint32_t flags;
/** Medium */
uint32_t medium;
/** Maximum packets per transfer */
uint32_t max_pkts;
/** Maximum transfer size */
uint32_t mtu;
/** Packet alignment factor */
uint32_t align;
/** Reserved */
uint32_t reserved;
} __attribute__ (( packed ));

/** RNDIS halt message */
#define RNIS_HALT_MSG 0x00000003UL

/** RNDIS halt message */
struct rndis_halt_message {
/** Request ID */
uint32_t id;
} __attribute__ (( packed ));

/** RNDIS query OID message */
#define RNDIS_QUERY_MSG 0x00000004UL

/** RNDIS set OID message */
#define RNDIS_SET_MSG 0x00000005UL

/** RNDIS query or set OID message */
struct rndis_oid_message {
/** Request ID */
uint32_t id;
/** Object ID */
uint32_t oid;
/** Information buffer length */
uint32_t len;
/** Information buffer offset */
uint32_t offset;
/** Reserved */
uint32_t reserved;
} __attribute__ (( packed ));

/** RNDIS query OID completion */
#define RNDIS_QUERY_CMPLT 0x80000004UL

/** RNDIS query OID completion */
struct rndis_query_completion {
/** Request ID */
uint32_t id;
/** Status */
uint32_t status;
/** Information buffer length */
uint32_t len;
/** Information buffer offset */
uint32_t offset;
} __attribute__ (( packed ));

/** RNDIS set OID completion */
#define RNDIS_SET_CMPLT 0x80000005UL

/** RNDIS set OID completion */
struct rndis_set_completion {
/** Request ID */
uint32_t id;
/** Status */
uint32_t status;
} __attribute__ (( packed ));

/** RNDIS reset message */
#define RNDIS_RESET_MSG 0x00000006UL

/** RNDIS reset message */
struct rndis_reset_message {
/** Reserved */
uint32_t reserved;
} __attribute__ (( packed ));

/** RNDIS reset completion */
#define RNDIS_RESET_CMPLT 0x80000006UL

/** RNDIS reset completion */
struct rndis_reset_completion {
/** Status */
uint32_t status;
/** Addressing reset */
uint32_t addr;
} __attribute__ (( packed ));

/** RNDIS indicate status message */
#define RNDIS_INDICATE_STATUS_MSG 0x00000007UL

/** RNDIS diagnostic information */
struct rndis_diagnostic_info {
/** Status */
uint32_t status;
/** Error offset */
uint32_t offset;
} __attribute__ (( packed ));

/** RNDIS indicate status message */
struct rndis_indicate_status_message {
/** Status */
uint32_t status;
/** Status buffer length */
uint32_t len;
/** Status buffer offset */
uint32_t offset;
/** Diagnostic information (optional) */
struct rndis_diagnostic_info diag[0];
} __attribute__ (( packed ));

/** RNDIS status codes */
enum rndis_status {
/** Device is connected to a network medium */
RNDIS_STATUS_MEDIA_CONNECT = 0x4001000bUL,
/** Device is disconnected from the medium */
RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000cUL,
};

/** RNDIS keepalive message */
#define RNDIS_KEEPALIVE_MSG 0x00000008UL

/** RNDIS keepalive message */
struct rndis_keepalive_message {
/** Request ID */
uint32_t id;
} __attribute__ (( packed ));

/** RNDIS keepalive completion */
#define RNDIS_KEEPALIVE_CMPLT 0x80000008UL

/** RNDIS keepalive completion */
struct rndis_keepalive_completion {
/** Request ID */
uint32_t id;
/** Status */
uint32_t status;
} __attribute__ (( packed ));

/** RNDIS packet message */
#define RNDIS_PACKET_MSG 0x00000001UL

/** RNDIS packet field */
struct rndis_packet_field {
/** Offset */
uint32_t offset;
/** Length */
uint32_t len;
} __attribute__ (( packed ));

/** RNDIS packet message */
struct rndis_packet_message {
/** Data */
struct rndis_packet_field data;
/** Out-of-band data records */
struct rndis_packet_field oob;
/** Number of out-of-band data records */
uint32_t oob_count;
/** Per-packet information record */
struct rndis_packet_field ppi;
/** Reserved */
uint32_t reserved;
} __attribute__ (( packed ));

/** RNDIS packet record */
struct rndis_packet_record {
/** Length */
uint32_t len;
/** Type */
uint32_t type;
/** Offset */
uint32_t offset;
} __attribute__ (( packed ));

/** OID for packet filter */
#define RNDIS_OID_GEN_CURRENT_PACKET_FILTER 0x0001010eUL

/** Packet filter bits */
enum rndis_packet_filter {
/** Unicast packets */
RNDIS_FILTER_UNICAST = 0x00000001UL,
/** Multicast packets */
RNDIS_FILTER_MULTICAST = 0x00000002UL,
/** All multicast packets */
RNDIS_FILTER_ALL_MULTICAST = 0x00000004UL,
/** Broadcast packets */
RNDIS_FILTER_BROADCAST = 0x00000008UL,
/** All packets */
RNDIS_FILTER_PROMISCUOUS = 0x00000020UL
};

/** OID for media status */
#define RNDIS_OID_GEN_MEDIA_CONNECT_STATUS 0x00010114UL

/** OID for permanent MAC address */
#define RNDIS_OID_802_3_PERMANENT_ADDRESS 0x01010101UL

/** OID for current MAC address */
#define RNDIS_OID_802_3_CURRENT_ADDRESS 0x01010102UL

struct rndis_device;

/** RNDIS device operations */
struct rndis_operations {
/**
* Open RNDIS device
*
* @v rndis RNDIS device
* @ret rc Return status code
*/
int ( * open ) ( struct rndis_device *rndis );
/**
* Close RNDIS device
*
* @v rndis RNDIS device
*/
void ( * close ) ( struct rndis_device *rndis );
/**
* Transmit packet
*
* @v rndis RNDIS device
* @v iobuf I/O buffer
* @ret rc Return status code
*
* If this method returns success then the RNDIS device must
* eventually report completion via rndis_tx_complete().
*/
int ( * transmit ) ( struct rndis_device *rndis,
struct io_buffer *iobuf );
/**
* Poll for completed and received packets
*
* @v rndis RNDIS device
*/
void ( * poll ) ( struct rndis_device *rndis );
};

/** An RNDIS device */
struct rndis_device {
/** Network device */
struct net_device *netdev;
/** Device name */
const char *name;
/** RNDIS operations */
struct rndis_operations *op;
/** Driver private data */
void *priv;

/** Request ID for current blocking request */
unsigned int wait_id;
/** Return status code for current blocking request */
int wait_rc;
};

/**
* Initialise an RNDIS device
*
* @v rndis RNDIS device
* @v op RNDIS device operations
*/
static inline void rndis_init ( struct rndis_device *rndis,
struct rndis_operations *op ) {

rndis->op = op;
}

extern void rndis_tx_complete_err ( struct rndis_device *rndis,
struct io_buffer *iobuf, int rc );
extern int rndis_tx_defer ( struct rndis_device *rndis,
struct io_buffer *iobuf );
extern void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf );

extern struct rndis_device * alloc_rndis ( size_t priv_len );
extern int register_rndis ( struct rndis_device *rndis );
extern void unregister_rndis ( struct rndis_device *rndis );
extern void free_rndis ( struct rndis_device *rndis );

/**
* Complete message transmission
*
* @v rndis RNDIS device
* @v iobuf I/O buffer
*/
static inline void rndis_tx_complete ( struct rndis_device *rndis,
struct io_buffer *iobuf ) {

rndis_tx_complete_err ( rndis, iobuf, 0 );
}

#endif /* _IPXE_RNDIS_H */

0 comments on commit 1d2b7c9

Please sign in to comment.