📄 rndis.c
字号:
case OID_GEN_DIRECTED_BYTES_RCV:
DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast * 1111);
retval = 0;
}
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
retval = 0;
}
break;
case OID_GEN_BROADCAST_BYTES_RCV:
DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42*255);
retval = 0;
}
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42);
retval = 0;
}
break;
case OID_GEN_RCV_CRC_ERROR:
DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_crc_errors);
retval = 0;
}
break;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
*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", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
rndis_per_dev_params [configNr].host_mac,
length);
retval = 0;
}
break;
/* mandatory */
case OID_802_3_CURRENT_ADDRESS:
DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
rndis_per_dev_params [configNr].host_mac,
length);
retval = 0;
}
break;
/* mandatory */
case OID_802_3_MULTICAST_LIST:
DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
/* 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", __FUNCTION__);
/* 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", __FUNCTION__);
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", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_frame_errors);
retval = 0;
}
break;
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
*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", __FUNCTION__);
*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", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_MAX_COLLISIONS:
DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_RCV_OVERRUN:
DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_UNDERRUN:
DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_TIMES_CRS_LOST:
DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_LATE_COLLISIONS:
DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
/* 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", __FUNCTION__);
/* 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", __FUNCTION__,
le32_to_cpup((__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:
printk (KERN_WARNING "%s: query unknown OID 0x%08X\n",
__FUNCTION__, 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;
}
static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
rndis_resp_t *r)
{
rndis_set_cmplt_type *resp;
int i, retval = -ENOTSUPP;
struct rndis_params *params;
if (!r)
return -ENOMEM;
resp = (rndis_set_cmplt_type *) r->buf;
if (!resp)
return -ENOMEM;
if (buf_len && rndis_debug > 1) {
DEBUG("set 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,
le32_to_cpup((__le32 *)&buf[i]),
le32_to_cpup((__le32 *)&buf[i + 4]),
le32_to_cpup((__le32 *)&buf[i + 8]),
le32_to_cpup((__le32 *)&buf[i + 12]));
}
}
params = &rndis_per_dev_params [configNr];
switch (OID) {
case 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) le32_to_cpup((__le32 *)buf);
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__FUNCTION__, *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.
*/
#ifdef RNDIS_PM
update_linkstate:
#endif
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 OID_802_3_MULTICAST_LIST:
/* I think we can ignore this */
DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
retval = 0;
break;
#if 0
case OID_GEN_RNDIS_CONFIG_PARAMETER:
{
struct rndis_config_parameter *param;
param = (struct rndis_config_parameter *) buf;
DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
__FUNCTION__,
min(cpu_to_le32(param->ParameterNameLength),80),
buf + param->ParameterNameOffset);
retval = 0;
}
break;
#endif
#ifdef RNDIS_PM
case OID_PNP_SET_POWER:
/* The only real power state is USB suspend, and RNDIS requests
* can't enter it; this one isn't really about power. After
* resuming, Windows forces a reset, and then SET_POWER D0.
* FIXME ... then things go batty; Windows wedges itself.
*/
i = le32_to_cpup((__force __le32 *)buf);
DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
switch (i) {
case NdisDeviceStateD0:
*params->filter = params->saved_filter;
goto update_linkstate;
case NdisDeviceStateD3:
case NdisDeviceStateD2:
case NdisDeviceStateD1:
params->saved_filter = *params->filter;
retval = 0;
break;
}
break;
#ifdef RNDIS_WAKEUP
// no wakeup support advertised, so wakeup OIDs always fail:
// - OID_PNP_ENABLE_WAKE_UP
// - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
#endif
#endif /* RNDIS_PM */
default:
printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n",
__FUNCTION__, OID, buf_len);
}
return retval;
}
/*
* Response Functions
*/
static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
{
rndis_init_cmplt_type *resp;
rndis_resp_t *r;
if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
if (!r)
return -ENOMEM;
resp = (rndis_init_cmplt_type *) r->buf;
resp->MessageType = __constant_cpu_to_le32 (
REMOTE_NDIS_INITIALIZE_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (52);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
resp->MajorVersion = __constant_cpu_to_le32 (RNDIS_MAJOR_VERSION);
resp->MinorVersion = __constant_cpu_to_le32 (RNDIS_MINOR_VERSION);
resp->DeviceFlags = __constant_cpu_to_le32 (RNDIS_DF_CONNECTIONLESS);
resp->Medium = __constant_cpu_to_le32 (RNDIS_MEDIUM_802_3);
resp->MaxPacketsPerTransfer = __constant_cpu_to_le32 (1);
resp->MaxTransferSize = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu
+ sizeof (struct ethhdr)
+ sizeof (struct rndis_packet_msg_type)
+ 22);
resp->PacketAlignmentFactor = __constant_cpu_to_le32 (0);
resp->AFListOffset = __constant_cpu_to_le32 (0);
resp->AFListSize = __constant_cpu_to_le32 (0);
if (rndis_per_dev_params [configNr].ack)
rndis_per_dev_params [configNr].ack (
rndis_per_dev_params [configNr].dev);
return 0;
}
static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
{
rndis_query_cmplt_type *resp;
rndis_resp_t *r;
// DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
/*
* we need more memory:
* oid_supported_list is the largest answer
*/
r = rndis_add_response (configNr, sizeof (oid_supported_list));
if (!r)
return -ENOMEM;
resp = (rndis_query_cmplt_type *) r->buf;
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
le32_to_cpu(buf->InformationBufferOffset)
+ 8 + (u8 *) buf,
le32_to_cpu(buf->InformationBufferLength),
r)) {
/* OID not supported */
resp->Status = __constant_cpu_to_le32 (
RNDIS_STATUS_NOT_SUPPORTED);
resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp);
resp->InformationBufferLength = __constant_cpu_to_le32 (0);
resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
} else
resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
if (rndis_per_dev_params [configNr].ack)
rndis_per_dev_params [configNr].ack (
rndis_per_dev_params [configNr].dev);
return 0;
}
static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
{
u32 BufLength, BufOffset;
rndis_set_cmplt_type *resp;
rndis_resp_t *r;
r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
if (!r)
return -ENOMEM;
resp = (rndis_set_cmplt_type *) r->buf;
BufLength = le32_to_cpu (buf->InformationBufferLength);
BufOffset = le32_to_cpu (buf->InformationBufferOffset);
#ifdef VERBOSE
DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
DEBUG("%s: InfoBuffer: ", __FUNCTION__);
for (i = 0; i < BufLength; i++) {
DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
}
DEBUG ("\n");
#endif
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (16);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
if (gen_ndis_set_resp (configNr, le32_to_cpu (buf->OID),
((u8 *) buf) + 8 + BufOffset, BufLength, r))
resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED);
else resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
if (rndis_per_dev_params [configNr].ack)
rndis_per_dev_params [configNr].ack (
rndis_per_dev_params [configNr].dev);
return 0;
}
static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
{
rndis_reset_cmplt_type *resp;
rndis_resp_t *r;
r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
if (!r)
return -ENOMEM;
resp = (rndis_reset_cmplt_type *) r->buf;
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (16);
resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
/* resent information */
resp->AddressingReset = __constant_cpu_to_le32 (1);
if (rndis_per_dev_params [configNr].ack)
rndis_per_dev_params [configNr].ack (
rndis_per_dev_params [configNr].dev);
return 0;
}
static int rndis_keepalive_response (int configNr,
rndis_keepalive_msg_type *buf)
{
rndis_keepalive_cmplt_type *resp;
rndis_resp_t *r;
/* host "should" check only in RNDIS_DATA_INITIALIZED state */
r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
if (!r)
return -ENOMEM;
resp = (rndis_keepalive_cmplt_type *) r->buf;
resp->MessageType = __constant_cpu_to_le32 (
REMOTE_NDIS_KEEPALIVE_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (16);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -