in drivers/usb/gadget/rndis.c [144:644]
static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
unsigned buf_len, rndis_resp_t *r)
{
int retval = -ENOTSUPP;
u32 length = 4; /* usually */
__le32 *outbuf;
int i, count;
rndis_query_cmplt_type *resp;
rndis_params *params;
if (!r)
return -ENOMEM;
resp = (rndis_query_cmplt_type *) r->buf;
if (!resp)
return -ENOMEM;
#if defined(DEBUG) && defined(DEBUG_VERBOSE)
if (buf_len) {
debug("query OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
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]));
}
}
#endif
/* response goes here, right after the header */
outbuf = (__le32 *) &resp[1];
resp->InformationBufferOffset = __constant_cpu_to_le32(16);
params = &rndis_per_dev_params[configNr];
switch (OID) {
/* general oids (table 4-1) */
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
debug("%s: 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 OID_GEN_HARDWARE_STATUS:
debug("%s: 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 = __constant_cpu_to_le32(0);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__);
*outbuf = cpu_to_le32(params->medium);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
debug("%s: 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 OID_GEN_MAXIMUM_FRAME_SIZE:
debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
if (params->dev) {
*outbuf = cpu_to_le32(params->mtu);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_LINK_SPEED:
#if defined(DEBUG) && defined(DEBUG_VERBOSE)
debug("%s: OID_GEN_LINK_SPEED\n", __func__);
#endif
if (params->media_state == NDIS_MEDIA_STATE_DISCONNECTED)
*outbuf = __constant_cpu_to_le32(0);
else
*outbuf = cpu_to_le32(params->speed);
retval = 0;
break;
/* mandatory */
case OID_GEN_TRANSMIT_BLOCK_SIZE:
debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
if (params->dev) {
*outbuf = cpu_to_le32(params->mtu);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_RECEIVE_BLOCK_SIZE:
debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
if (params->dev) {
*outbuf = cpu_to_le32(params->mtu);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_VENDOR_ID:
debug("%s: OID_GEN_VENDOR_ID\n", __func__);
*outbuf = cpu_to_le32(params->vendorID);
retval = 0;
break;
/* mandatory */
case OID_GEN_VENDOR_DESCRIPTION:
debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__);
length = strlen(params->vendorDescr);
memcpy(outbuf, params->vendorDescr, length);
retval = 0;
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
debug("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
/* Created as LE */
*outbuf = rndis_driver_version;
retval = 0;
break;
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
*outbuf = cpu_to_le32(*params->filter);
retval = 0;
break;
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
debug("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_CONNECT_STATUS:
#if defined(DEBUG) && defined(DEBUG_VERBOSE)
debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
#endif
*outbuf = cpu_to_le32(params->media_state);
retval = 0;
break;
case OID_GEN_PHYSICAL_MEDIUM:
debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__);
*outbuf = __constant_cpu_to_le32(0);
retval = 0;
break;
/*
* The RNDIS specification is incomplete/wrong. Some versions
* of MS-Windows expect OIDs that aren't specified there. Other
* versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
*/
case OID_GEN_MAC_OPTIONS: /* from WinME */
debug("%s: OID_GEN_MAC_OPTIONS\n", __func__);
*outbuf = __constant_cpu_to_le32(
NDIS_MAC_OPTION_RECEIVE_SERIALIZED
| NDIS_MAC_OPTION_FULL_DUPLEX);
retval = 0;
break;
/* statistics OIDs (table 4-2) */
/* mandatory */
case OID_GEN_XMIT_OK:
#if defined(DEBUG) && defined(DEBUG_VERBOSE)
debug("%s: OID_GEN_XMIT_OK\n", __func__);
#endif
if (params->stats) {
*outbuf = cpu_to_le32(
params->stats->tx_packets -
params->stats->tx_errors -
params->stats->tx_dropped);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_RCV_OK:
#if defined(DEBUG) && defined(DEBUG_VERBOSE)
debug("%s: OID_GEN_RCV_OK\n", __func__);
#endif
if (params->stats) {
*outbuf = cpu_to_le32(
params->stats->rx_packets -
params->stats->rx_errors -
params->stats->rx_dropped);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_XMIT_ERROR:
#if defined(DEBUG) && defined(DEBUG_VERBOSE)
debug("%s: OID_GEN_XMIT_ERROR\n", __func__);
#endif
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->tx_errors);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_RCV_ERROR:
#if defined(DEBUG) && defined(DEBUG_VERBOSE)
debug("%s: OID_GEN_RCV_ERROR\n", __func__);
#endif
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->rx_errors);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_RCV_NO_BUFFER:
debug("%s: OID_GEN_RCV_NO_BUFFER\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->rx_dropped);
retval = 0;
}
break;
#ifdef RNDIS_OPTIONAL_STATS
case OID_GEN_DIRECTED_BYTES_XMIT:
debug("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __func__);
/*
* Aunt Tilly's size of shoes
* minus antarctica count of penguins
* divided by weight of Alpha Centauri
*/
if (params->stats) {
*outbuf = cpu_to_le32(
(params->stats->tx_packets -
params->stats->tx_errors -
params->stats->tx_dropped)
* 123);
retval = 0;
}
break;
case OID_GEN_DIRECTED_FRAMES_XMIT:
debug("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __func__);
/* dito */
if (params->stats) {
*outbuf = cpu_to_le32(
(params->stats->tx_packets -
params->stats->tx_errors -
params->stats->tx_dropped)
/ 123);
retval = 0;
}
break;
case OID_GEN_MULTICAST_BYTES_XMIT:
debug("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->multicast * 1234);
retval = 0;
}
break;
case OID_GEN_MULTICAST_FRAMES_XMIT:
debug("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->multicast);
retval = 0;
}
break;
case OID_GEN_BROADCAST_BYTES_XMIT:
debug("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->tx_packets/42*255);
retval = 0;
}
break;
case OID_GEN_BROADCAST_FRAMES_XMIT:
debug("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->tx_packets / 42);
retval = 0;
}
break;
case OID_GEN_DIRECTED_BYTES_RCV:
debug("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __func__);
*outbuf = __constant_cpu_to_le32(0);
retval = 0;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
debug("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __func__);
*outbuf = __constant_cpu_to_le32(0);
retval = 0;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
debug("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->multicast * 1111);
retval = 0;
}
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
debug("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->multicast);
retval = 0;
}
break;
case OID_GEN_BROADCAST_BYTES_RCV:
debug("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->rx_packets/42*255);
retval = 0;
}
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
debug("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->rx_packets / 42);
retval = 0;
}
break;
case OID_GEN_RCV_CRC_ERROR:
debug("%s: OID_GEN_RCV_CRC_ERROR\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->rx_crc_errors);
retval = 0;
}
break;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
debug("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __func__);
*outbuf = __constant_cpu_to_le32(0);
retval = 0;
break;
#endif /* RNDIS_OPTIONAL_STATS */
/* ieee802.3 OIDs (table 4-3) */
/* mandatory */
case OID_802_3_PERMANENT_ADDRESS:
debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__);
if (params->dev) {
length = ETH_ALEN;
memcpy(outbuf, params->host_mac, length);
retval = 0;
}
break;
/* mandatory */
case OID_802_3_CURRENT_ADDRESS:
debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__);
if (params->dev) {
length = ETH_ALEN;
memcpy(outbuf, params->host_mac, length);
retval = 0;
}
break;
/* mandatory */
case OID_802_3_MULTICAST_LIST:
debug("%s: OID_802_3_MULTICAST_LIST\n", __func__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32(0xE0000000);
retval = 0;
break;
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32(1);
retval = 0;
break;
case OID_802_3_MAC_OPTIONS:
debug("%s: OID_802_3_MAC_OPTIONS\n", __func__);
break;
/* ieee802.3 statistics OIDs (table 4-4) */
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
debug("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
if (params->stats) {
*outbuf = cpu_to_le32(params->stats->rx_frame_errors);
retval = 0;
}
break;
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__);
*outbuf = __constant_cpu_to_le32(0);
retval = 0;
break;
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
*outbuf = __constant_cpu_to_le32(0);
retval = 0;
break;
#ifdef RNDIS_OPTIONAL_STATS
case OID_802_3_XMIT_DEFERRED:
debug("%s: OID_802_3_XMIT_DEFERRED\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_MAX_COLLISIONS:
debug("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __func__);
/* TODO */
break;
case OID_802_3_RCV_OVERRUN:
debug("%s: OID_802_3_RCV_OVERRUN\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_UNDERRUN:
debug("%s: OID_802_3_XMIT_UNDERRUN\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
debug("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_TIMES_CRS_LOST:
debug("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_LATE_COLLISIONS:
debug("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __func__);
/* TODO */
break;
#endif /* RNDIS_OPTIONAL_STATS */
#ifdef RNDIS_PM
/* power management OIDs (table 4-5) */
case OID_PNP_CAPABILITIES:
debug("%s: OID_PNP_CAPABILITIES\n", __func__);
/* for now, no wakeup capabilities */
length = sizeof(struct NDIS_PNP_CAPABILITIES);
memset(outbuf, 0, length);
retval = 0;
break;
case OID_PNP_QUERY_POWER:
debug("%s: OID_PNP_QUERY_POWER D%d\n", __func__,
get_unaligned_le32(buf) - 1);
/*
* only suspend is a real power state, and
* it can't be entered by OID_PNP_SET_POWER...
*/
length = 0;
retval = 0;
break;
#endif
default:
debug("%s: query unknown OID 0x%08X\n", __func__, OID);
}
if (retval < 0)
length = 0;
resp->InformationBufferLength = cpu_to_le32(length);
r->length = length + sizeof *resp;
resp->MessageLength = cpu_to_le32(r->length);
return retval;
}