/* The driver for your USB chip needs to support ep0 OUT to work with * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional). * * Windows hosts need an INF file like Documentation/usb/linux.inf * and will be happier if you provide the host_addr module parameter.
*/
#ifdef RNDIS_PM /* PM and wakeup are "mandatory" for USB, but the RNDIS specs * don't say what they mean ... and the NDIS specs are often * confusing and/or ambiguous in this context. (That is, more * so than their specs for the other OIDs.) * * FIXME someone who knows what these should do, please * implement them!
*/
/* power management */
OID_PNP_CAPABILITIES,
OID_PNP_QUERY_POWER,
OID_PNP_SET_POWER,
#ifdef RNDIS_WAKEUP /* wake up host */
OID_PNP_ENABLE_WAKE_UP,
OID_PNP_ADD_WAKE_UP_PATTERN,
OID_PNP_REMOVE_WAKE_UP_PATTERN, #endif/* RNDIS_WAKEUP */ #endif/* RNDIS_PM */
};
if (!r) return -ENOMEM;
resp = (rndis_query_cmplt_type *)r->buf;
if (!resp) return -ENOMEM;
if (buf_len && rndis_debug > 1) {
pr_debug("query OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) {
pr_debug("%03d: %08x %08x %08x %08x\n", i,
get_unaligned_le32(&buf[i]),
get_unaligned_le32(&buf[i + 4]),
get_unaligned_le32(&buf[i + 8]),
get_unaligned_le32(&buf[i + 12]));
}
}
/* response goes here, right after the header */
outbuf = (__le32 *)&resp[1];
resp->InformationBufferOffset = cpu_to_le32(16);
net = params->dev;
stats = dev_get_stats(net, &temp);
switch (OID) {
/* general oids (table 4-1) */
/* mandatory */ case RNDIS_OID_GEN_SUPPORTED_LIST:
pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__);
length = sizeof(oid_supported_list);
count = length / sizeof(u32); for (i = 0; i < count; i++)
outbuf[i] = cpu_to_le32(oid_supported_list[i]);
retval = 0; break;
/* mandatory */ case RNDIS_OID_GEN_HARDWARE_STATUS:
pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__); /* Bogus question! * Hardware must be ready to receive high level protocols. * BTW: * reddite ergo quae sunt Caesaris Caesari * et quae sunt Dei Deo!
*/
*outbuf = cpu_to_le32(0);
retval = 0; break;
/* mandatory */ case RNDIS_OID_GEN_MEDIA_IN_USE:
pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__); /* one medium, one transport... (maybe you do it better) */
*outbuf = cpu_to_le32(params->medium);
retval = 0; break;
/* mandatory */ case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE:
pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__); if (params->dev) {
*outbuf = cpu_to_le32(params->dev->mtu);
retval = 0;
} break;
/* mandatory */ case RNDIS_OID_GEN_LINK_SPEED: if (rndis_debug > 1)
pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__); if (params->media_state == RNDIS_MEDIA_STATE_DISCONNECTED)
*outbuf = cpu_to_le32(0); else
*outbuf = cpu_to_le32(params->speed);
retval = 0; break;
/* mandatory */ case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE:
pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__); if (params->dev) {
*outbuf = cpu_to_le32(params->dev->mtu);
retval = 0;
} break;
/* mandatory */ case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE:
pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__); if (params->dev) {
*outbuf = cpu_to_le32(params->dev->mtu);
retval = 0;
} break;
case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION:
pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__); /* Created as LE */
*outbuf = rndis_driver_version;
retval = 0; break;
staticint gen_ndis_set_resp(struct rndis_params *params, u32 OID,
u8 *buf, u32 buf_len, rndis_resp_t *r)
{
rndis_set_cmplt_type *resp; int i, retval = -ENOTSUPP;
if (!r) return -ENOMEM;
resp = (rndis_set_cmplt_type *)r->buf; if (!resp) return -ENOMEM;
if (buf_len && rndis_debug > 1) {
pr_debug("set OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) {
pr_debug("%03d: %08x %08x %08x %08x\n", i,
get_unaligned_le32(&buf[i]),
get_unaligned_le32(&buf[i + 4]),
get_unaligned_le32(&buf[i + 8]),
get_unaligned_le32(&buf[i + 12]));
}
}
switch (OID) { case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
/* these NDIS_PACKET_TYPE_* bitflags are shared with * cdc_filter; it's not RNDIS-specific * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST
*/
*params->filter = (u16)get_unaligned_le32(buf);
pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__func__, *params->filter);
/* this call has a significant side effect: it's * what makes the packet flow start and stop, like * activating the CDC Ethernet altsetting.
*/
retval = 0; if (*params->filter) {
params->state = RNDIS_DATA_INITIALIZED;
netif_carrier_on(params->dev); if (netif_running(params->dev))
netif_wake_queue(params->dev);
} else {
params->state = RNDIS_INITIALIZED;
netif_carrier_off(params->dev);
netif_stop_queue(params->dev);
} break;
case RNDIS_OID_802_3_MULTICAST_LIST: /* I think we can ignore this */
pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
retval = 0; break;
default:
pr_warn("%s: set unknown OID 0x%08X, size %d\n",
__func__, OID, buf_len);
}
/* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */ if (!params->dev) return -ENOTSUPP;
/* * we need more memory: * gen_ndis_query_resp expects enough space for * rndis_query_cmplt_type followed by data. * oid_supported_list is the largest data reply
*/
r = rndis_add_response(params, sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type)); if (!r) return -ENOMEM;
resp = (rndis_query_cmplt_type *)r->buf;
resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
/* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for * rx/tx statistics and link status, in addition to KEEPALIVE traffic * and normal HC level polling to see if there's any IN traffic.
*/
/* For USB: responses may take up to 10 seconds */ switch (MsgType) { case RNDIS_MSG_INIT:
pr_debug("%s: RNDIS_MSG_INIT\n",
__func__);
params->state = RNDIS_INITIALIZED; return rndis_init_response(params, (rndis_init_msg_type *)buf);
case RNDIS_MSG_HALT:
pr_debug("%s: RNDIS_MSG_HALT\n",
__func__);
params->state = RNDIS_UNINITIALIZED; if (params->dev) {
netif_carrier_off(params->dev);
netif_stop_queue(params->dev);
} return 0;
case RNDIS_MSG_QUERY: return rndis_query_response(params,
(rndis_query_msg_type *)buf);
case RNDIS_MSG_SET: return rndis_set_response(params, (rndis_set_msg_type *)buf);
case RNDIS_MSG_RESET:
pr_debug("%s: RNDIS_MSG_RESET\n",
__func__); return rndis_reset_response(params,
(rndis_reset_msg_type *)buf);
case RNDIS_MSG_KEEPALIVE: /* For USB: host does this every 5 seconds */ if (rndis_debug > 1)
pr_debug("%s: RNDIS_MSG_KEEPALIVE\n",
__func__); return rndis_keepalive_response(params,
(rndis_keepalive_msg_type *)
buf);
default: /* At least Windows XP emits some undefined RNDIS messages. * In one case those messages seemed to relate to the host * suspending itself.
*/
pr_warn("%s: unknown RNDIS message 0x%08X len %d\n",
__func__, MsgType, MsgLength); /* Garbled message can be huge, so limit what we display */ if (MsgLength > 16)
MsgLength = 16;
print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
buf, MsgLength); break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.