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 14adf8d3ffSJeff Kirsher * this program; if not, see <http://www.gnu.org/licenses/>. 1595fa0405SHaiyang Zhang * 1695fa0405SHaiyang Zhang * Authors: 1795fa0405SHaiyang Zhang * Haiyang Zhang <haiyangz@microsoft.com> 1895fa0405SHaiyang Zhang * Hank Janssen <hjanssen@microsoft.com> 1995fa0405SHaiyang Zhang */ 2095fa0405SHaiyang Zhang #include <linux/kernel.h> 2195fa0405SHaiyang Zhang #include <linux/sched.h> 2295fa0405SHaiyang Zhang #include <linux/wait.h> 2395fa0405SHaiyang Zhang #include <linux/highmem.h> 2495fa0405SHaiyang Zhang #include <linux/slab.h> 2595fa0405SHaiyang Zhang #include <linux/io.h> 2695fa0405SHaiyang Zhang #include <linux/if_ether.h> 2795fa0405SHaiyang Zhang #include <linux/netdevice.h> 281f5f3a75SHaiyang Zhang #include <linux/if_vlan.h> 291ce09e89SHaiyang Zhang #include <linux/nls.h> 3095fa0405SHaiyang Zhang 3195fa0405SHaiyang Zhang #include "hyperv_net.h" 3295fa0405SHaiyang Zhang 3395fa0405SHaiyang Zhang 345b54dac8SHaiyang Zhang #define RNDIS_EXT_LEN PAGE_SIZE 3595fa0405SHaiyang Zhang struct rndis_request { 3695fa0405SHaiyang Zhang struct list_head list_ent; 3795fa0405SHaiyang Zhang struct completion wait_event; 3895fa0405SHaiyang Zhang 3995fa0405SHaiyang Zhang struct rndis_message response_msg; 40a3a6cab5SHaiyang Zhang /* 41a3a6cab5SHaiyang Zhang * The buffer for extended info after the RNDIS response message. It's 42a3a6cab5SHaiyang Zhang * referenced based on the data offset in the RNDIS message. Its size 43a3a6cab5SHaiyang Zhang * is enough for current needs, and should be sufficient for the near 44a3a6cab5SHaiyang Zhang * future. 45a3a6cab5SHaiyang Zhang */ 46a3a6cab5SHaiyang Zhang u8 response_ext[RNDIS_EXT_LEN]; 4795fa0405SHaiyang Zhang 4895fa0405SHaiyang Zhang /* Simplify allocation by having a netvsc packet inline */ 4995fa0405SHaiyang Zhang struct hv_netvsc_packet pkt; 5099e3fcfaSHaiyang Zhang /* Set 2 pages for rndis requests crossing page boundary */ 5199e3fcfaSHaiyang Zhang struct hv_page_buffer buf[2]; 520f48917bSHaiyang Zhang 5395fa0405SHaiyang Zhang struct rndis_message request_msg; 540f48917bSHaiyang Zhang /* 55a3a6cab5SHaiyang Zhang * The buffer for the extended info after the RNDIS request message. 56a3a6cab5SHaiyang Zhang * It is referenced and sized in a similar way as response_ext. 570f48917bSHaiyang Zhang */ 58a3a6cab5SHaiyang Zhang u8 request_ext[RNDIS_EXT_LEN]; 5995fa0405SHaiyang Zhang }; 6095fa0405SHaiyang Zhang 6195fa0405SHaiyang Zhang static struct rndis_device *get_rndis_device(void) 6295fa0405SHaiyang Zhang { 6395fa0405SHaiyang Zhang struct rndis_device *device; 6495fa0405SHaiyang Zhang 6595fa0405SHaiyang Zhang device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL); 6695fa0405SHaiyang Zhang if (!device) 6795fa0405SHaiyang Zhang return NULL; 6895fa0405SHaiyang Zhang 6995fa0405SHaiyang Zhang spin_lock_init(&device->request_lock); 7095fa0405SHaiyang Zhang 7195fa0405SHaiyang Zhang INIT_LIST_HEAD(&device->req_list); 7295fa0405SHaiyang Zhang 7395fa0405SHaiyang Zhang device->state = RNDIS_DEV_UNINITIALIZED; 7495fa0405SHaiyang Zhang 7595fa0405SHaiyang Zhang return device; 7695fa0405SHaiyang Zhang } 7795fa0405SHaiyang Zhang 7895fa0405SHaiyang Zhang static struct rndis_request *get_rndis_request(struct rndis_device *dev, 7995fa0405SHaiyang Zhang u32 msg_type, 8095fa0405SHaiyang Zhang u32 msg_len) 8195fa0405SHaiyang Zhang { 8295fa0405SHaiyang Zhang struct rndis_request *request; 8395fa0405SHaiyang Zhang struct rndis_message *rndis_msg; 8495fa0405SHaiyang Zhang struct rndis_set_request *set; 8595fa0405SHaiyang Zhang unsigned long flags; 8695fa0405SHaiyang Zhang 8795fa0405SHaiyang Zhang request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL); 8895fa0405SHaiyang Zhang if (!request) 8995fa0405SHaiyang Zhang return NULL; 9095fa0405SHaiyang Zhang 9195fa0405SHaiyang Zhang init_completion(&request->wait_event); 9295fa0405SHaiyang Zhang 9395fa0405SHaiyang Zhang rndis_msg = &request->request_msg; 9495fa0405SHaiyang Zhang rndis_msg->ndis_msg_type = msg_type; 9595fa0405SHaiyang Zhang rndis_msg->msg_len = msg_len; 9695fa0405SHaiyang Zhang 975b54dac8SHaiyang Zhang request->pkt.q_idx = 0; 985b54dac8SHaiyang Zhang 9995fa0405SHaiyang Zhang /* 10095fa0405SHaiyang Zhang * Set the request id. This field is always after the rndis header for 10195fa0405SHaiyang Zhang * request/response packet types so we just used the SetRequest as a 10295fa0405SHaiyang Zhang * template 10395fa0405SHaiyang Zhang */ 10495fa0405SHaiyang Zhang set = &rndis_msg->msg.set_req; 10595fa0405SHaiyang Zhang set->req_id = atomic_inc_return(&dev->new_req_id); 10695fa0405SHaiyang Zhang 10795fa0405SHaiyang Zhang /* Add to the request list */ 10895fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 10995fa0405SHaiyang Zhang list_add_tail(&request->list_ent, &dev->req_list); 11095fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 11195fa0405SHaiyang Zhang 11295fa0405SHaiyang Zhang return request; 11395fa0405SHaiyang Zhang } 11495fa0405SHaiyang Zhang 11595fa0405SHaiyang Zhang static void put_rndis_request(struct rndis_device *dev, 11695fa0405SHaiyang Zhang struct rndis_request *req) 11795fa0405SHaiyang Zhang { 11895fa0405SHaiyang Zhang unsigned long flags; 11995fa0405SHaiyang Zhang 12095fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 12195fa0405SHaiyang Zhang list_del(&req->list_ent); 12295fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 12395fa0405SHaiyang Zhang 12495fa0405SHaiyang Zhang kfree(req); 12595fa0405SHaiyang Zhang } 12695fa0405SHaiyang Zhang 12795fa0405SHaiyang Zhang static void dump_rndis_message(struct hv_device *hv_dev, 12895fa0405SHaiyang Zhang struct rndis_message *rndis_msg) 12995fa0405SHaiyang Zhang { 13095fa0405SHaiyang Zhang struct net_device *netdev; 13195fa0405SHaiyang Zhang struct netvsc_device *net_device; 13295fa0405SHaiyang Zhang 13395fa0405SHaiyang Zhang net_device = hv_get_drvdata(hv_dev); 13495fa0405SHaiyang Zhang netdev = net_device->ndev; 13595fa0405SHaiyang Zhang 13695fa0405SHaiyang Zhang switch (rndis_msg->ndis_msg_type) { 13751491167SLinus Walleij case RNDIS_MSG_PACKET: 13851491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, " 13995fa0405SHaiyang Zhang "data offset %u data len %u, # oob %u, " 14095fa0405SHaiyang Zhang "oob offset %u, oob len %u, pkt offset %u, " 14195fa0405SHaiyang Zhang "pkt len %u\n", 14295fa0405SHaiyang Zhang rndis_msg->msg_len, 14395fa0405SHaiyang Zhang rndis_msg->msg.pkt.data_offset, 14495fa0405SHaiyang Zhang rndis_msg->msg.pkt.data_len, 14595fa0405SHaiyang Zhang rndis_msg->msg.pkt.num_oob_data_elements, 14695fa0405SHaiyang Zhang rndis_msg->msg.pkt.oob_data_offset, 14795fa0405SHaiyang Zhang rndis_msg->msg.pkt.oob_data_len, 14895fa0405SHaiyang Zhang rndis_msg->msg.pkt.per_pkt_info_offset, 14995fa0405SHaiyang Zhang rndis_msg->msg.pkt.per_pkt_info_len); 15095fa0405SHaiyang Zhang break; 15195fa0405SHaiyang Zhang 15251491167SLinus Walleij case RNDIS_MSG_INIT_C: 15351491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_INIT_C " 15495fa0405SHaiyang Zhang "(len %u, id 0x%x, status 0x%x, major %d, minor %d, " 15595fa0405SHaiyang Zhang "device flags %d, max xfer size 0x%x, max pkts %u, " 15695fa0405SHaiyang Zhang "pkt aligned %u)\n", 15795fa0405SHaiyang Zhang rndis_msg->msg_len, 15895fa0405SHaiyang Zhang rndis_msg->msg.init_complete.req_id, 15995fa0405SHaiyang Zhang rndis_msg->msg.init_complete.status, 16095fa0405SHaiyang Zhang rndis_msg->msg.init_complete.major_ver, 16195fa0405SHaiyang Zhang rndis_msg->msg.init_complete.minor_ver, 16295fa0405SHaiyang Zhang rndis_msg->msg.init_complete.dev_flags, 16395fa0405SHaiyang Zhang rndis_msg->msg.init_complete.max_xfer_size, 16495fa0405SHaiyang Zhang rndis_msg->msg.init_complete. 16595fa0405SHaiyang Zhang max_pkt_per_msg, 16695fa0405SHaiyang Zhang rndis_msg->msg.init_complete. 16795fa0405SHaiyang Zhang pkt_alignment_factor); 16895fa0405SHaiyang Zhang break; 16995fa0405SHaiyang Zhang 17051491167SLinus Walleij case RNDIS_MSG_QUERY_C: 17151491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_QUERY_C " 17295fa0405SHaiyang Zhang "(len %u, id 0x%x, status 0x%x, buf len %u, " 17395fa0405SHaiyang Zhang "buf offset %u)\n", 17495fa0405SHaiyang Zhang rndis_msg->msg_len, 17595fa0405SHaiyang Zhang rndis_msg->msg.query_complete.req_id, 17695fa0405SHaiyang Zhang rndis_msg->msg.query_complete.status, 17795fa0405SHaiyang Zhang rndis_msg->msg.query_complete. 17895fa0405SHaiyang Zhang info_buflen, 17995fa0405SHaiyang Zhang rndis_msg->msg.query_complete. 18095fa0405SHaiyang Zhang info_buf_offset); 18195fa0405SHaiyang Zhang break; 18295fa0405SHaiyang Zhang 18351491167SLinus Walleij case RNDIS_MSG_SET_C: 18495fa0405SHaiyang Zhang netdev_dbg(netdev, 18551491167SLinus Walleij "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n", 18695fa0405SHaiyang Zhang rndis_msg->msg_len, 18795fa0405SHaiyang Zhang rndis_msg->msg.set_complete.req_id, 18895fa0405SHaiyang Zhang rndis_msg->msg.set_complete.status); 18995fa0405SHaiyang Zhang break; 19095fa0405SHaiyang Zhang 19151491167SLinus Walleij case RNDIS_MSG_INDICATE: 19251491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_INDICATE " 19395fa0405SHaiyang Zhang "(len %u, status 0x%x, buf len %u, buf offset %u)\n", 19495fa0405SHaiyang Zhang rndis_msg->msg_len, 19595fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status, 19695fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status_buflen, 19795fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status_buf_offset); 19895fa0405SHaiyang Zhang break; 19995fa0405SHaiyang Zhang 20095fa0405SHaiyang Zhang default: 20195fa0405SHaiyang Zhang netdev_dbg(netdev, "0x%x (len %u)\n", 20295fa0405SHaiyang Zhang rndis_msg->ndis_msg_type, 20395fa0405SHaiyang Zhang rndis_msg->msg_len); 20495fa0405SHaiyang Zhang break; 20595fa0405SHaiyang Zhang } 20695fa0405SHaiyang Zhang } 20795fa0405SHaiyang Zhang 20895fa0405SHaiyang Zhang static int rndis_filter_send_request(struct rndis_device *dev, 20995fa0405SHaiyang Zhang struct rndis_request *req) 21095fa0405SHaiyang Zhang { 21195fa0405SHaiyang Zhang int ret; 21295fa0405SHaiyang Zhang struct hv_netvsc_packet *packet; 21395fa0405SHaiyang Zhang 21495fa0405SHaiyang Zhang /* Setup the packet to send it */ 21595fa0405SHaiyang Zhang packet = &req->pkt; 21695fa0405SHaiyang Zhang 21795fa0405SHaiyang Zhang packet->is_data_pkt = false; 21895fa0405SHaiyang Zhang packet->total_data_buflen = req->request_msg.msg_len; 21995fa0405SHaiyang Zhang packet->page_buf_cnt = 1; 22095fa0405SHaiyang Zhang 22195fa0405SHaiyang Zhang packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >> 22295fa0405SHaiyang Zhang PAGE_SHIFT; 22395fa0405SHaiyang Zhang packet->page_buf[0].len = req->request_msg.msg_len; 22495fa0405SHaiyang Zhang packet->page_buf[0].offset = 22595fa0405SHaiyang Zhang (unsigned long)&req->request_msg & (PAGE_SIZE - 1); 22695fa0405SHaiyang Zhang 22799e3fcfaSHaiyang Zhang /* Add one page_buf when request_msg crossing page boundary */ 22899e3fcfaSHaiyang Zhang if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) { 22999e3fcfaSHaiyang Zhang packet->page_buf_cnt++; 23099e3fcfaSHaiyang Zhang packet->page_buf[0].len = PAGE_SIZE - 23199e3fcfaSHaiyang Zhang packet->page_buf[0].offset; 23299e3fcfaSHaiyang Zhang packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg 23399e3fcfaSHaiyang Zhang + packet->page_buf[0].len) >> PAGE_SHIFT; 23499e3fcfaSHaiyang Zhang packet->page_buf[1].offset = 0; 23599e3fcfaSHaiyang Zhang packet->page_buf[1].len = req->request_msg.msg_len - 23699e3fcfaSHaiyang Zhang packet->page_buf[0].len; 23799e3fcfaSHaiyang Zhang } 23899e3fcfaSHaiyang Zhang 239893f6627SHaiyang Zhang packet->send_completion = NULL; 2407c3877f2SHaiyang Zhang packet->xmit_more = false; 24195fa0405SHaiyang Zhang 24295fa0405SHaiyang Zhang ret = netvsc_send(dev->net_dev->dev, packet); 24395fa0405SHaiyang Zhang return ret; 24495fa0405SHaiyang Zhang } 24595fa0405SHaiyang Zhang 2461b07da51SHaiyang Zhang static void rndis_set_link_state(struct rndis_device *rdev, 2471b07da51SHaiyang Zhang struct rndis_request *request) 2481b07da51SHaiyang Zhang { 2491b07da51SHaiyang Zhang u32 link_status; 2501b07da51SHaiyang Zhang struct rndis_query_complete *query_complete; 2511b07da51SHaiyang Zhang 2521b07da51SHaiyang Zhang query_complete = &request->response_msg.msg.query_complete; 2531b07da51SHaiyang Zhang 2541b07da51SHaiyang Zhang if (query_complete->status == RNDIS_STATUS_SUCCESS && 2551b07da51SHaiyang Zhang query_complete->info_buflen == sizeof(u32)) { 2561b07da51SHaiyang Zhang memcpy(&link_status, (void *)((unsigned long)query_complete + 2571b07da51SHaiyang Zhang query_complete->info_buf_offset), sizeof(u32)); 2581b07da51SHaiyang Zhang rdev->link_state = link_status != 0; 2591b07da51SHaiyang Zhang } 2601b07da51SHaiyang Zhang } 2611b07da51SHaiyang Zhang 26295fa0405SHaiyang Zhang static void rndis_filter_receive_response(struct rndis_device *dev, 26395fa0405SHaiyang Zhang struct rndis_message *resp) 26495fa0405SHaiyang Zhang { 26595fa0405SHaiyang Zhang struct rndis_request *request = NULL; 26695fa0405SHaiyang Zhang bool found = false; 26795fa0405SHaiyang Zhang unsigned long flags; 26895fa0405SHaiyang Zhang struct net_device *ndev; 26995fa0405SHaiyang Zhang 27095fa0405SHaiyang Zhang ndev = dev->net_dev->ndev; 27195fa0405SHaiyang Zhang 27295fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 27395fa0405SHaiyang Zhang list_for_each_entry(request, &dev->req_list, list_ent) { 27495fa0405SHaiyang Zhang /* 27595fa0405SHaiyang Zhang * All request/response message contains RequestId as the 1st 27695fa0405SHaiyang Zhang * field 27795fa0405SHaiyang Zhang */ 27895fa0405SHaiyang Zhang if (request->request_msg.msg.init_req.req_id 27995fa0405SHaiyang Zhang == resp->msg.init_complete.req_id) { 28095fa0405SHaiyang Zhang found = true; 28195fa0405SHaiyang Zhang break; 28295fa0405SHaiyang Zhang } 28395fa0405SHaiyang Zhang } 28495fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 28595fa0405SHaiyang Zhang 28695fa0405SHaiyang Zhang if (found) { 287a3a6cab5SHaiyang Zhang if (resp->msg_len <= 288a3a6cab5SHaiyang Zhang sizeof(struct rndis_message) + RNDIS_EXT_LEN) { 28995fa0405SHaiyang Zhang memcpy(&request->response_msg, resp, 29095fa0405SHaiyang Zhang resp->msg_len); 2911b07da51SHaiyang Zhang if (request->request_msg.ndis_msg_type == 2921b07da51SHaiyang Zhang RNDIS_MSG_QUERY && request->request_msg.msg. 2931b07da51SHaiyang Zhang query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS) 2941b07da51SHaiyang Zhang rndis_set_link_state(dev, request); 29595fa0405SHaiyang Zhang } else { 29695fa0405SHaiyang Zhang netdev_err(ndev, 29795fa0405SHaiyang Zhang "rndis response buffer overflow " 29895fa0405SHaiyang Zhang "detected (size %u max %zu)\n", 29995fa0405SHaiyang Zhang resp->msg_len, 30086eedaccSKY Srinivasan sizeof(struct rndis_message)); 30195fa0405SHaiyang Zhang 30295fa0405SHaiyang Zhang if (resp->ndis_msg_type == 30351491167SLinus Walleij RNDIS_MSG_RESET_C) { 30495fa0405SHaiyang Zhang /* does not have a request id field */ 30595fa0405SHaiyang Zhang request->response_msg.msg.reset_complete. 306007e5c8eSLinus Walleij status = RNDIS_STATUS_BUFFER_OVERFLOW; 30795fa0405SHaiyang Zhang } else { 30895fa0405SHaiyang Zhang request->response_msg.msg. 30995fa0405SHaiyang Zhang init_complete.status = 310007e5c8eSLinus Walleij RNDIS_STATUS_BUFFER_OVERFLOW; 31195fa0405SHaiyang Zhang } 31295fa0405SHaiyang Zhang } 31395fa0405SHaiyang Zhang 31495fa0405SHaiyang Zhang complete(&request->wait_event); 31595fa0405SHaiyang Zhang } else { 31695fa0405SHaiyang Zhang netdev_err(ndev, 31795fa0405SHaiyang Zhang "no rndis request found for this response " 31895fa0405SHaiyang Zhang "(id 0x%x res type 0x%x)\n", 31995fa0405SHaiyang Zhang resp->msg.init_complete.req_id, 32095fa0405SHaiyang Zhang resp->ndis_msg_type); 32195fa0405SHaiyang Zhang } 32295fa0405SHaiyang Zhang } 32395fa0405SHaiyang Zhang 3241f5f3a75SHaiyang Zhang /* 3251f5f3a75SHaiyang Zhang * Get the Per-Packet-Info with the specified type 3261f5f3a75SHaiyang Zhang * return NULL if not found. 3271f5f3a75SHaiyang Zhang */ 3281f5f3a75SHaiyang Zhang static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type) 3291f5f3a75SHaiyang Zhang { 3301f5f3a75SHaiyang Zhang struct rndis_per_packet_info *ppi; 3311f5f3a75SHaiyang Zhang int len; 3321f5f3a75SHaiyang Zhang 3331f5f3a75SHaiyang Zhang if (rpkt->per_pkt_info_offset == 0) 3341f5f3a75SHaiyang Zhang return NULL; 3351f5f3a75SHaiyang Zhang 3361f5f3a75SHaiyang Zhang ppi = (struct rndis_per_packet_info *)((ulong)rpkt + 3371f5f3a75SHaiyang Zhang rpkt->per_pkt_info_offset); 3381f5f3a75SHaiyang Zhang len = rpkt->per_pkt_info_len; 3391f5f3a75SHaiyang Zhang 3401f5f3a75SHaiyang Zhang while (len > 0) { 3411f5f3a75SHaiyang Zhang if (ppi->type == type) 3421f5f3a75SHaiyang Zhang return (void *)((ulong)ppi + ppi->ppi_offset); 3431f5f3a75SHaiyang Zhang len -= ppi->size; 3441f5f3a75SHaiyang Zhang ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size); 3451f5f3a75SHaiyang Zhang } 3461f5f3a75SHaiyang Zhang 3471f5f3a75SHaiyang Zhang return NULL; 3481f5f3a75SHaiyang Zhang } 3491f5f3a75SHaiyang Zhang 35095fa0405SHaiyang Zhang static void rndis_filter_receive_data(struct rndis_device *dev, 35195fa0405SHaiyang Zhang struct rndis_message *msg, 35295fa0405SHaiyang Zhang struct hv_netvsc_packet *pkt) 35395fa0405SHaiyang Zhang { 35495fa0405SHaiyang Zhang struct rndis_packet *rndis_pkt; 35595fa0405SHaiyang Zhang u32 data_offset; 3561f5f3a75SHaiyang Zhang struct ndis_pkt_8021q_info *vlan; 357e3d605edSKY Srinivasan struct ndis_tcp_ip_checksum_info *csum_info; 35895fa0405SHaiyang Zhang 35995fa0405SHaiyang Zhang rndis_pkt = &msg->msg.pkt; 36095fa0405SHaiyang Zhang 36195fa0405SHaiyang Zhang /* Remove the rndis header and pass it back up the stack */ 36295fa0405SHaiyang Zhang data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset; 36395fa0405SHaiyang Zhang 36495fa0405SHaiyang Zhang pkt->total_data_buflen -= data_offset; 3654b8a8bc9SWei Yongjun 3664b8a8bc9SWei Yongjun /* 3674b8a8bc9SWei Yongjun * Make sure we got a valid RNDIS message, now total_data_buflen 3684b8a8bc9SWei Yongjun * should be the data packet size plus the trailer padding size 3694b8a8bc9SWei Yongjun */ 3704b8a8bc9SWei Yongjun if (pkt->total_data_buflen < rndis_pkt->data_len) { 3714b8a8bc9SWei Yongjun netdev_err(dev->net_dev->ndev, "rndis message buffer " 3724b8a8bc9SWei Yongjun "overflow detected (got %u, min %u)" 3734b8a8bc9SWei Yongjun "...dropping this message!\n", 3744b8a8bc9SWei Yongjun pkt->total_data_buflen, rndis_pkt->data_len); 3754b8a8bc9SWei Yongjun return; 3764b8a8bc9SWei Yongjun } 3774b8a8bc9SWei Yongjun 3784b8a8bc9SWei Yongjun /* 3794b8a8bc9SWei Yongjun * Remove the rndis trailer padding from rndis packet message 3804b8a8bc9SWei Yongjun * rndis_pkt->data_len tell us the real data length, we only copy 3814b8a8bc9SWei Yongjun * the data packet to the stack, without the rndis trailer padding 3824b8a8bc9SWei Yongjun */ 3834b8a8bc9SWei Yongjun pkt->total_data_buflen = rndis_pkt->data_len; 38445326342SHaiyang Zhang pkt->data = (void *)((unsigned long)pkt->data + data_offset); 38595fa0405SHaiyang Zhang 3861f5f3a75SHaiyang Zhang vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO); 3871f5f3a75SHaiyang Zhang if (vlan) { 3881f5f3a75SHaiyang Zhang pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid | 3891f5f3a75SHaiyang Zhang (vlan->pri << VLAN_PRIO_SHIFT); 3901f5f3a75SHaiyang Zhang } else { 3911f5f3a75SHaiyang Zhang pkt->vlan_tci = 0; 3921f5f3a75SHaiyang Zhang } 3931f5f3a75SHaiyang Zhang 394e3d605edSKY Srinivasan csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO); 395e3d605edSKY Srinivasan netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info); 39695fa0405SHaiyang Zhang } 39795fa0405SHaiyang Zhang 39895fa0405SHaiyang Zhang int rndis_filter_receive(struct hv_device *dev, 39995fa0405SHaiyang Zhang struct hv_netvsc_packet *pkt) 40095fa0405SHaiyang Zhang { 40195fa0405SHaiyang Zhang struct netvsc_device *net_dev = hv_get_drvdata(dev); 40295fa0405SHaiyang Zhang struct rndis_device *rndis_dev; 403ef31bef6SHaiyang Zhang struct rndis_message *rndis_msg; 40495fa0405SHaiyang Zhang struct net_device *ndev; 40563f6921dSHaiyang Zhang int ret = 0; 40695fa0405SHaiyang Zhang 40763f6921dSHaiyang Zhang if (!net_dev) { 40863f6921dSHaiyang Zhang ret = -EINVAL; 40963f6921dSHaiyang Zhang goto exit; 41063f6921dSHaiyang Zhang } 41195fa0405SHaiyang Zhang 41295fa0405SHaiyang Zhang ndev = net_dev->ndev; 41395fa0405SHaiyang Zhang 41495fa0405SHaiyang Zhang /* Make sure the rndis device state is initialized */ 41595fa0405SHaiyang Zhang if (!net_dev->extension) { 41695fa0405SHaiyang Zhang netdev_err(ndev, "got rndis message but no rndis device - " 41795fa0405SHaiyang Zhang "dropping this message!\n"); 41863f6921dSHaiyang Zhang ret = -ENODEV; 41963f6921dSHaiyang Zhang goto exit; 42095fa0405SHaiyang Zhang } 42195fa0405SHaiyang Zhang 42295fa0405SHaiyang Zhang rndis_dev = (struct rndis_device *)net_dev->extension; 42395fa0405SHaiyang Zhang if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { 42495fa0405SHaiyang Zhang netdev_err(ndev, "got rndis message but rndis device " 42595fa0405SHaiyang Zhang "uninitialized...dropping this message!\n"); 42663f6921dSHaiyang Zhang ret = -ENODEV; 42763f6921dSHaiyang Zhang goto exit; 42895fa0405SHaiyang Zhang } 42995fa0405SHaiyang Zhang 430ef31bef6SHaiyang Zhang rndis_msg = pkt->data; 43195fa0405SHaiyang Zhang 432ef31bef6SHaiyang Zhang dump_rndis_message(dev, rndis_msg); 43395fa0405SHaiyang Zhang 434ef31bef6SHaiyang Zhang switch (rndis_msg->ndis_msg_type) { 43551491167SLinus Walleij case RNDIS_MSG_PACKET: 43695fa0405SHaiyang Zhang /* data msg */ 437ef31bef6SHaiyang Zhang rndis_filter_receive_data(rndis_dev, rndis_msg, pkt); 43895fa0405SHaiyang Zhang break; 43995fa0405SHaiyang Zhang 44051491167SLinus Walleij case RNDIS_MSG_INIT_C: 44151491167SLinus Walleij case RNDIS_MSG_QUERY_C: 44251491167SLinus Walleij case RNDIS_MSG_SET_C: 44395fa0405SHaiyang Zhang /* completion msgs */ 444ef31bef6SHaiyang Zhang rndis_filter_receive_response(rndis_dev, rndis_msg); 44595fa0405SHaiyang Zhang break; 44695fa0405SHaiyang Zhang 44751491167SLinus Walleij case RNDIS_MSG_INDICATE: 44895fa0405SHaiyang Zhang /* notification msgs */ 4493a494e71SHaiyang Zhang netvsc_linkstatus_callback(dev, rndis_msg); 45095fa0405SHaiyang Zhang break; 45195fa0405SHaiyang Zhang default: 45295fa0405SHaiyang Zhang netdev_err(ndev, 45395fa0405SHaiyang Zhang "unhandled rndis message (type %u len %u)\n", 454ef31bef6SHaiyang Zhang rndis_msg->ndis_msg_type, 455ef31bef6SHaiyang Zhang rndis_msg->msg_len); 45695fa0405SHaiyang Zhang break; 45795fa0405SHaiyang Zhang } 45895fa0405SHaiyang Zhang 45963f6921dSHaiyang Zhang exit: 46063f6921dSHaiyang Zhang if (ret != 0) 46163f6921dSHaiyang Zhang pkt->status = NVSP_STAT_FAIL; 46263f6921dSHaiyang Zhang 46363f6921dSHaiyang Zhang return ret; 46495fa0405SHaiyang Zhang } 46595fa0405SHaiyang Zhang 46695fa0405SHaiyang Zhang static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, 46795fa0405SHaiyang Zhang void *result, u32 *result_size) 46895fa0405SHaiyang Zhang { 46995fa0405SHaiyang Zhang struct rndis_request *request; 47095fa0405SHaiyang Zhang u32 inresult_size = *result_size; 47195fa0405SHaiyang Zhang struct rndis_query_request *query; 47295fa0405SHaiyang Zhang struct rndis_query_complete *query_complete; 47395fa0405SHaiyang Zhang int ret = 0; 474999028ccSNicholas Mc Guire unsigned long t; 47595fa0405SHaiyang Zhang 47695fa0405SHaiyang Zhang if (!result) 47795fa0405SHaiyang Zhang return -EINVAL; 47895fa0405SHaiyang Zhang 47995fa0405SHaiyang Zhang *result_size = 0; 48051491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_QUERY, 48195fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_query_request)); 48295fa0405SHaiyang Zhang if (!request) { 48395fa0405SHaiyang Zhang ret = -ENOMEM; 48495fa0405SHaiyang Zhang goto cleanup; 48595fa0405SHaiyang Zhang } 48695fa0405SHaiyang Zhang 48795fa0405SHaiyang Zhang /* Setup the rndis query */ 48895fa0405SHaiyang Zhang query = &request->request_msg.msg.query_req; 48995fa0405SHaiyang Zhang query->oid = oid; 49095fa0405SHaiyang Zhang query->info_buf_offset = sizeof(struct rndis_query_request); 49195fa0405SHaiyang Zhang query->info_buflen = 0; 49295fa0405SHaiyang Zhang query->dev_vc_handle = 0; 49395fa0405SHaiyang Zhang 4945b54dac8SHaiyang Zhang if (oid == OID_GEN_RECEIVE_SCALE_CAPABILITIES) { 4955b54dac8SHaiyang Zhang struct ndis_recv_scale_cap *cap; 4965b54dac8SHaiyang Zhang 4975b54dac8SHaiyang Zhang request->request_msg.msg_len += 4985b54dac8SHaiyang Zhang sizeof(struct ndis_recv_scale_cap); 4995b54dac8SHaiyang Zhang query->info_buflen = sizeof(struct ndis_recv_scale_cap); 5005b54dac8SHaiyang Zhang cap = (struct ndis_recv_scale_cap *)((unsigned long)query + 5015b54dac8SHaiyang Zhang query->info_buf_offset); 5025b54dac8SHaiyang Zhang cap->hdr.type = NDIS_OBJECT_TYPE_RSS_CAPABILITIES; 5035b54dac8SHaiyang Zhang cap->hdr.rev = NDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2; 5045b54dac8SHaiyang Zhang cap->hdr.size = sizeof(struct ndis_recv_scale_cap); 5055b54dac8SHaiyang Zhang } 5065b54dac8SHaiyang Zhang 50795fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 50895fa0405SHaiyang Zhang if (ret != 0) 50995fa0405SHaiyang Zhang goto cleanup; 51095fa0405SHaiyang Zhang 51195fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 51295fa0405SHaiyang Zhang if (t == 0) { 51395fa0405SHaiyang Zhang ret = -ETIMEDOUT; 51495fa0405SHaiyang Zhang goto cleanup; 51595fa0405SHaiyang Zhang } 51695fa0405SHaiyang Zhang 51795fa0405SHaiyang Zhang /* Copy the response back */ 51895fa0405SHaiyang Zhang query_complete = &request->response_msg.msg.query_complete; 51995fa0405SHaiyang Zhang 52095fa0405SHaiyang Zhang if (query_complete->info_buflen > inresult_size) { 52195fa0405SHaiyang Zhang ret = -1; 52295fa0405SHaiyang Zhang goto cleanup; 52395fa0405SHaiyang Zhang } 52495fa0405SHaiyang Zhang 52595fa0405SHaiyang Zhang memcpy(result, 52695fa0405SHaiyang Zhang (void *)((unsigned long)query_complete + 52795fa0405SHaiyang Zhang query_complete->info_buf_offset), 52895fa0405SHaiyang Zhang query_complete->info_buflen); 52995fa0405SHaiyang Zhang 53095fa0405SHaiyang Zhang *result_size = query_complete->info_buflen; 53195fa0405SHaiyang Zhang 53295fa0405SHaiyang Zhang cleanup: 53395fa0405SHaiyang Zhang if (request) 53495fa0405SHaiyang Zhang put_rndis_request(dev, request); 53595fa0405SHaiyang Zhang 53695fa0405SHaiyang Zhang return ret; 53795fa0405SHaiyang Zhang } 53895fa0405SHaiyang Zhang 53995fa0405SHaiyang Zhang static int rndis_filter_query_device_mac(struct rndis_device *dev) 54095fa0405SHaiyang Zhang { 54195fa0405SHaiyang Zhang u32 size = ETH_ALEN; 54295fa0405SHaiyang Zhang 54395fa0405SHaiyang Zhang return rndis_filter_query_device(dev, 54495fa0405SHaiyang Zhang RNDIS_OID_802_3_PERMANENT_ADDRESS, 54595fa0405SHaiyang Zhang dev->hw_mac_adr, &size); 54695fa0405SHaiyang Zhang } 54795fa0405SHaiyang Zhang 5481ce09e89SHaiyang Zhang #define NWADR_STR "NetworkAddress" 5491ce09e89SHaiyang Zhang #define NWADR_STRLEN 14 5501ce09e89SHaiyang Zhang 5511ce09e89SHaiyang Zhang int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac) 5521ce09e89SHaiyang Zhang { 5531ce09e89SHaiyang Zhang struct netvsc_device *nvdev = hv_get_drvdata(hdev); 5541ce09e89SHaiyang Zhang struct rndis_device *rdev = nvdev->extension; 5551ce09e89SHaiyang Zhang struct net_device *ndev = nvdev->ndev; 5561ce09e89SHaiyang Zhang struct rndis_request *request; 5571ce09e89SHaiyang Zhang struct rndis_set_request *set; 5581ce09e89SHaiyang Zhang struct rndis_config_parameter_info *cpi; 5591ce09e89SHaiyang Zhang wchar_t *cfg_nwadr, *cfg_mac; 5601ce09e89SHaiyang Zhang struct rndis_set_complete *set_complete; 5611ce09e89SHaiyang Zhang char macstr[2*ETH_ALEN+1]; 5621ce09e89SHaiyang Zhang u32 extlen = sizeof(struct rndis_config_parameter_info) + 5631ce09e89SHaiyang Zhang 2*NWADR_STRLEN + 4*ETH_ALEN; 564999028ccSNicholas Mc Guire int ret; 565999028ccSNicholas Mc Guire unsigned long t; 5661ce09e89SHaiyang Zhang 5671ce09e89SHaiyang Zhang request = get_rndis_request(rdev, RNDIS_MSG_SET, 5681ce09e89SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); 5691ce09e89SHaiyang Zhang if (!request) 5701ce09e89SHaiyang Zhang return -ENOMEM; 5711ce09e89SHaiyang Zhang 5721ce09e89SHaiyang Zhang set = &request->request_msg.msg.set_req; 5731ce09e89SHaiyang Zhang set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER; 5741ce09e89SHaiyang Zhang set->info_buflen = extlen; 5751ce09e89SHaiyang Zhang set->info_buf_offset = sizeof(struct rndis_set_request); 5761ce09e89SHaiyang Zhang set->dev_vc_handle = 0; 5771ce09e89SHaiyang Zhang 5781ce09e89SHaiyang Zhang cpi = (struct rndis_config_parameter_info *)((ulong)set + 5791ce09e89SHaiyang Zhang set->info_buf_offset); 5801ce09e89SHaiyang Zhang cpi->parameter_name_offset = 5811ce09e89SHaiyang Zhang sizeof(struct rndis_config_parameter_info); 5821ce09e89SHaiyang Zhang /* Multiply by 2 because host needs 2 bytes (utf16) for each char */ 5831ce09e89SHaiyang Zhang cpi->parameter_name_length = 2*NWADR_STRLEN; 5841ce09e89SHaiyang Zhang cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING; 5851ce09e89SHaiyang Zhang cpi->parameter_value_offset = 5861ce09e89SHaiyang Zhang cpi->parameter_name_offset + cpi->parameter_name_length; 5871ce09e89SHaiyang Zhang /* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */ 5881ce09e89SHaiyang Zhang cpi->parameter_value_length = 4*ETH_ALEN; 5891ce09e89SHaiyang Zhang 5901ce09e89SHaiyang Zhang cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset); 5911ce09e89SHaiyang Zhang cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset); 5921ce09e89SHaiyang Zhang ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN, 5931ce09e89SHaiyang Zhang cfg_nwadr, NWADR_STRLEN); 5941ce09e89SHaiyang Zhang if (ret < 0) 5951ce09e89SHaiyang Zhang goto cleanup; 5961ce09e89SHaiyang Zhang snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac); 5971ce09e89SHaiyang Zhang ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN, 5981ce09e89SHaiyang Zhang cfg_mac, 2*ETH_ALEN); 5991ce09e89SHaiyang Zhang if (ret < 0) 6001ce09e89SHaiyang Zhang goto cleanup; 6011ce09e89SHaiyang Zhang 6021ce09e89SHaiyang Zhang ret = rndis_filter_send_request(rdev, request); 6031ce09e89SHaiyang Zhang if (ret != 0) 6041ce09e89SHaiyang Zhang goto cleanup; 6051ce09e89SHaiyang Zhang 6061ce09e89SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 6071ce09e89SHaiyang Zhang if (t == 0) { 6081ce09e89SHaiyang Zhang netdev_err(ndev, "timeout before we got a set response...\n"); 6091ce09e89SHaiyang Zhang /* 6101ce09e89SHaiyang Zhang * can't put_rndis_request, since we may still receive a 6111ce09e89SHaiyang Zhang * send-completion. 6121ce09e89SHaiyang Zhang */ 6131ce09e89SHaiyang Zhang return -EBUSY; 6141ce09e89SHaiyang Zhang } else { 6151ce09e89SHaiyang Zhang set_complete = &request->response_msg.msg.set_complete; 616b02a8067SHaiyang Zhang if (set_complete->status != RNDIS_STATUS_SUCCESS) { 617b02a8067SHaiyang Zhang netdev_err(ndev, "Fail to set MAC on host side:0x%x\n", 618b02a8067SHaiyang Zhang set_complete->status); 6191ce09e89SHaiyang Zhang ret = -EINVAL; 6201ce09e89SHaiyang Zhang } 621b02a8067SHaiyang Zhang } 6221ce09e89SHaiyang Zhang 6231ce09e89SHaiyang Zhang cleanup: 6241ce09e89SHaiyang Zhang put_rndis_request(rdev, request); 6251ce09e89SHaiyang Zhang return ret; 6261ce09e89SHaiyang Zhang } 6271ce09e89SHaiyang Zhang 628da19fcd0SLad, Prabhakar static int 629da19fcd0SLad, Prabhakar rndis_filter_set_offload_params(struct hv_device *hdev, 6304a0e70aeSKY Srinivasan struct ndis_offload_params *req_offloads) 6314a0e70aeSKY Srinivasan { 6324a0e70aeSKY Srinivasan struct netvsc_device *nvdev = hv_get_drvdata(hdev); 6334a0e70aeSKY Srinivasan struct rndis_device *rdev = nvdev->extension; 6344a0e70aeSKY Srinivasan struct net_device *ndev = nvdev->ndev; 6354a0e70aeSKY Srinivasan struct rndis_request *request; 6364a0e70aeSKY Srinivasan struct rndis_set_request *set; 6374a0e70aeSKY Srinivasan struct ndis_offload_params *offload_params; 6384a0e70aeSKY Srinivasan struct rndis_set_complete *set_complete; 6394a0e70aeSKY Srinivasan u32 extlen = sizeof(struct ndis_offload_params); 640999028ccSNicholas Mc Guire int ret; 641999028ccSNicholas Mc Guire unsigned long t; 642af9893a3SKY Srinivasan u32 vsp_version = nvdev->nvsp_version; 643af9893a3SKY Srinivasan 644af9893a3SKY Srinivasan if (vsp_version <= NVSP_PROTOCOL_VERSION_4) { 645af9893a3SKY Srinivasan extlen = VERSION_4_OFFLOAD_SIZE; 646af9893a3SKY Srinivasan /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support 647af9893a3SKY Srinivasan * UDP checksum offload. 648af9893a3SKY Srinivasan */ 649af9893a3SKY Srinivasan req_offloads->udp_ip_v4_csum = 0; 650af9893a3SKY Srinivasan req_offloads->udp_ip_v6_csum = 0; 651af9893a3SKY Srinivasan } 6524a0e70aeSKY Srinivasan 6534a0e70aeSKY Srinivasan request = get_rndis_request(rdev, RNDIS_MSG_SET, 6544a0e70aeSKY Srinivasan RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); 6554a0e70aeSKY Srinivasan if (!request) 6564a0e70aeSKY Srinivasan return -ENOMEM; 6574a0e70aeSKY Srinivasan 6584a0e70aeSKY Srinivasan set = &request->request_msg.msg.set_req; 6594a0e70aeSKY Srinivasan set->oid = OID_TCP_OFFLOAD_PARAMETERS; 6604a0e70aeSKY Srinivasan set->info_buflen = extlen; 6614a0e70aeSKY Srinivasan set->info_buf_offset = sizeof(struct rndis_set_request); 6624a0e70aeSKY Srinivasan set->dev_vc_handle = 0; 6634a0e70aeSKY Srinivasan 6644a0e70aeSKY Srinivasan offload_params = (struct ndis_offload_params *)((ulong)set + 6654a0e70aeSKY Srinivasan set->info_buf_offset); 6664a0e70aeSKY Srinivasan *offload_params = *req_offloads; 6674a0e70aeSKY Srinivasan offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT; 6684a0e70aeSKY Srinivasan offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3; 6694a0e70aeSKY Srinivasan offload_params->header.size = extlen; 6704a0e70aeSKY Srinivasan 6714a0e70aeSKY Srinivasan ret = rndis_filter_send_request(rdev, request); 6724a0e70aeSKY Srinivasan if (ret != 0) 6734a0e70aeSKY Srinivasan goto cleanup; 6744a0e70aeSKY Srinivasan 6754a0e70aeSKY Srinivasan t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 6764a0e70aeSKY Srinivasan if (t == 0) { 6774a0e70aeSKY Srinivasan netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n"); 6784a0e70aeSKY Srinivasan /* can't put_rndis_request, since we may still receive a 6794a0e70aeSKY Srinivasan * send-completion. 6804a0e70aeSKY Srinivasan */ 6814a0e70aeSKY Srinivasan return -EBUSY; 6824a0e70aeSKY Srinivasan } else { 6834a0e70aeSKY Srinivasan set_complete = &request->response_msg.msg.set_complete; 6844a0e70aeSKY Srinivasan if (set_complete->status != RNDIS_STATUS_SUCCESS) { 685af9893a3SKY Srinivasan netdev_err(ndev, "Fail to set offload on host side:0x%x\n", 6864a0e70aeSKY Srinivasan set_complete->status); 6874a0e70aeSKY Srinivasan ret = -EINVAL; 6884a0e70aeSKY Srinivasan } 6894a0e70aeSKY Srinivasan } 6904a0e70aeSKY Srinivasan 6914a0e70aeSKY Srinivasan cleanup: 6924a0e70aeSKY Srinivasan put_rndis_request(rdev, request); 6934a0e70aeSKY Srinivasan return ret; 6944a0e70aeSKY Srinivasan } 6951ce09e89SHaiyang Zhang 6965b54dac8SHaiyang Zhang u8 netvsc_hash_key[HASH_KEYLEN] = { 6975b54dac8SHaiyang Zhang 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 6985b54dac8SHaiyang Zhang 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 6995b54dac8SHaiyang Zhang 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 7005b54dac8SHaiyang Zhang 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 7015b54dac8SHaiyang Zhang 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa 7025b54dac8SHaiyang Zhang }; 7035b54dac8SHaiyang Zhang 704da19fcd0SLad, Prabhakar static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue) 7055b54dac8SHaiyang Zhang { 7065b54dac8SHaiyang Zhang struct net_device *ndev = rdev->net_dev->ndev; 7075b54dac8SHaiyang Zhang struct rndis_request *request; 7085b54dac8SHaiyang Zhang struct rndis_set_request *set; 7095b54dac8SHaiyang Zhang struct rndis_set_complete *set_complete; 7105b54dac8SHaiyang Zhang u32 extlen = sizeof(struct ndis_recv_scale_param) + 7115b54dac8SHaiyang Zhang 4*ITAB_NUM + HASH_KEYLEN; 7125b54dac8SHaiyang Zhang struct ndis_recv_scale_param *rssp; 7135b54dac8SHaiyang Zhang u32 *itab; 7145b54dac8SHaiyang Zhang u8 *keyp; 715999028ccSNicholas Mc Guire int i, ret; 716999028ccSNicholas Mc Guire unsigned long t; 7175b54dac8SHaiyang Zhang 7185b54dac8SHaiyang Zhang request = get_rndis_request( 7195b54dac8SHaiyang Zhang rdev, RNDIS_MSG_SET, 7205b54dac8SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); 7215b54dac8SHaiyang Zhang if (!request) 7225b54dac8SHaiyang Zhang return -ENOMEM; 7235b54dac8SHaiyang Zhang 7245b54dac8SHaiyang Zhang set = &request->request_msg.msg.set_req; 7255b54dac8SHaiyang Zhang set->oid = OID_GEN_RECEIVE_SCALE_PARAMETERS; 7265b54dac8SHaiyang Zhang set->info_buflen = extlen; 7275b54dac8SHaiyang Zhang set->info_buf_offset = sizeof(struct rndis_set_request); 7285b54dac8SHaiyang Zhang set->dev_vc_handle = 0; 7295b54dac8SHaiyang Zhang 7305b54dac8SHaiyang Zhang rssp = (struct ndis_recv_scale_param *)(set + 1); 7315b54dac8SHaiyang Zhang rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS; 7325b54dac8SHaiyang Zhang rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2; 7335b54dac8SHaiyang Zhang rssp->hdr.size = sizeof(struct ndis_recv_scale_param); 7345b54dac8SHaiyang Zhang rssp->flag = 0; 7355b54dac8SHaiyang Zhang rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 | 7364c87454aSHaiyang Zhang NDIS_HASH_TCP_IPV4 | NDIS_HASH_IPV6 | 7374c87454aSHaiyang Zhang NDIS_HASH_TCP_IPV6; 7385b54dac8SHaiyang Zhang rssp->indirect_tabsize = 4*ITAB_NUM; 7395b54dac8SHaiyang Zhang rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param); 7405b54dac8SHaiyang Zhang rssp->hashkey_size = HASH_KEYLEN; 7415b54dac8SHaiyang Zhang rssp->kashkey_offset = rssp->indirect_taboffset + 7425b54dac8SHaiyang Zhang rssp->indirect_tabsize; 7435b54dac8SHaiyang Zhang 7445b54dac8SHaiyang Zhang /* Set indirection table entries */ 7455b54dac8SHaiyang Zhang itab = (u32 *)(rssp + 1); 7465b54dac8SHaiyang Zhang for (i = 0; i < ITAB_NUM; i++) 7475b54dac8SHaiyang Zhang itab[i] = i % num_queue; 7485b54dac8SHaiyang Zhang 7495b54dac8SHaiyang Zhang /* Set hask key values */ 7505b54dac8SHaiyang Zhang keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset); 7515b54dac8SHaiyang Zhang for (i = 0; i < HASH_KEYLEN; i++) 7525b54dac8SHaiyang Zhang keyp[i] = netvsc_hash_key[i]; 7535b54dac8SHaiyang Zhang 7545b54dac8SHaiyang Zhang 7555b54dac8SHaiyang Zhang ret = rndis_filter_send_request(rdev, request); 7565b54dac8SHaiyang Zhang if (ret != 0) 7575b54dac8SHaiyang Zhang goto cleanup; 7585b54dac8SHaiyang Zhang 7595b54dac8SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 7605b54dac8SHaiyang Zhang if (t == 0) { 7615b54dac8SHaiyang Zhang netdev_err(ndev, "timeout before we got a set response...\n"); 7625b54dac8SHaiyang Zhang /* can't put_rndis_request, since we may still receive a 7635b54dac8SHaiyang Zhang * send-completion. 7645b54dac8SHaiyang Zhang */ 7655b54dac8SHaiyang Zhang return -ETIMEDOUT; 7665b54dac8SHaiyang Zhang } else { 7675b54dac8SHaiyang Zhang set_complete = &request->response_msg.msg.set_complete; 7685b54dac8SHaiyang Zhang if (set_complete->status != RNDIS_STATUS_SUCCESS) { 7695b54dac8SHaiyang Zhang netdev_err(ndev, "Fail to set RSS parameters:0x%x\n", 7705b54dac8SHaiyang Zhang set_complete->status); 7715b54dac8SHaiyang Zhang ret = -EINVAL; 7725b54dac8SHaiyang Zhang } 7735b54dac8SHaiyang Zhang } 7745b54dac8SHaiyang Zhang 7755b54dac8SHaiyang Zhang cleanup: 7765b54dac8SHaiyang Zhang put_rndis_request(rdev, request); 7775b54dac8SHaiyang Zhang return ret; 7785b54dac8SHaiyang Zhang } 7795b54dac8SHaiyang Zhang 7805b54dac8SHaiyang Zhang 78195fa0405SHaiyang Zhang static int rndis_filter_query_device_link_status(struct rndis_device *dev) 78295fa0405SHaiyang Zhang { 78395fa0405SHaiyang Zhang u32 size = sizeof(u32); 78495fa0405SHaiyang Zhang u32 link_status; 78595fa0405SHaiyang Zhang int ret; 78695fa0405SHaiyang Zhang 78795fa0405SHaiyang Zhang ret = rndis_filter_query_device(dev, 78895fa0405SHaiyang Zhang RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, 78995fa0405SHaiyang Zhang &link_status, &size); 79095fa0405SHaiyang Zhang 79195fa0405SHaiyang Zhang return ret; 79295fa0405SHaiyang Zhang } 79395fa0405SHaiyang Zhang 794d426b2e3SHaiyang Zhang int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) 79595fa0405SHaiyang Zhang { 79695fa0405SHaiyang Zhang struct rndis_request *request; 79795fa0405SHaiyang Zhang struct rndis_set_request *set; 79895fa0405SHaiyang Zhang struct rndis_set_complete *set_complete; 79995fa0405SHaiyang Zhang u32 status; 800999028ccSNicholas Mc Guire int ret; 801999028ccSNicholas Mc Guire unsigned long t; 80295fa0405SHaiyang Zhang struct net_device *ndev; 80395fa0405SHaiyang Zhang 80495fa0405SHaiyang Zhang ndev = dev->net_dev->ndev; 80595fa0405SHaiyang Zhang 80651491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_SET, 80795fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_set_request) + 80895fa0405SHaiyang Zhang sizeof(u32)); 80995fa0405SHaiyang Zhang if (!request) { 81095fa0405SHaiyang Zhang ret = -ENOMEM; 81195fa0405SHaiyang Zhang goto cleanup; 81295fa0405SHaiyang Zhang } 81395fa0405SHaiyang Zhang 81495fa0405SHaiyang Zhang /* Setup the rndis set */ 81595fa0405SHaiyang Zhang set = &request->request_msg.msg.set_req; 81695fa0405SHaiyang Zhang set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; 81795fa0405SHaiyang Zhang set->info_buflen = sizeof(u32); 81895fa0405SHaiyang Zhang set->info_buf_offset = sizeof(struct rndis_set_request); 81995fa0405SHaiyang Zhang 82095fa0405SHaiyang Zhang memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), 82195fa0405SHaiyang Zhang &new_filter, sizeof(u32)); 82295fa0405SHaiyang Zhang 82395fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 82495fa0405SHaiyang Zhang if (ret != 0) 82595fa0405SHaiyang Zhang goto cleanup; 82695fa0405SHaiyang Zhang 82795fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 82895fa0405SHaiyang Zhang 82995fa0405SHaiyang Zhang if (t == 0) { 83095fa0405SHaiyang Zhang netdev_err(ndev, 83195fa0405SHaiyang Zhang "timeout before we got a set response...\n"); 832ea496374SHaiyang Zhang ret = -ETIMEDOUT; 83395fa0405SHaiyang Zhang /* 83495fa0405SHaiyang Zhang * We can't deallocate the request since we may still receive a 83595fa0405SHaiyang Zhang * send completion for it. 83695fa0405SHaiyang Zhang */ 83795fa0405SHaiyang Zhang goto exit; 83895fa0405SHaiyang Zhang } else { 83995fa0405SHaiyang Zhang set_complete = &request->response_msg.msg.set_complete; 84095fa0405SHaiyang Zhang status = set_complete->status; 84195fa0405SHaiyang Zhang } 84295fa0405SHaiyang Zhang 84395fa0405SHaiyang Zhang cleanup: 84495fa0405SHaiyang Zhang if (request) 84595fa0405SHaiyang Zhang put_rndis_request(dev, request); 84695fa0405SHaiyang Zhang exit: 84795fa0405SHaiyang Zhang return ret; 84895fa0405SHaiyang Zhang } 84995fa0405SHaiyang Zhang 85095fa0405SHaiyang Zhang 85195fa0405SHaiyang Zhang static int rndis_filter_init_device(struct rndis_device *dev) 85295fa0405SHaiyang Zhang { 85395fa0405SHaiyang Zhang struct rndis_request *request; 85495fa0405SHaiyang Zhang struct rndis_initialize_request *init; 85595fa0405SHaiyang Zhang struct rndis_initialize_complete *init_complete; 85695fa0405SHaiyang Zhang u32 status; 857999028ccSNicholas Mc Guire int ret; 858999028ccSNicholas Mc Guire unsigned long t; 8597c3877f2SHaiyang Zhang struct netvsc_device *nvdev = dev->net_dev; 86095fa0405SHaiyang Zhang 86151491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_INIT, 86295fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); 86395fa0405SHaiyang Zhang if (!request) { 86495fa0405SHaiyang Zhang ret = -ENOMEM; 86595fa0405SHaiyang Zhang goto cleanup; 86695fa0405SHaiyang Zhang } 86795fa0405SHaiyang Zhang 86895fa0405SHaiyang Zhang /* Setup the rndis set */ 86995fa0405SHaiyang Zhang init = &request->request_msg.msg.init_req; 87095fa0405SHaiyang Zhang init->major_ver = RNDIS_MAJOR_VERSION; 87195fa0405SHaiyang Zhang init->minor_ver = RNDIS_MINOR_VERSION; 872fb1d074eSHaiyang Zhang init->max_xfer_size = 0x4000; 87395fa0405SHaiyang Zhang 87495fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZING; 87595fa0405SHaiyang Zhang 87695fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 87795fa0405SHaiyang Zhang if (ret != 0) { 87895fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 87995fa0405SHaiyang Zhang goto cleanup; 88095fa0405SHaiyang Zhang } 88195fa0405SHaiyang Zhang 88295fa0405SHaiyang Zhang 88395fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 88495fa0405SHaiyang Zhang 88595fa0405SHaiyang Zhang if (t == 0) { 88695fa0405SHaiyang Zhang ret = -ETIMEDOUT; 88795fa0405SHaiyang Zhang goto cleanup; 88895fa0405SHaiyang Zhang } 88995fa0405SHaiyang Zhang 89095fa0405SHaiyang Zhang init_complete = &request->response_msg.msg.init_complete; 89195fa0405SHaiyang Zhang status = init_complete->status; 89295fa0405SHaiyang Zhang if (status == RNDIS_STATUS_SUCCESS) { 89395fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZED; 8947c3877f2SHaiyang Zhang nvdev->max_pkt = init_complete->max_pkt_per_msg; 8957c3877f2SHaiyang Zhang nvdev->pkt_align = 1 << init_complete->pkt_alignment_factor; 89695fa0405SHaiyang Zhang ret = 0; 89795fa0405SHaiyang Zhang } else { 89895fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 89995fa0405SHaiyang Zhang ret = -EINVAL; 90095fa0405SHaiyang Zhang } 90195fa0405SHaiyang Zhang 90295fa0405SHaiyang Zhang cleanup: 90395fa0405SHaiyang Zhang if (request) 90495fa0405SHaiyang Zhang put_rndis_request(dev, request); 90595fa0405SHaiyang Zhang 90695fa0405SHaiyang Zhang return ret; 90795fa0405SHaiyang Zhang } 90895fa0405SHaiyang Zhang 90995fa0405SHaiyang Zhang static void rndis_filter_halt_device(struct rndis_device *dev) 91095fa0405SHaiyang Zhang { 91195fa0405SHaiyang Zhang struct rndis_request *request; 91295fa0405SHaiyang Zhang struct rndis_halt_request *halt; 913ae9e63bbSHaiyang Zhang struct netvsc_device *nvdev = dev->net_dev; 914ae9e63bbSHaiyang Zhang struct hv_device *hdev = nvdev->dev; 915ae9e63bbSHaiyang Zhang ulong flags; 91695fa0405SHaiyang Zhang 91795fa0405SHaiyang Zhang /* Attempt to do a rndis device halt */ 91851491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_HALT, 91995fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); 92095fa0405SHaiyang Zhang if (!request) 92195fa0405SHaiyang Zhang goto cleanup; 92295fa0405SHaiyang Zhang 92395fa0405SHaiyang Zhang /* Setup the rndis set */ 92495fa0405SHaiyang Zhang halt = &request->request_msg.msg.halt_req; 92595fa0405SHaiyang Zhang halt->req_id = atomic_inc_return(&dev->new_req_id); 92695fa0405SHaiyang Zhang 92795fa0405SHaiyang Zhang /* Ignore return since this msg is optional. */ 92895fa0405SHaiyang Zhang rndis_filter_send_request(dev, request); 92995fa0405SHaiyang Zhang 93095fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 93195fa0405SHaiyang Zhang 93295fa0405SHaiyang Zhang cleanup: 933ae9e63bbSHaiyang Zhang spin_lock_irqsave(&hdev->channel->inbound_lock, flags); 934ae9e63bbSHaiyang Zhang nvdev->destroy = true; 935ae9e63bbSHaiyang Zhang spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags); 936ae9e63bbSHaiyang Zhang 937ae9e63bbSHaiyang Zhang /* Wait for all send completions */ 938ae9e63bbSHaiyang Zhang wait_event(nvdev->wait_drain, 939ae9e63bbSHaiyang Zhang atomic_read(&nvdev->num_outstanding_sends) == 0); 940ae9e63bbSHaiyang Zhang 94195fa0405SHaiyang Zhang if (request) 94295fa0405SHaiyang Zhang put_rndis_request(dev, request); 94395fa0405SHaiyang Zhang return; 94495fa0405SHaiyang Zhang } 94595fa0405SHaiyang Zhang 94695fa0405SHaiyang Zhang static int rndis_filter_open_device(struct rndis_device *dev) 94795fa0405SHaiyang Zhang { 94895fa0405SHaiyang Zhang int ret; 94995fa0405SHaiyang Zhang 95095fa0405SHaiyang Zhang if (dev->state != RNDIS_DEV_INITIALIZED) 95195fa0405SHaiyang Zhang return 0; 95295fa0405SHaiyang Zhang 95395fa0405SHaiyang Zhang ret = rndis_filter_set_packet_filter(dev, 95495fa0405SHaiyang Zhang NDIS_PACKET_TYPE_BROADCAST | 95595fa0405SHaiyang Zhang NDIS_PACKET_TYPE_ALL_MULTICAST | 95695fa0405SHaiyang Zhang NDIS_PACKET_TYPE_DIRECTED); 95795fa0405SHaiyang Zhang if (ret == 0) 95895fa0405SHaiyang Zhang dev->state = RNDIS_DEV_DATAINITIALIZED; 95995fa0405SHaiyang Zhang 96095fa0405SHaiyang Zhang return ret; 96195fa0405SHaiyang Zhang } 96295fa0405SHaiyang Zhang 96395fa0405SHaiyang Zhang static int rndis_filter_close_device(struct rndis_device *dev) 96495fa0405SHaiyang Zhang { 96595fa0405SHaiyang Zhang int ret; 96695fa0405SHaiyang Zhang 96795fa0405SHaiyang Zhang if (dev->state != RNDIS_DEV_DATAINITIALIZED) 96895fa0405SHaiyang Zhang return 0; 96995fa0405SHaiyang Zhang 97095fa0405SHaiyang Zhang ret = rndis_filter_set_packet_filter(dev, 0); 971c3582a2cSHaiyang Zhang if (ret == -ENODEV) 972c3582a2cSHaiyang Zhang ret = 0; 973c3582a2cSHaiyang Zhang 97495fa0405SHaiyang Zhang if (ret == 0) 97595fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZED; 97695fa0405SHaiyang Zhang 97795fa0405SHaiyang Zhang return ret; 97895fa0405SHaiyang Zhang } 97995fa0405SHaiyang Zhang 9805b54dac8SHaiyang Zhang static void netvsc_sc_open(struct vmbus_channel *new_sc) 9815b54dac8SHaiyang Zhang { 9825b54dac8SHaiyang Zhang struct netvsc_device *nvscdev; 9835b54dac8SHaiyang Zhang u16 chn_index = new_sc->offermsg.offer.sub_channel_index; 9845b54dac8SHaiyang Zhang int ret; 9855b54dac8SHaiyang Zhang 9865b54dac8SHaiyang Zhang nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj); 9875b54dac8SHaiyang Zhang 9885b54dac8SHaiyang Zhang if (chn_index >= nvscdev->num_chn) 9895b54dac8SHaiyang Zhang return; 9905b54dac8SHaiyang Zhang 9915b54dac8SHaiyang Zhang set_per_channel_state(new_sc, nvscdev->sub_cb_buf + (chn_index - 1) * 9925b54dac8SHaiyang Zhang NETVSC_PACKET_SIZE); 9935b54dac8SHaiyang Zhang 9945b54dac8SHaiyang Zhang ret = vmbus_open(new_sc, nvscdev->ring_size * PAGE_SIZE, 9955b54dac8SHaiyang Zhang nvscdev->ring_size * PAGE_SIZE, NULL, 0, 9965b54dac8SHaiyang Zhang netvsc_channel_cb, new_sc); 9975b54dac8SHaiyang Zhang 9985b54dac8SHaiyang Zhang if (ret == 0) 9995b54dac8SHaiyang Zhang nvscdev->chn_table[chn_index] = new_sc; 10005b54dac8SHaiyang Zhang } 10015b54dac8SHaiyang Zhang 100295fa0405SHaiyang Zhang int rndis_filter_device_add(struct hv_device *dev, 100395fa0405SHaiyang Zhang void *additional_info) 100495fa0405SHaiyang Zhang { 100595fa0405SHaiyang Zhang int ret; 100695fa0405SHaiyang Zhang struct netvsc_device *net_device; 100795fa0405SHaiyang Zhang struct rndis_device *rndis_device; 100895fa0405SHaiyang Zhang struct netvsc_device_info *device_info = additional_info; 10094a0e70aeSKY Srinivasan struct ndis_offload_params offloads; 10105b54dac8SHaiyang Zhang struct nvsp_message *init_packet; 1011999028ccSNicholas Mc Guire unsigned long t; 10125b54dac8SHaiyang Zhang struct ndis_recv_scale_cap rsscap; 10135b54dac8SHaiyang Zhang u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); 10144d3c9d37SHaiyang Zhang u32 mtu, size; 101595fa0405SHaiyang Zhang 101695fa0405SHaiyang Zhang rndis_device = get_rndis_device(); 101795fa0405SHaiyang Zhang if (!rndis_device) 101895fa0405SHaiyang Zhang return -ENODEV; 101995fa0405SHaiyang Zhang 102095fa0405SHaiyang Zhang /* 102195fa0405SHaiyang Zhang * Let the inner driver handle this first to create the netvsc channel 102295fa0405SHaiyang Zhang * NOTE! Once the channel is created, we may get a receive callback 102395fa0405SHaiyang Zhang * (RndisFilterOnReceive()) before this call is completed 102495fa0405SHaiyang Zhang */ 102595fa0405SHaiyang Zhang ret = netvsc_device_add(dev, additional_info); 102695fa0405SHaiyang Zhang if (ret != 0) { 102795fa0405SHaiyang Zhang kfree(rndis_device); 102895fa0405SHaiyang Zhang return ret; 102995fa0405SHaiyang Zhang } 103095fa0405SHaiyang Zhang 103195fa0405SHaiyang Zhang 103295fa0405SHaiyang Zhang /* Initialize the rndis device */ 103395fa0405SHaiyang Zhang net_device = hv_get_drvdata(dev); 103459995370SAndrew Schwartzmeyer net_device->max_chn = 1; 10355b54dac8SHaiyang Zhang net_device->num_chn = 1; 103695fa0405SHaiyang Zhang 103795fa0405SHaiyang Zhang net_device->extension = rndis_device; 103895fa0405SHaiyang Zhang rndis_device->net_dev = net_device; 103995fa0405SHaiyang Zhang 104095fa0405SHaiyang Zhang /* Send the rndis initialization message */ 104195fa0405SHaiyang Zhang ret = rndis_filter_init_device(rndis_device); 104295fa0405SHaiyang Zhang if (ret != 0) { 10435243e7bdSHaiyang Zhang rndis_filter_device_remove(dev); 10445243e7bdSHaiyang Zhang return ret; 104595fa0405SHaiyang Zhang } 104695fa0405SHaiyang Zhang 10474d3c9d37SHaiyang Zhang /* Get the MTU from the host */ 10484d3c9d37SHaiyang Zhang size = sizeof(u32); 10494d3c9d37SHaiyang Zhang ret = rndis_filter_query_device(rndis_device, 10504d3c9d37SHaiyang Zhang RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, 10514d3c9d37SHaiyang Zhang &mtu, &size); 10524d3c9d37SHaiyang Zhang if (ret == 0 && size == sizeof(u32)) 10534d3c9d37SHaiyang Zhang net_device->ndev->mtu = mtu; 10544d3c9d37SHaiyang Zhang 105595fa0405SHaiyang Zhang /* Get the mac address */ 105695fa0405SHaiyang Zhang ret = rndis_filter_query_device_mac(rndis_device); 105795fa0405SHaiyang Zhang if (ret != 0) { 10585243e7bdSHaiyang Zhang rndis_filter_device_remove(dev); 10595243e7bdSHaiyang Zhang return ret; 106095fa0405SHaiyang Zhang } 106195fa0405SHaiyang Zhang 106295fa0405SHaiyang Zhang memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); 106395fa0405SHaiyang Zhang 10644a0e70aeSKY Srinivasan /* Turn on the offloads; the host supports all of the relevant 10654a0e70aeSKY Srinivasan * offloads. 10664a0e70aeSKY Srinivasan */ 10674a0e70aeSKY Srinivasan memset(&offloads, 0, sizeof(struct ndis_offload_params)); 10684a0e70aeSKY Srinivasan /* A value of zero means "no change"; now turn on what we 10694a0e70aeSKY Srinivasan * want. 10704a0e70aeSKY Srinivasan */ 10714a0e70aeSKY Srinivasan offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; 10724a0e70aeSKY Srinivasan offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; 10734a0e70aeSKY Srinivasan offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; 10744a0e70aeSKY Srinivasan offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; 10754a0e70aeSKY Srinivasan offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; 10764a0e70aeSKY Srinivasan offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED; 10774a0e70aeSKY Srinivasan 10784a0e70aeSKY Srinivasan 10794a0e70aeSKY Srinivasan ret = rndis_filter_set_offload_params(dev, &offloads); 10804a0e70aeSKY Srinivasan if (ret) 10814a0e70aeSKY Srinivasan goto err_dev_remv; 10824a0e70aeSKY Srinivasan 108395fa0405SHaiyang Zhang rndis_filter_query_device_link_status(rndis_device); 108495fa0405SHaiyang Zhang 108595fa0405SHaiyang Zhang device_info->link_state = rndis_device->link_state; 108695fa0405SHaiyang Zhang 108795fa0405SHaiyang Zhang dev_info(&dev->device, "Device MAC %pM link state %s\n", 108895fa0405SHaiyang Zhang rndis_device->hw_mac_adr, 108995fa0405SHaiyang Zhang device_info->link_state ? "down" : "up"); 109095fa0405SHaiyang Zhang 10915b54dac8SHaiyang Zhang if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5) 10925b54dac8SHaiyang Zhang return 0; 10935b54dac8SHaiyang Zhang 10945b54dac8SHaiyang Zhang /* vRSS setup */ 10955b54dac8SHaiyang Zhang memset(&rsscap, 0, rsscap_size); 10965b54dac8SHaiyang Zhang ret = rndis_filter_query_device(rndis_device, 10975b54dac8SHaiyang Zhang OID_GEN_RECEIVE_SCALE_CAPABILITIES, 10985b54dac8SHaiyang Zhang &rsscap, &rsscap_size); 10995b54dac8SHaiyang Zhang if (ret || rsscap.num_recv_que < 2) 11005b54dac8SHaiyang Zhang goto out; 11015b54dac8SHaiyang Zhang 110259995370SAndrew Schwartzmeyer net_device->max_chn = rsscap.num_recv_que; 11035b54dac8SHaiyang Zhang net_device->num_chn = (num_online_cpus() < rsscap.num_recv_que) ? 11045b54dac8SHaiyang Zhang num_online_cpus() : rsscap.num_recv_que; 11055b54dac8SHaiyang Zhang if (net_device->num_chn == 1) 11065b54dac8SHaiyang Zhang goto out; 11075b54dac8SHaiyang Zhang 11085b54dac8SHaiyang Zhang net_device->sub_cb_buf = vzalloc((net_device->num_chn - 1) * 11095b54dac8SHaiyang Zhang NETVSC_PACKET_SIZE); 11105b54dac8SHaiyang Zhang if (!net_device->sub_cb_buf) { 11115b54dac8SHaiyang Zhang net_device->num_chn = 1; 11125b54dac8SHaiyang Zhang dev_info(&dev->device, "No memory for subchannels.\n"); 11135b54dac8SHaiyang Zhang goto out; 11145b54dac8SHaiyang Zhang } 11155b54dac8SHaiyang Zhang 11165b54dac8SHaiyang Zhang vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open); 11175b54dac8SHaiyang Zhang 11185b54dac8SHaiyang Zhang init_packet = &net_device->channel_init_pkt; 11195b54dac8SHaiyang Zhang memset(init_packet, 0, sizeof(struct nvsp_message)); 11205b54dac8SHaiyang Zhang init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL; 11215b54dac8SHaiyang Zhang init_packet->msg.v5_msg.subchn_req.op = NVSP_SUBCHANNEL_ALLOCATE; 11225b54dac8SHaiyang Zhang init_packet->msg.v5_msg.subchn_req.num_subchannels = 11235b54dac8SHaiyang Zhang net_device->num_chn - 1; 11245b54dac8SHaiyang Zhang ret = vmbus_sendpacket(dev->channel, init_packet, 11255b54dac8SHaiyang Zhang sizeof(struct nvsp_message), 11265b54dac8SHaiyang Zhang (unsigned long)init_packet, 11275b54dac8SHaiyang Zhang VM_PKT_DATA_INBAND, 11285b54dac8SHaiyang Zhang VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 11295b54dac8SHaiyang Zhang if (ret) 11305b54dac8SHaiyang Zhang goto out; 11315b54dac8SHaiyang Zhang t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); 11325b54dac8SHaiyang Zhang if (t == 0) { 11335b54dac8SHaiyang Zhang ret = -ETIMEDOUT; 11345b54dac8SHaiyang Zhang goto out; 11355b54dac8SHaiyang Zhang } 11365b54dac8SHaiyang Zhang if (init_packet->msg.v5_msg.subchn_comp.status != 11375b54dac8SHaiyang Zhang NVSP_STAT_SUCCESS) { 11385b54dac8SHaiyang Zhang ret = -ENODEV; 11395b54dac8SHaiyang Zhang goto out; 11405b54dac8SHaiyang Zhang } 11415b54dac8SHaiyang Zhang net_device->num_chn = 1 + 11425b54dac8SHaiyang Zhang init_packet->msg.v5_msg.subchn_comp.num_subchannels; 11435b54dac8SHaiyang Zhang 11445b54dac8SHaiyang Zhang vmbus_are_subchannels_present(dev->channel); 11455b54dac8SHaiyang Zhang 11465b54dac8SHaiyang Zhang ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn); 11475b54dac8SHaiyang Zhang 11485b54dac8SHaiyang Zhang out: 114959995370SAndrew Schwartzmeyer if (ret) { 115059995370SAndrew Schwartzmeyer net_device->max_chn = 1; 11515b54dac8SHaiyang Zhang net_device->num_chn = 1; 115259995370SAndrew Schwartzmeyer } 11535b54dac8SHaiyang Zhang return 0; /* return 0 because primary channel can be used alone */ 11544a0e70aeSKY Srinivasan 11554a0e70aeSKY Srinivasan err_dev_remv: 11564a0e70aeSKY Srinivasan rndis_filter_device_remove(dev); 11574a0e70aeSKY Srinivasan return ret; 115895fa0405SHaiyang Zhang } 115995fa0405SHaiyang Zhang 116095fa0405SHaiyang Zhang void rndis_filter_device_remove(struct hv_device *dev) 116195fa0405SHaiyang Zhang { 116295fa0405SHaiyang Zhang struct netvsc_device *net_dev = hv_get_drvdata(dev); 116395fa0405SHaiyang Zhang struct rndis_device *rndis_dev = net_dev->extension; 116495fa0405SHaiyang Zhang 116595fa0405SHaiyang Zhang /* Halt and release the rndis device */ 116695fa0405SHaiyang Zhang rndis_filter_halt_device(rndis_dev); 116795fa0405SHaiyang Zhang 116895fa0405SHaiyang Zhang kfree(rndis_dev); 116995fa0405SHaiyang Zhang net_dev->extension = NULL; 117095fa0405SHaiyang Zhang 117195fa0405SHaiyang Zhang netvsc_device_remove(dev); 117295fa0405SHaiyang Zhang } 117395fa0405SHaiyang Zhang 117495fa0405SHaiyang Zhang 117595fa0405SHaiyang Zhang int rndis_filter_open(struct hv_device *dev) 117695fa0405SHaiyang Zhang { 117795fa0405SHaiyang Zhang struct netvsc_device *net_device = hv_get_drvdata(dev); 117895fa0405SHaiyang Zhang 117995fa0405SHaiyang Zhang if (!net_device) 118095fa0405SHaiyang Zhang return -EINVAL; 118195fa0405SHaiyang Zhang 118295fa0405SHaiyang Zhang return rndis_filter_open_device(net_device->extension); 118395fa0405SHaiyang Zhang } 118495fa0405SHaiyang Zhang 118595fa0405SHaiyang Zhang int rndis_filter_close(struct hv_device *dev) 118695fa0405SHaiyang Zhang { 11875fccab3bSHaiyang Zhang struct netvsc_device *nvdev = hv_get_drvdata(dev); 118895fa0405SHaiyang Zhang 11895fccab3bSHaiyang Zhang if (!nvdev) 119095fa0405SHaiyang Zhang return -EINVAL; 119195fa0405SHaiyang Zhang 11925fccab3bSHaiyang Zhang return rndis_filter_close_device(nvdev->extension); 119395fa0405SHaiyang Zhang } 1194