195fa0405SHaiyang Zhang /* 295fa0405SHaiyang Zhang * Copyright (c) 2009, Microsoft Corporation. 395fa0405SHaiyang Zhang * 495fa0405SHaiyang Zhang * This program is free software; you can redistribute it and/or modify it 595fa0405SHaiyang Zhang * under the terms and conditions of the GNU General Public License, 695fa0405SHaiyang Zhang * version 2, as published by the Free Software Foundation. 795fa0405SHaiyang Zhang * 895fa0405SHaiyang Zhang * This program is distributed in the hope it will be useful, but WITHOUT 995fa0405SHaiyang Zhang * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1095fa0405SHaiyang Zhang * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1195fa0405SHaiyang Zhang * more details. 1295fa0405SHaiyang Zhang * 1395fa0405SHaiyang Zhang * You should have received a copy of the GNU General Public License along with 1495fa0405SHaiyang Zhang * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 1595fa0405SHaiyang Zhang * Place - Suite 330, Boston, MA 02111-1307 USA. 1695fa0405SHaiyang Zhang * 1795fa0405SHaiyang Zhang * Authors: 1895fa0405SHaiyang Zhang * Haiyang Zhang <haiyangz@microsoft.com> 1995fa0405SHaiyang Zhang * Hank Janssen <hjanssen@microsoft.com> 2095fa0405SHaiyang Zhang */ 2195fa0405SHaiyang Zhang #include <linux/kernel.h> 2295fa0405SHaiyang Zhang #include <linux/sched.h> 2395fa0405SHaiyang Zhang #include <linux/wait.h> 2495fa0405SHaiyang Zhang #include <linux/highmem.h> 2595fa0405SHaiyang Zhang #include <linux/slab.h> 2695fa0405SHaiyang Zhang #include <linux/io.h> 2795fa0405SHaiyang Zhang #include <linux/if_ether.h> 2895fa0405SHaiyang Zhang #include <linux/netdevice.h> 291f5f3a75SHaiyang Zhang #include <linux/if_vlan.h> 301ce09e89SHaiyang Zhang #include <linux/nls.h> 3195fa0405SHaiyang Zhang 3295fa0405SHaiyang Zhang #include "hyperv_net.h" 3395fa0405SHaiyang Zhang 3495fa0405SHaiyang Zhang 35a3a6cab5SHaiyang Zhang #define RNDIS_EXT_LEN 100 3695fa0405SHaiyang Zhang struct rndis_request { 3795fa0405SHaiyang Zhang struct list_head list_ent; 3895fa0405SHaiyang Zhang struct completion wait_event; 3995fa0405SHaiyang Zhang 4095fa0405SHaiyang Zhang struct rndis_message response_msg; 41a3a6cab5SHaiyang Zhang /* 42a3a6cab5SHaiyang Zhang * The buffer for extended info after the RNDIS response message. It's 43a3a6cab5SHaiyang Zhang * referenced based on the data offset in the RNDIS message. Its size 44a3a6cab5SHaiyang Zhang * is enough for current needs, and should be sufficient for the near 45a3a6cab5SHaiyang Zhang * future. 46a3a6cab5SHaiyang Zhang */ 47a3a6cab5SHaiyang Zhang u8 response_ext[RNDIS_EXT_LEN]; 4895fa0405SHaiyang Zhang 4995fa0405SHaiyang Zhang /* Simplify allocation by having a netvsc packet inline */ 5095fa0405SHaiyang Zhang struct hv_netvsc_packet pkt; 5199e3fcfaSHaiyang Zhang /* Set 2 pages for rndis requests crossing page boundary */ 5299e3fcfaSHaiyang Zhang struct hv_page_buffer buf[2]; 530f48917bSHaiyang Zhang 5495fa0405SHaiyang Zhang struct rndis_message request_msg; 550f48917bSHaiyang Zhang /* 56a3a6cab5SHaiyang Zhang * The buffer for the extended info after the RNDIS request message. 57a3a6cab5SHaiyang Zhang * It is referenced and sized in a similar way as response_ext. 580f48917bSHaiyang Zhang */ 59a3a6cab5SHaiyang Zhang u8 request_ext[RNDIS_EXT_LEN]; 6095fa0405SHaiyang Zhang }; 6195fa0405SHaiyang Zhang 6295fa0405SHaiyang Zhang static void rndis_filter_send_completion(void *ctx); 6395fa0405SHaiyang Zhang 6495fa0405SHaiyang Zhang static void rndis_filter_send_request_completion(void *ctx); 6595fa0405SHaiyang Zhang 6695fa0405SHaiyang Zhang 6795fa0405SHaiyang Zhang 6895fa0405SHaiyang Zhang static struct rndis_device *get_rndis_device(void) 6995fa0405SHaiyang Zhang { 7095fa0405SHaiyang Zhang struct rndis_device *device; 7195fa0405SHaiyang Zhang 7295fa0405SHaiyang Zhang device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL); 7395fa0405SHaiyang Zhang if (!device) 7495fa0405SHaiyang Zhang return NULL; 7595fa0405SHaiyang Zhang 7695fa0405SHaiyang Zhang spin_lock_init(&device->request_lock); 7795fa0405SHaiyang Zhang 7895fa0405SHaiyang Zhang INIT_LIST_HEAD(&device->req_list); 7995fa0405SHaiyang Zhang 8095fa0405SHaiyang Zhang device->state = RNDIS_DEV_UNINITIALIZED; 8195fa0405SHaiyang Zhang 8295fa0405SHaiyang Zhang return device; 8395fa0405SHaiyang Zhang } 8495fa0405SHaiyang Zhang 8595fa0405SHaiyang Zhang static struct rndis_request *get_rndis_request(struct rndis_device *dev, 8695fa0405SHaiyang Zhang u32 msg_type, 8795fa0405SHaiyang Zhang u32 msg_len) 8895fa0405SHaiyang Zhang { 8995fa0405SHaiyang Zhang struct rndis_request *request; 9095fa0405SHaiyang Zhang struct rndis_message *rndis_msg; 9195fa0405SHaiyang Zhang struct rndis_set_request *set; 9295fa0405SHaiyang Zhang unsigned long flags; 9395fa0405SHaiyang Zhang 9495fa0405SHaiyang Zhang request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL); 9595fa0405SHaiyang Zhang if (!request) 9695fa0405SHaiyang Zhang return NULL; 9795fa0405SHaiyang Zhang 9895fa0405SHaiyang Zhang init_completion(&request->wait_event); 9995fa0405SHaiyang Zhang 10095fa0405SHaiyang Zhang rndis_msg = &request->request_msg; 10195fa0405SHaiyang Zhang rndis_msg->ndis_msg_type = msg_type; 10295fa0405SHaiyang Zhang rndis_msg->msg_len = msg_len; 10395fa0405SHaiyang Zhang 10495fa0405SHaiyang Zhang /* 10595fa0405SHaiyang Zhang * Set the request id. This field is always after the rndis header for 10695fa0405SHaiyang Zhang * request/response packet types so we just used the SetRequest as a 10795fa0405SHaiyang Zhang * template 10895fa0405SHaiyang Zhang */ 10995fa0405SHaiyang Zhang set = &rndis_msg->msg.set_req; 11095fa0405SHaiyang Zhang set->req_id = atomic_inc_return(&dev->new_req_id); 11195fa0405SHaiyang Zhang 11295fa0405SHaiyang Zhang /* Add to the request list */ 11395fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 11495fa0405SHaiyang Zhang list_add_tail(&request->list_ent, &dev->req_list); 11595fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 11695fa0405SHaiyang Zhang 11795fa0405SHaiyang Zhang return request; 11895fa0405SHaiyang Zhang } 11995fa0405SHaiyang Zhang 12095fa0405SHaiyang Zhang static void put_rndis_request(struct rndis_device *dev, 12195fa0405SHaiyang Zhang struct rndis_request *req) 12295fa0405SHaiyang Zhang { 12395fa0405SHaiyang Zhang unsigned long flags; 12495fa0405SHaiyang Zhang 12595fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 12695fa0405SHaiyang Zhang list_del(&req->list_ent); 12795fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 12895fa0405SHaiyang Zhang 12995fa0405SHaiyang Zhang kfree(req); 13095fa0405SHaiyang Zhang } 13195fa0405SHaiyang Zhang 13295fa0405SHaiyang Zhang static void dump_rndis_message(struct hv_device *hv_dev, 13395fa0405SHaiyang Zhang struct rndis_message *rndis_msg) 13495fa0405SHaiyang Zhang { 13595fa0405SHaiyang Zhang struct net_device *netdev; 13695fa0405SHaiyang Zhang struct netvsc_device *net_device; 13795fa0405SHaiyang Zhang 13895fa0405SHaiyang Zhang net_device = hv_get_drvdata(hv_dev); 13995fa0405SHaiyang Zhang netdev = net_device->ndev; 14095fa0405SHaiyang Zhang 14195fa0405SHaiyang Zhang switch (rndis_msg->ndis_msg_type) { 14251491167SLinus Walleij case RNDIS_MSG_PACKET: 14351491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, " 14495fa0405SHaiyang Zhang "data offset %u data len %u, # oob %u, " 14595fa0405SHaiyang Zhang "oob offset %u, oob len %u, pkt offset %u, " 14695fa0405SHaiyang Zhang "pkt len %u\n", 14795fa0405SHaiyang Zhang rndis_msg->msg_len, 14895fa0405SHaiyang Zhang rndis_msg->msg.pkt.data_offset, 14995fa0405SHaiyang Zhang rndis_msg->msg.pkt.data_len, 15095fa0405SHaiyang Zhang rndis_msg->msg.pkt.num_oob_data_elements, 15195fa0405SHaiyang Zhang rndis_msg->msg.pkt.oob_data_offset, 15295fa0405SHaiyang Zhang rndis_msg->msg.pkt.oob_data_len, 15395fa0405SHaiyang Zhang rndis_msg->msg.pkt.per_pkt_info_offset, 15495fa0405SHaiyang Zhang rndis_msg->msg.pkt.per_pkt_info_len); 15595fa0405SHaiyang Zhang break; 15695fa0405SHaiyang Zhang 15751491167SLinus Walleij case RNDIS_MSG_INIT_C: 15851491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_INIT_C " 15995fa0405SHaiyang Zhang "(len %u, id 0x%x, status 0x%x, major %d, minor %d, " 16095fa0405SHaiyang Zhang "device flags %d, max xfer size 0x%x, max pkts %u, " 16195fa0405SHaiyang Zhang "pkt aligned %u)\n", 16295fa0405SHaiyang Zhang rndis_msg->msg_len, 16395fa0405SHaiyang Zhang rndis_msg->msg.init_complete.req_id, 16495fa0405SHaiyang Zhang rndis_msg->msg.init_complete.status, 16595fa0405SHaiyang Zhang rndis_msg->msg.init_complete.major_ver, 16695fa0405SHaiyang Zhang rndis_msg->msg.init_complete.minor_ver, 16795fa0405SHaiyang Zhang rndis_msg->msg.init_complete.dev_flags, 16895fa0405SHaiyang Zhang rndis_msg->msg.init_complete.max_xfer_size, 16995fa0405SHaiyang Zhang rndis_msg->msg.init_complete. 17095fa0405SHaiyang Zhang max_pkt_per_msg, 17195fa0405SHaiyang Zhang rndis_msg->msg.init_complete. 17295fa0405SHaiyang Zhang pkt_alignment_factor); 17395fa0405SHaiyang Zhang break; 17495fa0405SHaiyang Zhang 17551491167SLinus Walleij case RNDIS_MSG_QUERY_C: 17651491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_QUERY_C " 17795fa0405SHaiyang Zhang "(len %u, id 0x%x, status 0x%x, buf len %u, " 17895fa0405SHaiyang Zhang "buf offset %u)\n", 17995fa0405SHaiyang Zhang rndis_msg->msg_len, 18095fa0405SHaiyang Zhang rndis_msg->msg.query_complete.req_id, 18195fa0405SHaiyang Zhang rndis_msg->msg.query_complete.status, 18295fa0405SHaiyang Zhang rndis_msg->msg.query_complete. 18395fa0405SHaiyang Zhang info_buflen, 18495fa0405SHaiyang Zhang rndis_msg->msg.query_complete. 18595fa0405SHaiyang Zhang info_buf_offset); 18695fa0405SHaiyang Zhang break; 18795fa0405SHaiyang Zhang 18851491167SLinus Walleij case RNDIS_MSG_SET_C: 18995fa0405SHaiyang Zhang netdev_dbg(netdev, 19051491167SLinus Walleij "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n", 19195fa0405SHaiyang Zhang rndis_msg->msg_len, 19295fa0405SHaiyang Zhang rndis_msg->msg.set_complete.req_id, 19395fa0405SHaiyang Zhang rndis_msg->msg.set_complete.status); 19495fa0405SHaiyang Zhang break; 19595fa0405SHaiyang Zhang 19651491167SLinus Walleij case RNDIS_MSG_INDICATE: 19751491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_INDICATE " 19895fa0405SHaiyang Zhang "(len %u, status 0x%x, buf len %u, buf offset %u)\n", 19995fa0405SHaiyang Zhang rndis_msg->msg_len, 20095fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status, 20195fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status_buflen, 20295fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status_buf_offset); 20395fa0405SHaiyang Zhang break; 20495fa0405SHaiyang Zhang 20595fa0405SHaiyang Zhang default: 20695fa0405SHaiyang Zhang netdev_dbg(netdev, "0x%x (len %u)\n", 20795fa0405SHaiyang Zhang rndis_msg->ndis_msg_type, 20895fa0405SHaiyang Zhang rndis_msg->msg_len); 20995fa0405SHaiyang Zhang break; 21095fa0405SHaiyang Zhang } 21195fa0405SHaiyang Zhang } 21295fa0405SHaiyang Zhang 21395fa0405SHaiyang Zhang static int rndis_filter_send_request(struct rndis_device *dev, 21495fa0405SHaiyang Zhang struct rndis_request *req) 21595fa0405SHaiyang Zhang { 21695fa0405SHaiyang Zhang int ret; 21795fa0405SHaiyang Zhang struct hv_netvsc_packet *packet; 21895fa0405SHaiyang Zhang 21995fa0405SHaiyang Zhang /* Setup the packet to send it */ 22095fa0405SHaiyang Zhang packet = &req->pkt; 22195fa0405SHaiyang Zhang 22295fa0405SHaiyang Zhang packet->is_data_pkt = false; 22395fa0405SHaiyang Zhang packet->total_data_buflen = req->request_msg.msg_len; 22495fa0405SHaiyang Zhang packet->page_buf_cnt = 1; 22595fa0405SHaiyang Zhang 22695fa0405SHaiyang Zhang packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >> 22795fa0405SHaiyang Zhang PAGE_SHIFT; 22895fa0405SHaiyang Zhang packet->page_buf[0].len = req->request_msg.msg_len; 22995fa0405SHaiyang Zhang packet->page_buf[0].offset = 23095fa0405SHaiyang Zhang (unsigned long)&req->request_msg & (PAGE_SIZE - 1); 23195fa0405SHaiyang Zhang 23299e3fcfaSHaiyang Zhang /* Add one page_buf when request_msg crossing page boundary */ 23399e3fcfaSHaiyang Zhang if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) { 23499e3fcfaSHaiyang Zhang packet->page_buf_cnt++; 23599e3fcfaSHaiyang Zhang packet->page_buf[0].len = PAGE_SIZE - 23699e3fcfaSHaiyang Zhang packet->page_buf[0].offset; 23799e3fcfaSHaiyang Zhang packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg 23899e3fcfaSHaiyang Zhang + packet->page_buf[0].len) >> PAGE_SHIFT; 23999e3fcfaSHaiyang Zhang packet->page_buf[1].offset = 0; 24099e3fcfaSHaiyang Zhang packet->page_buf[1].len = req->request_msg.msg_len - 24199e3fcfaSHaiyang Zhang packet->page_buf[0].len; 24299e3fcfaSHaiyang Zhang } 24399e3fcfaSHaiyang Zhang 24495fa0405SHaiyang Zhang packet->completion.send.send_completion_ctx = req;/* packet; */ 24595fa0405SHaiyang Zhang packet->completion.send.send_completion = 24695fa0405SHaiyang Zhang rndis_filter_send_request_completion; 24795fa0405SHaiyang Zhang packet->completion.send.send_completion_tid = (unsigned long)dev; 24895fa0405SHaiyang Zhang 24995fa0405SHaiyang Zhang ret = netvsc_send(dev->net_dev->dev, packet); 25095fa0405SHaiyang Zhang return ret; 25195fa0405SHaiyang Zhang } 25295fa0405SHaiyang Zhang 25395fa0405SHaiyang Zhang static void rndis_filter_receive_response(struct rndis_device *dev, 25495fa0405SHaiyang Zhang struct rndis_message *resp) 25595fa0405SHaiyang Zhang { 25695fa0405SHaiyang Zhang struct rndis_request *request = NULL; 25795fa0405SHaiyang Zhang bool found = false; 25895fa0405SHaiyang Zhang unsigned long flags; 25995fa0405SHaiyang Zhang struct net_device *ndev; 26095fa0405SHaiyang Zhang 26195fa0405SHaiyang Zhang ndev = dev->net_dev->ndev; 26295fa0405SHaiyang Zhang 26395fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 26495fa0405SHaiyang Zhang list_for_each_entry(request, &dev->req_list, list_ent) { 26595fa0405SHaiyang Zhang /* 26695fa0405SHaiyang Zhang * All request/response message contains RequestId as the 1st 26795fa0405SHaiyang Zhang * field 26895fa0405SHaiyang Zhang */ 26995fa0405SHaiyang Zhang if (request->request_msg.msg.init_req.req_id 27095fa0405SHaiyang Zhang == resp->msg.init_complete.req_id) { 27195fa0405SHaiyang Zhang found = true; 27295fa0405SHaiyang Zhang break; 27395fa0405SHaiyang Zhang } 27495fa0405SHaiyang Zhang } 27595fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 27695fa0405SHaiyang Zhang 27795fa0405SHaiyang Zhang if (found) { 278a3a6cab5SHaiyang Zhang if (resp->msg_len <= 279a3a6cab5SHaiyang Zhang sizeof(struct rndis_message) + RNDIS_EXT_LEN) { 28095fa0405SHaiyang Zhang memcpy(&request->response_msg, resp, 28195fa0405SHaiyang Zhang resp->msg_len); 28295fa0405SHaiyang Zhang } else { 28395fa0405SHaiyang Zhang netdev_err(ndev, 28495fa0405SHaiyang Zhang "rndis response buffer overflow " 28595fa0405SHaiyang Zhang "detected (size %u max %zu)\n", 28695fa0405SHaiyang Zhang resp->msg_len, 28795fa0405SHaiyang Zhang sizeof(struct rndis_filter_packet)); 28895fa0405SHaiyang Zhang 28995fa0405SHaiyang Zhang if (resp->ndis_msg_type == 29051491167SLinus Walleij RNDIS_MSG_RESET_C) { 29195fa0405SHaiyang Zhang /* does not have a request id field */ 29295fa0405SHaiyang Zhang request->response_msg.msg.reset_complete. 293007e5c8eSLinus Walleij status = RNDIS_STATUS_BUFFER_OVERFLOW; 29495fa0405SHaiyang Zhang } else { 29595fa0405SHaiyang Zhang request->response_msg.msg. 29695fa0405SHaiyang Zhang init_complete.status = 297007e5c8eSLinus Walleij RNDIS_STATUS_BUFFER_OVERFLOW; 29895fa0405SHaiyang Zhang } 29995fa0405SHaiyang Zhang } 30095fa0405SHaiyang Zhang 30195fa0405SHaiyang Zhang complete(&request->wait_event); 30295fa0405SHaiyang Zhang } else { 30395fa0405SHaiyang Zhang netdev_err(ndev, 30495fa0405SHaiyang Zhang "no rndis request found for this response " 30595fa0405SHaiyang Zhang "(id 0x%x res type 0x%x)\n", 30695fa0405SHaiyang Zhang resp->msg.init_complete.req_id, 30795fa0405SHaiyang Zhang resp->ndis_msg_type); 30895fa0405SHaiyang Zhang } 30995fa0405SHaiyang Zhang } 31095fa0405SHaiyang Zhang 31195fa0405SHaiyang Zhang static void rndis_filter_receive_indicate_status(struct rndis_device *dev, 31295fa0405SHaiyang Zhang struct rndis_message *resp) 31395fa0405SHaiyang Zhang { 31495fa0405SHaiyang Zhang struct rndis_indicate_status *indicate = 31595fa0405SHaiyang Zhang &resp->msg.indicate_status; 31695fa0405SHaiyang Zhang 31795fa0405SHaiyang Zhang if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) { 31895fa0405SHaiyang Zhang netvsc_linkstatus_callback( 31995fa0405SHaiyang Zhang dev->net_dev->dev, 1); 32095fa0405SHaiyang Zhang } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) { 32195fa0405SHaiyang Zhang netvsc_linkstatus_callback( 32295fa0405SHaiyang Zhang dev->net_dev->dev, 0); 32395fa0405SHaiyang Zhang } else { 32495fa0405SHaiyang Zhang /* 32595fa0405SHaiyang Zhang * TODO: 32695fa0405SHaiyang Zhang */ 32795fa0405SHaiyang Zhang } 32895fa0405SHaiyang Zhang } 32995fa0405SHaiyang Zhang 3301f5f3a75SHaiyang Zhang /* 3311f5f3a75SHaiyang Zhang * Get the Per-Packet-Info with the specified type 3321f5f3a75SHaiyang Zhang * return NULL if not found. 3331f5f3a75SHaiyang Zhang */ 3341f5f3a75SHaiyang Zhang static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type) 3351f5f3a75SHaiyang Zhang { 3361f5f3a75SHaiyang Zhang struct rndis_per_packet_info *ppi; 3371f5f3a75SHaiyang Zhang int len; 3381f5f3a75SHaiyang Zhang 3391f5f3a75SHaiyang Zhang if (rpkt->per_pkt_info_offset == 0) 3401f5f3a75SHaiyang Zhang return NULL; 3411f5f3a75SHaiyang Zhang 3421f5f3a75SHaiyang Zhang ppi = (struct rndis_per_packet_info *)((ulong)rpkt + 3431f5f3a75SHaiyang Zhang rpkt->per_pkt_info_offset); 3441f5f3a75SHaiyang Zhang len = rpkt->per_pkt_info_len; 3451f5f3a75SHaiyang Zhang 3461f5f3a75SHaiyang Zhang while (len > 0) { 3471f5f3a75SHaiyang Zhang if (ppi->type == type) 3481f5f3a75SHaiyang Zhang return (void *)((ulong)ppi + ppi->ppi_offset); 3491f5f3a75SHaiyang Zhang len -= ppi->size; 3501f5f3a75SHaiyang Zhang ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size); 3511f5f3a75SHaiyang Zhang } 3521f5f3a75SHaiyang Zhang 3531f5f3a75SHaiyang Zhang return NULL; 3541f5f3a75SHaiyang Zhang } 3551f5f3a75SHaiyang Zhang 35695fa0405SHaiyang Zhang static void rndis_filter_receive_data(struct rndis_device *dev, 35795fa0405SHaiyang Zhang struct rndis_message *msg, 35895fa0405SHaiyang Zhang struct hv_netvsc_packet *pkt) 35995fa0405SHaiyang Zhang { 36095fa0405SHaiyang Zhang struct rndis_packet *rndis_pkt; 36195fa0405SHaiyang Zhang u32 data_offset; 3621f5f3a75SHaiyang Zhang struct ndis_pkt_8021q_info *vlan; 36395fa0405SHaiyang Zhang 36495fa0405SHaiyang Zhang rndis_pkt = &msg->msg.pkt; 36595fa0405SHaiyang Zhang 36695fa0405SHaiyang Zhang /* 36795fa0405SHaiyang Zhang * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this 36895fa0405SHaiyang Zhang * netvsc packet (ie TotalDataBufferLength != MessageLength) 36995fa0405SHaiyang Zhang */ 37095fa0405SHaiyang Zhang 37195fa0405SHaiyang Zhang /* Remove the rndis header and pass it back up the stack */ 37295fa0405SHaiyang Zhang data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset; 37395fa0405SHaiyang Zhang 37495fa0405SHaiyang Zhang pkt->total_data_buflen -= data_offset; 3754b8a8bc9SWei Yongjun 3764b8a8bc9SWei Yongjun /* 3774b8a8bc9SWei Yongjun * Make sure we got a valid RNDIS message, now total_data_buflen 3784b8a8bc9SWei Yongjun * should be the data packet size plus the trailer padding size 3794b8a8bc9SWei Yongjun */ 3804b8a8bc9SWei Yongjun if (pkt->total_data_buflen < rndis_pkt->data_len) { 3814b8a8bc9SWei Yongjun netdev_err(dev->net_dev->ndev, "rndis message buffer " 3824b8a8bc9SWei Yongjun "overflow detected (got %u, min %u)" 3834b8a8bc9SWei Yongjun "...dropping this message!\n", 3844b8a8bc9SWei Yongjun pkt->total_data_buflen, rndis_pkt->data_len); 3854b8a8bc9SWei Yongjun return; 3864b8a8bc9SWei Yongjun } 3874b8a8bc9SWei Yongjun 3884b8a8bc9SWei Yongjun /* 3894b8a8bc9SWei Yongjun * Remove the rndis trailer padding from rndis packet message 3904b8a8bc9SWei Yongjun * rndis_pkt->data_len tell us the real data length, we only copy 3914b8a8bc9SWei Yongjun * the data packet to the stack, without the rndis trailer padding 3924b8a8bc9SWei Yongjun */ 3934b8a8bc9SWei Yongjun pkt->total_data_buflen = rndis_pkt->data_len; 39445326342SHaiyang Zhang pkt->data = (void *)((unsigned long)pkt->data + data_offset); 39595fa0405SHaiyang Zhang 39695fa0405SHaiyang Zhang pkt->is_data_pkt = true; 39795fa0405SHaiyang Zhang 3981f5f3a75SHaiyang Zhang vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO); 3991f5f3a75SHaiyang Zhang if (vlan) { 4001f5f3a75SHaiyang Zhang pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid | 4011f5f3a75SHaiyang Zhang (vlan->pri << VLAN_PRIO_SHIFT); 4021f5f3a75SHaiyang Zhang } else { 4031f5f3a75SHaiyang Zhang pkt->vlan_tci = 0; 4041f5f3a75SHaiyang Zhang } 4051f5f3a75SHaiyang Zhang 40695fa0405SHaiyang Zhang netvsc_recv_callback(dev->net_dev->dev, pkt); 40795fa0405SHaiyang Zhang } 40895fa0405SHaiyang Zhang 40995fa0405SHaiyang Zhang int rndis_filter_receive(struct hv_device *dev, 41095fa0405SHaiyang Zhang struct hv_netvsc_packet *pkt) 41195fa0405SHaiyang Zhang { 41295fa0405SHaiyang Zhang struct netvsc_device *net_dev = hv_get_drvdata(dev); 41395fa0405SHaiyang Zhang struct rndis_device *rndis_dev; 414ef31bef6SHaiyang Zhang struct rndis_message *rndis_msg; 41595fa0405SHaiyang Zhang struct net_device *ndev; 41663f6921dSHaiyang Zhang int ret = 0; 41795fa0405SHaiyang Zhang 41863f6921dSHaiyang Zhang if (!net_dev) { 41963f6921dSHaiyang Zhang ret = -EINVAL; 42063f6921dSHaiyang Zhang goto exit; 42163f6921dSHaiyang Zhang } 42295fa0405SHaiyang Zhang 42395fa0405SHaiyang Zhang ndev = net_dev->ndev; 42495fa0405SHaiyang Zhang 42595fa0405SHaiyang Zhang /* Make sure the rndis device state is initialized */ 42695fa0405SHaiyang Zhang if (!net_dev->extension) { 42795fa0405SHaiyang Zhang netdev_err(ndev, "got rndis message but no rndis device - " 42895fa0405SHaiyang Zhang "dropping this message!\n"); 42963f6921dSHaiyang Zhang ret = -ENODEV; 43063f6921dSHaiyang Zhang goto exit; 43195fa0405SHaiyang Zhang } 43295fa0405SHaiyang Zhang 43395fa0405SHaiyang Zhang rndis_dev = (struct rndis_device *)net_dev->extension; 43495fa0405SHaiyang Zhang if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { 43595fa0405SHaiyang Zhang netdev_err(ndev, "got rndis message but rndis device " 43695fa0405SHaiyang Zhang "uninitialized...dropping this message!\n"); 43763f6921dSHaiyang Zhang ret = -ENODEV; 43863f6921dSHaiyang Zhang goto exit; 43995fa0405SHaiyang Zhang } 44095fa0405SHaiyang Zhang 441ef31bef6SHaiyang Zhang rndis_msg = pkt->data; 44295fa0405SHaiyang Zhang 443ef31bef6SHaiyang Zhang dump_rndis_message(dev, rndis_msg); 44495fa0405SHaiyang Zhang 445ef31bef6SHaiyang Zhang switch (rndis_msg->ndis_msg_type) { 44651491167SLinus Walleij case RNDIS_MSG_PACKET: 44795fa0405SHaiyang Zhang /* data msg */ 448ef31bef6SHaiyang Zhang rndis_filter_receive_data(rndis_dev, rndis_msg, pkt); 44995fa0405SHaiyang Zhang break; 45095fa0405SHaiyang Zhang 45151491167SLinus Walleij case RNDIS_MSG_INIT_C: 45251491167SLinus Walleij case RNDIS_MSG_QUERY_C: 45351491167SLinus Walleij case RNDIS_MSG_SET_C: 45495fa0405SHaiyang Zhang /* completion msgs */ 455ef31bef6SHaiyang Zhang rndis_filter_receive_response(rndis_dev, rndis_msg); 45695fa0405SHaiyang Zhang break; 45795fa0405SHaiyang Zhang 45851491167SLinus Walleij case RNDIS_MSG_INDICATE: 45995fa0405SHaiyang Zhang /* notification msgs */ 460ef31bef6SHaiyang Zhang rndis_filter_receive_indicate_status(rndis_dev, rndis_msg); 46195fa0405SHaiyang Zhang break; 46295fa0405SHaiyang Zhang default: 46395fa0405SHaiyang Zhang netdev_err(ndev, 46495fa0405SHaiyang Zhang "unhandled rndis message (type %u len %u)\n", 465ef31bef6SHaiyang Zhang rndis_msg->ndis_msg_type, 466ef31bef6SHaiyang Zhang rndis_msg->msg_len); 46795fa0405SHaiyang Zhang break; 46895fa0405SHaiyang Zhang } 46995fa0405SHaiyang Zhang 47063f6921dSHaiyang Zhang exit: 47163f6921dSHaiyang Zhang if (ret != 0) 47263f6921dSHaiyang Zhang pkt->status = NVSP_STAT_FAIL; 47363f6921dSHaiyang Zhang 47463f6921dSHaiyang Zhang return ret; 47595fa0405SHaiyang Zhang } 47695fa0405SHaiyang Zhang 47795fa0405SHaiyang Zhang static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, 47895fa0405SHaiyang Zhang void *result, u32 *result_size) 47995fa0405SHaiyang Zhang { 48095fa0405SHaiyang Zhang struct rndis_request *request; 48195fa0405SHaiyang Zhang u32 inresult_size = *result_size; 48295fa0405SHaiyang Zhang struct rndis_query_request *query; 48395fa0405SHaiyang Zhang struct rndis_query_complete *query_complete; 48495fa0405SHaiyang Zhang int ret = 0; 48595fa0405SHaiyang Zhang int t; 48695fa0405SHaiyang Zhang 48795fa0405SHaiyang Zhang if (!result) 48895fa0405SHaiyang Zhang return -EINVAL; 48995fa0405SHaiyang Zhang 49095fa0405SHaiyang Zhang *result_size = 0; 49151491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_QUERY, 49295fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_query_request)); 49395fa0405SHaiyang Zhang if (!request) { 49495fa0405SHaiyang Zhang ret = -ENOMEM; 49595fa0405SHaiyang Zhang goto cleanup; 49695fa0405SHaiyang Zhang } 49795fa0405SHaiyang Zhang 49895fa0405SHaiyang Zhang /* Setup the rndis query */ 49995fa0405SHaiyang Zhang query = &request->request_msg.msg.query_req; 50095fa0405SHaiyang Zhang query->oid = oid; 50195fa0405SHaiyang Zhang query->info_buf_offset = sizeof(struct rndis_query_request); 50295fa0405SHaiyang Zhang query->info_buflen = 0; 50395fa0405SHaiyang Zhang query->dev_vc_handle = 0; 50495fa0405SHaiyang Zhang 50595fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 50695fa0405SHaiyang Zhang if (ret != 0) 50795fa0405SHaiyang Zhang goto cleanup; 50895fa0405SHaiyang Zhang 50995fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 51095fa0405SHaiyang Zhang if (t == 0) { 51195fa0405SHaiyang Zhang ret = -ETIMEDOUT; 51295fa0405SHaiyang Zhang goto cleanup; 51395fa0405SHaiyang Zhang } 51495fa0405SHaiyang Zhang 51595fa0405SHaiyang Zhang /* Copy the response back */ 51695fa0405SHaiyang Zhang query_complete = &request->response_msg.msg.query_complete; 51795fa0405SHaiyang Zhang 51895fa0405SHaiyang Zhang if (query_complete->info_buflen > inresult_size) { 51995fa0405SHaiyang Zhang ret = -1; 52095fa0405SHaiyang Zhang goto cleanup; 52195fa0405SHaiyang Zhang } 52295fa0405SHaiyang Zhang 52395fa0405SHaiyang Zhang memcpy(result, 52495fa0405SHaiyang Zhang (void *)((unsigned long)query_complete + 52595fa0405SHaiyang Zhang query_complete->info_buf_offset), 52695fa0405SHaiyang Zhang query_complete->info_buflen); 52795fa0405SHaiyang Zhang 52895fa0405SHaiyang Zhang *result_size = query_complete->info_buflen; 52995fa0405SHaiyang Zhang 53095fa0405SHaiyang Zhang cleanup: 53195fa0405SHaiyang Zhang if (request) 53295fa0405SHaiyang Zhang put_rndis_request(dev, request); 53395fa0405SHaiyang Zhang 53495fa0405SHaiyang Zhang return ret; 53595fa0405SHaiyang Zhang } 53695fa0405SHaiyang Zhang 53795fa0405SHaiyang Zhang static int rndis_filter_query_device_mac(struct rndis_device *dev) 53895fa0405SHaiyang Zhang { 53995fa0405SHaiyang Zhang u32 size = ETH_ALEN; 54095fa0405SHaiyang Zhang 54195fa0405SHaiyang Zhang return rndis_filter_query_device(dev, 54295fa0405SHaiyang Zhang RNDIS_OID_802_3_PERMANENT_ADDRESS, 54395fa0405SHaiyang Zhang dev->hw_mac_adr, &size); 54495fa0405SHaiyang Zhang } 54595fa0405SHaiyang Zhang 5461ce09e89SHaiyang Zhang #define NWADR_STR "NetworkAddress" 5471ce09e89SHaiyang Zhang #define NWADR_STRLEN 14 5481ce09e89SHaiyang Zhang 5491ce09e89SHaiyang Zhang int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac) 5501ce09e89SHaiyang Zhang { 5511ce09e89SHaiyang Zhang struct netvsc_device *nvdev = hv_get_drvdata(hdev); 5521ce09e89SHaiyang Zhang struct rndis_device *rdev = nvdev->extension; 5531ce09e89SHaiyang Zhang struct net_device *ndev = nvdev->ndev; 5541ce09e89SHaiyang Zhang struct rndis_request *request; 5551ce09e89SHaiyang Zhang struct rndis_set_request *set; 5561ce09e89SHaiyang Zhang struct rndis_config_parameter_info *cpi; 5571ce09e89SHaiyang Zhang wchar_t *cfg_nwadr, *cfg_mac; 5581ce09e89SHaiyang Zhang struct rndis_set_complete *set_complete; 5591ce09e89SHaiyang Zhang char macstr[2*ETH_ALEN+1]; 5601ce09e89SHaiyang Zhang u32 extlen = sizeof(struct rndis_config_parameter_info) + 5611ce09e89SHaiyang Zhang 2*NWADR_STRLEN + 4*ETH_ALEN; 5621ce09e89SHaiyang Zhang int ret, t; 5631ce09e89SHaiyang Zhang 5641ce09e89SHaiyang Zhang request = get_rndis_request(rdev, RNDIS_MSG_SET, 5651ce09e89SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); 5661ce09e89SHaiyang Zhang if (!request) 5671ce09e89SHaiyang Zhang return -ENOMEM; 5681ce09e89SHaiyang Zhang 5691ce09e89SHaiyang Zhang set = &request->request_msg.msg.set_req; 5701ce09e89SHaiyang Zhang set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER; 5711ce09e89SHaiyang Zhang set->info_buflen = extlen; 5721ce09e89SHaiyang Zhang set->info_buf_offset = sizeof(struct rndis_set_request); 5731ce09e89SHaiyang Zhang set->dev_vc_handle = 0; 5741ce09e89SHaiyang Zhang 5751ce09e89SHaiyang Zhang cpi = (struct rndis_config_parameter_info *)((ulong)set + 5761ce09e89SHaiyang Zhang set->info_buf_offset); 5771ce09e89SHaiyang Zhang cpi->parameter_name_offset = 5781ce09e89SHaiyang Zhang sizeof(struct rndis_config_parameter_info); 5791ce09e89SHaiyang Zhang /* Multiply by 2 because host needs 2 bytes (utf16) for each char */ 5801ce09e89SHaiyang Zhang cpi->parameter_name_length = 2*NWADR_STRLEN; 5811ce09e89SHaiyang Zhang cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING; 5821ce09e89SHaiyang Zhang cpi->parameter_value_offset = 5831ce09e89SHaiyang Zhang cpi->parameter_name_offset + cpi->parameter_name_length; 5841ce09e89SHaiyang Zhang /* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */ 5851ce09e89SHaiyang Zhang cpi->parameter_value_length = 4*ETH_ALEN; 5861ce09e89SHaiyang Zhang 5871ce09e89SHaiyang Zhang cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset); 5881ce09e89SHaiyang Zhang cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset); 5891ce09e89SHaiyang Zhang ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN, 5901ce09e89SHaiyang Zhang cfg_nwadr, NWADR_STRLEN); 5911ce09e89SHaiyang Zhang if (ret < 0) 5921ce09e89SHaiyang Zhang goto cleanup; 5931ce09e89SHaiyang Zhang snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac); 5941ce09e89SHaiyang Zhang ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN, 5951ce09e89SHaiyang Zhang cfg_mac, 2*ETH_ALEN); 5961ce09e89SHaiyang Zhang if (ret < 0) 5971ce09e89SHaiyang Zhang goto cleanup; 5981ce09e89SHaiyang Zhang 5991ce09e89SHaiyang Zhang ret = rndis_filter_send_request(rdev, request); 6001ce09e89SHaiyang Zhang if (ret != 0) 6011ce09e89SHaiyang Zhang goto cleanup; 6021ce09e89SHaiyang Zhang 6031ce09e89SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 6041ce09e89SHaiyang Zhang if (t == 0) { 6051ce09e89SHaiyang Zhang netdev_err(ndev, "timeout before we got a set response...\n"); 6061ce09e89SHaiyang Zhang /* 6071ce09e89SHaiyang Zhang * can't put_rndis_request, since we may still receive a 6081ce09e89SHaiyang Zhang * send-completion. 6091ce09e89SHaiyang Zhang */ 6101ce09e89SHaiyang Zhang return -EBUSY; 6111ce09e89SHaiyang Zhang } else { 6121ce09e89SHaiyang Zhang set_complete = &request->response_msg.msg.set_complete; 6131ce09e89SHaiyang Zhang if (set_complete->status != RNDIS_STATUS_SUCCESS) 6141ce09e89SHaiyang Zhang ret = -EINVAL; 6151ce09e89SHaiyang Zhang } 6161ce09e89SHaiyang Zhang 6171ce09e89SHaiyang Zhang cleanup: 6181ce09e89SHaiyang Zhang put_rndis_request(rdev, request); 6191ce09e89SHaiyang Zhang return ret; 6201ce09e89SHaiyang Zhang } 6211ce09e89SHaiyang Zhang 6221ce09e89SHaiyang Zhang 62395fa0405SHaiyang Zhang static int rndis_filter_query_device_link_status(struct rndis_device *dev) 62495fa0405SHaiyang Zhang { 62595fa0405SHaiyang Zhang u32 size = sizeof(u32); 62695fa0405SHaiyang Zhang u32 link_status; 62795fa0405SHaiyang Zhang int ret; 62895fa0405SHaiyang Zhang 62995fa0405SHaiyang Zhang ret = rndis_filter_query_device(dev, 63095fa0405SHaiyang Zhang RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, 63195fa0405SHaiyang Zhang &link_status, &size); 63295fa0405SHaiyang Zhang dev->link_state = (link_status != 0) ? true : false; 63395fa0405SHaiyang Zhang 63495fa0405SHaiyang Zhang return ret; 63595fa0405SHaiyang Zhang } 63695fa0405SHaiyang Zhang 637d426b2e3SHaiyang Zhang int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) 63895fa0405SHaiyang Zhang { 63995fa0405SHaiyang Zhang struct rndis_request *request; 64095fa0405SHaiyang Zhang struct rndis_set_request *set; 64195fa0405SHaiyang Zhang struct rndis_set_complete *set_complete; 64295fa0405SHaiyang Zhang u32 status; 64395fa0405SHaiyang Zhang int ret, t; 64495fa0405SHaiyang Zhang struct net_device *ndev; 64595fa0405SHaiyang Zhang 64695fa0405SHaiyang Zhang ndev = dev->net_dev->ndev; 64795fa0405SHaiyang Zhang 64851491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_SET, 64995fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_set_request) + 65095fa0405SHaiyang Zhang sizeof(u32)); 65195fa0405SHaiyang Zhang if (!request) { 65295fa0405SHaiyang Zhang ret = -ENOMEM; 65395fa0405SHaiyang Zhang goto cleanup; 65495fa0405SHaiyang Zhang } 65595fa0405SHaiyang Zhang 65695fa0405SHaiyang Zhang /* Setup the rndis set */ 65795fa0405SHaiyang Zhang set = &request->request_msg.msg.set_req; 65895fa0405SHaiyang Zhang set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; 65995fa0405SHaiyang Zhang set->info_buflen = sizeof(u32); 66095fa0405SHaiyang Zhang set->info_buf_offset = sizeof(struct rndis_set_request); 66195fa0405SHaiyang Zhang 66295fa0405SHaiyang Zhang memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), 66395fa0405SHaiyang Zhang &new_filter, sizeof(u32)); 66495fa0405SHaiyang Zhang 66595fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 66695fa0405SHaiyang Zhang if (ret != 0) 66795fa0405SHaiyang Zhang goto cleanup; 66895fa0405SHaiyang Zhang 66995fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 67095fa0405SHaiyang Zhang 67195fa0405SHaiyang Zhang if (t == 0) { 67295fa0405SHaiyang Zhang netdev_err(ndev, 67395fa0405SHaiyang Zhang "timeout before we got a set response...\n"); 674ea496374SHaiyang Zhang ret = -ETIMEDOUT; 67595fa0405SHaiyang Zhang /* 67695fa0405SHaiyang Zhang * We can't deallocate the request since we may still receive a 67795fa0405SHaiyang Zhang * send completion for it. 67895fa0405SHaiyang Zhang */ 67995fa0405SHaiyang Zhang goto exit; 68095fa0405SHaiyang Zhang } else { 68195fa0405SHaiyang Zhang set_complete = &request->response_msg.msg.set_complete; 68295fa0405SHaiyang Zhang status = set_complete->status; 68395fa0405SHaiyang Zhang } 68495fa0405SHaiyang Zhang 68595fa0405SHaiyang Zhang cleanup: 68695fa0405SHaiyang Zhang if (request) 68795fa0405SHaiyang Zhang put_rndis_request(dev, request); 68895fa0405SHaiyang Zhang exit: 68995fa0405SHaiyang Zhang return ret; 69095fa0405SHaiyang Zhang } 69195fa0405SHaiyang Zhang 69295fa0405SHaiyang Zhang 69395fa0405SHaiyang Zhang static int rndis_filter_init_device(struct rndis_device *dev) 69495fa0405SHaiyang Zhang { 69595fa0405SHaiyang Zhang struct rndis_request *request; 69695fa0405SHaiyang Zhang struct rndis_initialize_request *init; 69795fa0405SHaiyang Zhang struct rndis_initialize_complete *init_complete; 69895fa0405SHaiyang Zhang u32 status; 69995fa0405SHaiyang Zhang int ret, t; 70095fa0405SHaiyang Zhang 70151491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_INIT, 70295fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); 70395fa0405SHaiyang Zhang if (!request) { 70495fa0405SHaiyang Zhang ret = -ENOMEM; 70595fa0405SHaiyang Zhang goto cleanup; 70695fa0405SHaiyang Zhang } 70795fa0405SHaiyang Zhang 70895fa0405SHaiyang Zhang /* Setup the rndis set */ 70995fa0405SHaiyang Zhang init = &request->request_msg.msg.init_req; 71095fa0405SHaiyang Zhang init->major_ver = RNDIS_MAJOR_VERSION; 71195fa0405SHaiyang Zhang init->minor_ver = RNDIS_MINOR_VERSION; 712fb1d074eSHaiyang Zhang init->max_xfer_size = 0x4000; 71395fa0405SHaiyang Zhang 71495fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZING; 71595fa0405SHaiyang Zhang 71695fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 71795fa0405SHaiyang Zhang if (ret != 0) { 71895fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 71995fa0405SHaiyang Zhang goto cleanup; 72095fa0405SHaiyang Zhang } 72195fa0405SHaiyang Zhang 72295fa0405SHaiyang Zhang 72395fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 72495fa0405SHaiyang Zhang 72595fa0405SHaiyang Zhang if (t == 0) { 72695fa0405SHaiyang Zhang ret = -ETIMEDOUT; 72795fa0405SHaiyang Zhang goto cleanup; 72895fa0405SHaiyang Zhang } 72995fa0405SHaiyang Zhang 73095fa0405SHaiyang Zhang init_complete = &request->response_msg.msg.init_complete; 73195fa0405SHaiyang Zhang status = init_complete->status; 73295fa0405SHaiyang Zhang if (status == RNDIS_STATUS_SUCCESS) { 73395fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZED; 73495fa0405SHaiyang Zhang ret = 0; 73595fa0405SHaiyang Zhang } else { 73695fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 73795fa0405SHaiyang Zhang ret = -EINVAL; 73895fa0405SHaiyang Zhang } 73995fa0405SHaiyang Zhang 74095fa0405SHaiyang Zhang cleanup: 74195fa0405SHaiyang Zhang if (request) 74295fa0405SHaiyang Zhang put_rndis_request(dev, request); 74395fa0405SHaiyang Zhang 74495fa0405SHaiyang Zhang return ret; 74595fa0405SHaiyang Zhang } 74695fa0405SHaiyang Zhang 74795fa0405SHaiyang Zhang static void rndis_filter_halt_device(struct rndis_device *dev) 74895fa0405SHaiyang Zhang { 74995fa0405SHaiyang Zhang struct rndis_request *request; 75095fa0405SHaiyang Zhang struct rndis_halt_request *halt; 751ae9e63bbSHaiyang Zhang struct netvsc_device *nvdev = dev->net_dev; 752ae9e63bbSHaiyang Zhang struct hv_device *hdev = nvdev->dev; 753ae9e63bbSHaiyang Zhang ulong flags; 75495fa0405SHaiyang Zhang 75595fa0405SHaiyang Zhang /* Attempt to do a rndis device halt */ 75651491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_HALT, 75795fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); 75895fa0405SHaiyang Zhang if (!request) 75995fa0405SHaiyang Zhang goto cleanup; 76095fa0405SHaiyang Zhang 76195fa0405SHaiyang Zhang /* Setup the rndis set */ 76295fa0405SHaiyang Zhang halt = &request->request_msg.msg.halt_req; 76395fa0405SHaiyang Zhang halt->req_id = atomic_inc_return(&dev->new_req_id); 76495fa0405SHaiyang Zhang 76595fa0405SHaiyang Zhang /* Ignore return since this msg is optional. */ 76695fa0405SHaiyang Zhang rndis_filter_send_request(dev, request); 76795fa0405SHaiyang Zhang 76895fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 76995fa0405SHaiyang Zhang 77095fa0405SHaiyang Zhang cleanup: 771ae9e63bbSHaiyang Zhang spin_lock_irqsave(&hdev->channel->inbound_lock, flags); 772ae9e63bbSHaiyang Zhang nvdev->destroy = true; 773ae9e63bbSHaiyang Zhang spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags); 774ae9e63bbSHaiyang Zhang 775ae9e63bbSHaiyang Zhang /* Wait for all send completions */ 776ae9e63bbSHaiyang Zhang wait_event(nvdev->wait_drain, 777ae9e63bbSHaiyang Zhang atomic_read(&nvdev->num_outstanding_sends) == 0); 778ae9e63bbSHaiyang Zhang 77995fa0405SHaiyang Zhang if (request) 78095fa0405SHaiyang Zhang put_rndis_request(dev, request); 78195fa0405SHaiyang Zhang return; 78295fa0405SHaiyang Zhang } 78395fa0405SHaiyang Zhang 78495fa0405SHaiyang Zhang static int rndis_filter_open_device(struct rndis_device *dev) 78595fa0405SHaiyang Zhang { 78695fa0405SHaiyang Zhang int ret; 78795fa0405SHaiyang Zhang 78895fa0405SHaiyang Zhang if (dev->state != RNDIS_DEV_INITIALIZED) 78995fa0405SHaiyang Zhang return 0; 79095fa0405SHaiyang Zhang 79195fa0405SHaiyang Zhang ret = rndis_filter_set_packet_filter(dev, 79295fa0405SHaiyang Zhang NDIS_PACKET_TYPE_BROADCAST | 79395fa0405SHaiyang Zhang NDIS_PACKET_TYPE_ALL_MULTICAST | 79495fa0405SHaiyang Zhang NDIS_PACKET_TYPE_DIRECTED); 79595fa0405SHaiyang Zhang if (ret == 0) 79695fa0405SHaiyang Zhang dev->state = RNDIS_DEV_DATAINITIALIZED; 79795fa0405SHaiyang Zhang 79895fa0405SHaiyang Zhang return ret; 79995fa0405SHaiyang Zhang } 80095fa0405SHaiyang Zhang 80195fa0405SHaiyang Zhang static int rndis_filter_close_device(struct rndis_device *dev) 80295fa0405SHaiyang Zhang { 80395fa0405SHaiyang Zhang int ret; 80495fa0405SHaiyang Zhang 80595fa0405SHaiyang Zhang if (dev->state != RNDIS_DEV_DATAINITIALIZED) 80695fa0405SHaiyang Zhang return 0; 80795fa0405SHaiyang Zhang 80895fa0405SHaiyang Zhang ret = rndis_filter_set_packet_filter(dev, 0); 80995fa0405SHaiyang Zhang if (ret == 0) 81095fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZED; 81195fa0405SHaiyang Zhang 81295fa0405SHaiyang Zhang return ret; 81395fa0405SHaiyang Zhang } 81495fa0405SHaiyang Zhang 81595fa0405SHaiyang Zhang int rndis_filter_device_add(struct hv_device *dev, 81695fa0405SHaiyang Zhang void *additional_info) 81795fa0405SHaiyang Zhang { 81895fa0405SHaiyang Zhang int ret; 81995fa0405SHaiyang Zhang struct netvsc_device *net_device; 82095fa0405SHaiyang Zhang struct rndis_device *rndis_device; 82195fa0405SHaiyang Zhang struct netvsc_device_info *device_info = additional_info; 82295fa0405SHaiyang Zhang 82395fa0405SHaiyang Zhang rndis_device = get_rndis_device(); 82495fa0405SHaiyang Zhang if (!rndis_device) 82595fa0405SHaiyang Zhang return -ENODEV; 82695fa0405SHaiyang Zhang 82795fa0405SHaiyang Zhang /* 82895fa0405SHaiyang Zhang * Let the inner driver handle this first to create the netvsc channel 82995fa0405SHaiyang Zhang * NOTE! Once the channel is created, we may get a receive callback 83095fa0405SHaiyang Zhang * (RndisFilterOnReceive()) before this call is completed 83195fa0405SHaiyang Zhang */ 83295fa0405SHaiyang Zhang ret = netvsc_device_add(dev, additional_info); 83395fa0405SHaiyang Zhang if (ret != 0) { 83495fa0405SHaiyang Zhang kfree(rndis_device); 83595fa0405SHaiyang Zhang return ret; 83695fa0405SHaiyang Zhang } 83795fa0405SHaiyang Zhang 83895fa0405SHaiyang Zhang 83995fa0405SHaiyang Zhang /* Initialize the rndis device */ 84095fa0405SHaiyang Zhang net_device = hv_get_drvdata(dev); 84195fa0405SHaiyang Zhang 84295fa0405SHaiyang Zhang net_device->extension = rndis_device; 84395fa0405SHaiyang Zhang rndis_device->net_dev = net_device; 84495fa0405SHaiyang Zhang 84595fa0405SHaiyang Zhang /* Send the rndis initialization message */ 84695fa0405SHaiyang Zhang ret = rndis_filter_init_device(rndis_device); 84795fa0405SHaiyang Zhang if (ret != 0) { 8485243e7bdSHaiyang Zhang rndis_filter_device_remove(dev); 8495243e7bdSHaiyang Zhang return ret; 85095fa0405SHaiyang Zhang } 85195fa0405SHaiyang Zhang 85295fa0405SHaiyang Zhang /* Get the mac address */ 85395fa0405SHaiyang Zhang ret = rndis_filter_query_device_mac(rndis_device); 85495fa0405SHaiyang Zhang if (ret != 0) { 8555243e7bdSHaiyang Zhang rndis_filter_device_remove(dev); 8565243e7bdSHaiyang Zhang return ret; 85795fa0405SHaiyang Zhang } 85895fa0405SHaiyang Zhang 85995fa0405SHaiyang Zhang memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); 86095fa0405SHaiyang Zhang 86195fa0405SHaiyang Zhang rndis_filter_query_device_link_status(rndis_device); 86295fa0405SHaiyang Zhang 86395fa0405SHaiyang Zhang device_info->link_state = rndis_device->link_state; 86495fa0405SHaiyang Zhang 86595fa0405SHaiyang Zhang dev_info(&dev->device, "Device MAC %pM link state %s\n", 86695fa0405SHaiyang Zhang rndis_device->hw_mac_adr, 86795fa0405SHaiyang Zhang device_info->link_state ? "down" : "up"); 86895fa0405SHaiyang Zhang 86995fa0405SHaiyang Zhang return ret; 87095fa0405SHaiyang Zhang } 87195fa0405SHaiyang Zhang 87295fa0405SHaiyang Zhang void rndis_filter_device_remove(struct hv_device *dev) 87395fa0405SHaiyang Zhang { 87495fa0405SHaiyang Zhang struct netvsc_device *net_dev = hv_get_drvdata(dev); 87595fa0405SHaiyang Zhang struct rndis_device *rndis_dev = net_dev->extension; 87695fa0405SHaiyang Zhang 87795fa0405SHaiyang Zhang /* Halt and release the rndis device */ 87895fa0405SHaiyang Zhang rndis_filter_halt_device(rndis_dev); 87995fa0405SHaiyang Zhang 88095fa0405SHaiyang Zhang kfree(rndis_dev); 88195fa0405SHaiyang Zhang net_dev->extension = NULL; 88295fa0405SHaiyang Zhang 88395fa0405SHaiyang Zhang netvsc_device_remove(dev); 88495fa0405SHaiyang Zhang } 88595fa0405SHaiyang Zhang 88695fa0405SHaiyang Zhang 88795fa0405SHaiyang Zhang int rndis_filter_open(struct hv_device *dev) 88895fa0405SHaiyang Zhang { 88995fa0405SHaiyang Zhang struct netvsc_device *net_device = hv_get_drvdata(dev); 89095fa0405SHaiyang Zhang 89195fa0405SHaiyang Zhang if (!net_device) 89295fa0405SHaiyang Zhang return -EINVAL; 89395fa0405SHaiyang Zhang 89495fa0405SHaiyang Zhang return rndis_filter_open_device(net_device->extension); 89595fa0405SHaiyang Zhang } 89695fa0405SHaiyang Zhang 89795fa0405SHaiyang Zhang int rndis_filter_close(struct hv_device *dev) 89895fa0405SHaiyang Zhang { 8995fccab3bSHaiyang Zhang struct netvsc_device *nvdev = hv_get_drvdata(dev); 90095fa0405SHaiyang Zhang 9015fccab3bSHaiyang Zhang if (!nvdev) 90295fa0405SHaiyang Zhang return -EINVAL; 90395fa0405SHaiyang Zhang 9045fccab3bSHaiyang Zhang return rndis_filter_close_device(nvdev->extension); 90595fa0405SHaiyang Zhang } 90695fa0405SHaiyang Zhang 90795fa0405SHaiyang Zhang int rndis_filter_send(struct hv_device *dev, 90895fa0405SHaiyang Zhang struct hv_netvsc_packet *pkt) 90995fa0405SHaiyang Zhang { 91095fa0405SHaiyang Zhang int ret; 9115fccab3bSHaiyang Zhang struct rndis_filter_packet *filter_pkt; 9125fccab3bSHaiyang Zhang struct rndis_message *rndis_msg; 9135fccab3bSHaiyang Zhang struct rndis_packet *rndis_pkt; 9145fccab3bSHaiyang Zhang u32 rndis_msg_size; 9151f5f3a75SHaiyang Zhang bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT; 91695fa0405SHaiyang Zhang 91795fa0405SHaiyang Zhang /* Add the rndis header */ 9185fccab3bSHaiyang Zhang filter_pkt = (struct rndis_filter_packet *)pkt->extension; 91995fa0405SHaiyang Zhang 9205fccab3bSHaiyang Zhang rndis_msg = &filter_pkt->msg; 9215fccab3bSHaiyang Zhang rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); 9221f5f3a75SHaiyang Zhang if (isvlan) 9231f5f3a75SHaiyang Zhang rndis_msg_size += NDIS_VLAN_PPI_SIZE; 92495fa0405SHaiyang Zhang 92551491167SLinus Walleij rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; 9265fccab3bSHaiyang Zhang rndis_msg->msg_len = pkt->total_data_buflen + 9275fccab3bSHaiyang Zhang rndis_msg_size; 92895fa0405SHaiyang Zhang 9295fccab3bSHaiyang Zhang rndis_pkt = &rndis_msg->msg.pkt; 9305fccab3bSHaiyang Zhang rndis_pkt->data_offset = sizeof(struct rndis_packet); 9311f5f3a75SHaiyang Zhang if (isvlan) 9321f5f3a75SHaiyang Zhang rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE; 9335fccab3bSHaiyang Zhang rndis_pkt->data_len = pkt->total_data_buflen; 93495fa0405SHaiyang Zhang 9351f5f3a75SHaiyang Zhang if (isvlan) { 9361f5f3a75SHaiyang Zhang struct rndis_per_packet_info *ppi; 9371f5f3a75SHaiyang Zhang struct ndis_pkt_8021q_info *vlan; 9381f5f3a75SHaiyang Zhang 9391f5f3a75SHaiyang Zhang rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); 9401f5f3a75SHaiyang Zhang rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE; 9411f5f3a75SHaiyang Zhang 9421f5f3a75SHaiyang Zhang ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt + 9431f5f3a75SHaiyang Zhang rndis_pkt->per_pkt_info_offset); 9441f5f3a75SHaiyang Zhang ppi->size = NDIS_VLAN_PPI_SIZE; 9451f5f3a75SHaiyang Zhang ppi->type = IEEE_8021Q_INFO; 9461f5f3a75SHaiyang Zhang ppi->ppi_offset = sizeof(struct rndis_per_packet_info); 9471f5f3a75SHaiyang Zhang 9481f5f3a75SHaiyang Zhang vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi + 9491f5f3a75SHaiyang Zhang ppi->ppi_offset); 9501f5f3a75SHaiyang Zhang vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK; 9511f5f3a75SHaiyang Zhang vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 9521f5f3a75SHaiyang Zhang } 9531f5f3a75SHaiyang Zhang 95495fa0405SHaiyang Zhang pkt->is_data_pkt = true; 9555fccab3bSHaiyang Zhang pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT; 95695fa0405SHaiyang Zhang pkt->page_buf[0].offset = 9575fccab3bSHaiyang Zhang (unsigned long)rndis_msg & (PAGE_SIZE-1); 9585fccab3bSHaiyang Zhang pkt->page_buf[0].len = rndis_msg_size; 95995fa0405SHaiyang Zhang 960c31c151bSHaiyang Zhang /* Add one page_buf if the rndis msg goes beyond page boundary */ 9615fccab3bSHaiyang Zhang if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) { 962c31c151bSHaiyang Zhang int i; 963c31c151bSHaiyang Zhang for (i = pkt->page_buf_cnt; i > 1; i--) 964c31c151bSHaiyang Zhang pkt->page_buf[i] = pkt->page_buf[i-1]; 965c31c151bSHaiyang Zhang pkt->page_buf_cnt++; 966c31c151bSHaiyang Zhang pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset; 967c31c151bSHaiyang Zhang pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong) 9685fccab3bSHaiyang Zhang rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT; 969c31c151bSHaiyang Zhang pkt->page_buf[1].offset = 0; 9705fccab3bSHaiyang Zhang pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len; 971c31c151bSHaiyang Zhang } 972c31c151bSHaiyang Zhang 97395fa0405SHaiyang Zhang /* Save the packet send completion and context */ 9745fccab3bSHaiyang Zhang filter_pkt->completion = pkt->completion.send.send_completion; 9755fccab3bSHaiyang Zhang filter_pkt->completion_ctx = 97695fa0405SHaiyang Zhang pkt->completion.send.send_completion_ctx; 97795fa0405SHaiyang Zhang 97895fa0405SHaiyang Zhang /* Use ours */ 97995fa0405SHaiyang Zhang pkt->completion.send.send_completion = rndis_filter_send_completion; 9805fccab3bSHaiyang Zhang pkt->completion.send.send_completion_ctx = filter_pkt; 98195fa0405SHaiyang Zhang 98295fa0405SHaiyang Zhang ret = netvsc_send(dev, pkt); 98395fa0405SHaiyang Zhang if (ret != 0) { 98495fa0405SHaiyang Zhang /* 98595fa0405SHaiyang Zhang * Reset the completion to originals to allow retries from 98695fa0405SHaiyang Zhang * above 98795fa0405SHaiyang Zhang */ 98895fa0405SHaiyang Zhang pkt->completion.send.send_completion = 9895fccab3bSHaiyang Zhang filter_pkt->completion; 99095fa0405SHaiyang Zhang pkt->completion.send.send_completion_ctx = 9915fccab3bSHaiyang Zhang filter_pkt->completion_ctx; 99295fa0405SHaiyang Zhang } 99395fa0405SHaiyang Zhang 99495fa0405SHaiyang Zhang return ret; 99595fa0405SHaiyang Zhang } 99695fa0405SHaiyang Zhang 99795fa0405SHaiyang Zhang static void rndis_filter_send_completion(void *ctx) 99895fa0405SHaiyang Zhang { 9995fccab3bSHaiyang Zhang struct rndis_filter_packet *filter_pkt = ctx; 100095fa0405SHaiyang Zhang 100195fa0405SHaiyang Zhang /* Pass it back to the original handler */ 10025fccab3bSHaiyang Zhang filter_pkt->completion(filter_pkt->completion_ctx); 100395fa0405SHaiyang Zhang } 100495fa0405SHaiyang Zhang 100595fa0405SHaiyang Zhang 100695fa0405SHaiyang Zhang static void rndis_filter_send_request_completion(void *ctx) 100795fa0405SHaiyang Zhang { 100895fa0405SHaiyang Zhang /* Noop */ 100995fa0405SHaiyang Zhang } 1010