?? rndis.c
字號:
__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: * 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 (configNr, sizeof (oid_supported_list) + sizeof(rndis_query_cmplt_type)); 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); 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); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ 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;}/* * Device to Host Comunication */static int rndis_indicate_status_msg (int configNr, u32 status){ rndis_indicate_status_msg_type *resp; rndis_resp_t *r; if (rndis_per_dev_params [configNr].state == RNDIS_UNINITIALIZED) return -ENOTSUPP; r = rndis_add_response (configNr, sizeof (rndis_indicate_status_msg_type)); if (!r) return -ENOMEM; resp = (rndis_indicate_status_msg_type *) r->buf; resp->MessageType = __constant_cpu_to_le32 ( REMOTE_NDIS_INDICATE_STATUS_MSG); resp->MessageLength = __constant_cpu_to_le32 (20); resp->Status = cpu_to_le32 (status); resp->StatusBufferLength = __constant_cpu_to_le32 (0); resp->StatusBufferOffset = __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;}int rndis_signal_connect (int configNr){ rndis_per_dev_params [configNr].media_state = NDIS_MEDIA_STATE_CONNECTED; return rndis_indicate_status_msg (configNr, RNDIS_STATUS_MEDIA_CONNECT);}int rndis_signal_disconnect (int configNr){ rndis_per_dev_params [configNr].media_state = NDIS_MEDIA_STATE_DISCONNECTED; return rndis_indicate_status_msg (configNr, RNDIS_STATUS_MEDIA_DISCONNECT);}void rndis_uninit (int configNr){ u8 *buf; u32 length; if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params [configNr].used = 0; rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; /* drain the response queue */ while ((buf = rndis_get_next_response(configNr, &length))) rndis_free_response(configNr, buf);}void rndis_set_host_mac (int configNr, const u8 *addr){ rndis_per_dev_params [configNr].host_mac = addr;}/* * Message Parser */int rndis_msg_parser (u8 configNr, u8 *buf){ u32 MsgType, MsgLength; __le32 *tmp; struct rndis_params *params; if (!buf) return -ENOMEM; tmp = (__le32 *) buf; MsgType = le32_to_cpu(get_unaligned(tmp++)); MsgLength = le32_to_cpu(get_unaligned(tmp++)); if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP; params = &rndis_per_dev_params [configNr]; /* 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 REMOTE_NDIS_INITIALIZE_MSG: DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __FUNCTION__ ); params->state = RNDIS_INITIALIZED; return rndis_init_response (configNr, (rndis_init_msg_type *) buf); case REMOTE_NDIS_HALT_MSG: DEBUG("%s: REMOTE_NDIS_HALT_MSG\n", __FUNCTION__ ); params->state = RNDIS_UNINITIALIZED; if (params->dev) { netif_carrier_off (params->dev); netif_stop_queue (params->dev); } return 0; case REMOTE_NDIS_QUERY_MSG: return rndis_query_response (configNr, (rndis_query_msg_type *) buf); case REMOTE_NDIS_SET_MSG: return rndis_set_response (configNr, (rndis_set_msg_type *) buf); case REMOTE_NDIS_RESET_MSG: DEBUG("%s: REMOTE_NDIS_RESET_MSG\n", __FUNCTION__ ); return rndis_reset_response (configNr, (rndis_reset_msg_type *) buf); case REMOTE_NDIS_KEEPALIVE_MSG: /* For USB: host does this every 5 seconds */ if (rndis_debug > 1) DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", __FUNCTION__ ); return rndis_keepalive_response (configNr, (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. */ printk (KERN_WARNING "%s: unknown RNDIS message 0x%08X len %d\n", __FUNCTION__ , MsgType, MsgLength); { unsigned i; for (i = 0; i < MsgLength; i += 16) { DEBUG ("%03d: " " %02x %02x %02x %02x" " %02x %02x %02x %02x" " %02x %02x %02x %02x" " %02x %02x %02x %02x" "\n", i, buf[i], buf [i+1], buf[i+2], buf[i+3], buf[i+4], buf [i+5], buf[i+6], buf[i+7], buf[i+8], buf [i+9], buf[i+10], buf[i+11], buf[i+12], buf [i+13], buf[i+14], buf[i+15]); } } break; } return -ENOTSUPP;}int rndis_register (int (* rndis_control_ack) (struct net_device *)){ u8 i; for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { if (!rndis_per_dev_params [i].used) { rndis_per_dev_params [i].used = 1; rndis_per_dev_params [i].ack = rndis_control_ack; DEBUG("%s: configNr = %d\n", __FUNCTION__, i); return i; } } DEBUG("failed\n"); return -1;}void rndis_deregister (int configNr){ DEBUG("%s: \n", __FUNCTION__ ); if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params [configNr].used = 0; return;}int rndis_set_param_dev (u8 configNr, struct net_device *dev, struct net_device_stats *stats, u16 *cdc_filter){ DEBUG("%s:\n", __FUNCTION__ ); if (!dev || !stats) return -1; if (configNr >= RNDIS_MAX_CONFIGS) return -1; rndis_per_dev_params [configNr].dev = dev; rndis_per_dev_params [configNr].stats = stats; rndis_per_dev_params [configNr].filter = cdc_filter; return 0;}int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr){ DEBUG("%s:\n", __FUNCTION__ ); if (!vendorDescr) return -1; if (configNr >= RNDIS_MAX_CONFIGS) return -1; rndis_per_dev_params [configNr].vendorID = vendorID; rndis_per_dev_params [configNr].vendorDescr = vendorDescr; return 0;}int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed){ DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed); if (configNr >= RNDIS_MAX_CONFIGS) return -1; rndis_per_dev_params [configNr].medium = medium; rndis_per_dev_params [configNr].speed = speed; return 0;}void rndis_add_hdr (struct sk_buff *skb){ struct rndis_packet_msg_type *header; if (!skb) return; header = (void *) skb_push (skb, sizeof *header); memset (header, 0, sizeof *header); header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG); header->MessageLength = cpu_to_le32(skb->len); header->DataOffset = __constant_cpu_to_le32 (36); header->DataLength = cpu_to_le32(skb->len - sizeof *header);}void rndis_free_response (int configNr, u8 *buf){ rndis_resp_t *r; struct list_head *act, *tmp; list_for_each_safe (act, tmp, &(rndis_per_dev_params [configNr].resp_queue)) { r = list_entry (act, rndis_resp_t, list); if (r && r->buf == buf) { list_del (&r->list); kfree (r); } }}u8 *rndis_get_next_response (int configNr, u32 *length){ rndis_resp_t *r; struct list_head *act, *tmp; if (!length) return NULL; list_for_each_safe (act, tmp, &(rndis_per_dev_params [configNr].resp_queue)) { r = list_entry (act, rndis_resp_t, list); if (!r->send) { r->send = 1; *length = r->length; return r->buf; } } return NULL;}static rndis_resp_t *rndis_add_response (int configNr, u32 length){ rndis_resp_t *r; /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC); if (!r) return NULL; r->buf = (u8 *) (r + 1); r->length = length; r->send = 0; list_add_tail (&r->list, &(rndis_per_dev_params [configNr].resp_queue)); return r;}int rndis_rm_hdr(struct sk_buff *skb){ /* tmp points to a struct rndis_packet_msg_type */ __le32 *tmp = (void *) skb->data; /* MessageType, MessageLength */ if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG) != get_unaligned(tmp++)) return -EINVAL; tmp++; /* DataOffset, DataLength */ if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++)) + 8 /* offset of DataOffset */)) return -EOVERFLOW; skb_trim(skb, le32_to_cpu(get_unaligned(tmp++))); return 0;}int __devinit rndis_init (void){ u8 i; for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { rndis_per_dev_params [i].confignr = i; rndis_per_dev_params [i].used = 0; rndis_per_dev_params [i].state = RNDIS_UNINITIALIZED; rndis_per_dev_params [i].media_state = NDIS_MEDIA_STATE_DISCONNECTED; INIT_LIST_HEAD (&(rndis_per_dev_params [i].resp_queue)); } return 0;}void rndis_exit (void){}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -