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 6595fa0405SHaiyang Zhang static struct rndis_device *get_rndis_device(void) 6695fa0405SHaiyang Zhang { 6795fa0405SHaiyang Zhang struct rndis_device *device; 6895fa0405SHaiyang Zhang 6995fa0405SHaiyang Zhang device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL); 7095fa0405SHaiyang Zhang if (!device) 7195fa0405SHaiyang Zhang return NULL; 7295fa0405SHaiyang Zhang 7395fa0405SHaiyang Zhang spin_lock_init(&device->request_lock); 7495fa0405SHaiyang Zhang 7595fa0405SHaiyang Zhang INIT_LIST_HEAD(&device->req_list); 7695fa0405SHaiyang Zhang 7795fa0405SHaiyang Zhang device->state = RNDIS_DEV_UNINITIALIZED; 7895fa0405SHaiyang Zhang 7995fa0405SHaiyang Zhang return device; 8095fa0405SHaiyang Zhang } 8195fa0405SHaiyang Zhang 8295fa0405SHaiyang Zhang static struct rndis_request *get_rndis_request(struct rndis_device *dev, 8395fa0405SHaiyang Zhang u32 msg_type, 8495fa0405SHaiyang Zhang u32 msg_len) 8595fa0405SHaiyang Zhang { 8695fa0405SHaiyang Zhang struct rndis_request *request; 8795fa0405SHaiyang Zhang struct rndis_message *rndis_msg; 8895fa0405SHaiyang Zhang struct rndis_set_request *set; 8995fa0405SHaiyang Zhang unsigned long flags; 9095fa0405SHaiyang Zhang 9195fa0405SHaiyang Zhang request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL); 9295fa0405SHaiyang Zhang if (!request) 9395fa0405SHaiyang Zhang return NULL; 9495fa0405SHaiyang Zhang 9595fa0405SHaiyang Zhang init_completion(&request->wait_event); 9695fa0405SHaiyang Zhang 9795fa0405SHaiyang Zhang rndis_msg = &request->request_msg; 9895fa0405SHaiyang Zhang rndis_msg->ndis_msg_type = msg_type; 9995fa0405SHaiyang Zhang rndis_msg->msg_len = msg_len; 10095fa0405SHaiyang Zhang 10195fa0405SHaiyang Zhang /* 10295fa0405SHaiyang Zhang * Set the request id. This field is always after the rndis header for 10395fa0405SHaiyang Zhang * request/response packet types so we just used the SetRequest as a 10495fa0405SHaiyang Zhang * template 10595fa0405SHaiyang Zhang */ 10695fa0405SHaiyang Zhang set = &rndis_msg->msg.set_req; 10795fa0405SHaiyang Zhang set->req_id = atomic_inc_return(&dev->new_req_id); 10895fa0405SHaiyang Zhang 10995fa0405SHaiyang Zhang /* Add to the request list */ 11095fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 11195fa0405SHaiyang Zhang list_add_tail(&request->list_ent, &dev->req_list); 11295fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 11395fa0405SHaiyang Zhang 11495fa0405SHaiyang Zhang return request; 11595fa0405SHaiyang Zhang } 11695fa0405SHaiyang Zhang 11795fa0405SHaiyang Zhang static void put_rndis_request(struct rndis_device *dev, 11895fa0405SHaiyang Zhang struct rndis_request *req) 11995fa0405SHaiyang Zhang { 12095fa0405SHaiyang Zhang unsigned long flags; 12195fa0405SHaiyang Zhang 12295fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 12395fa0405SHaiyang Zhang list_del(&req->list_ent); 12495fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 12595fa0405SHaiyang Zhang 12695fa0405SHaiyang Zhang kfree(req); 12795fa0405SHaiyang Zhang } 12895fa0405SHaiyang Zhang 12995fa0405SHaiyang Zhang static void dump_rndis_message(struct hv_device *hv_dev, 13095fa0405SHaiyang Zhang struct rndis_message *rndis_msg) 13195fa0405SHaiyang Zhang { 13295fa0405SHaiyang Zhang struct net_device *netdev; 13395fa0405SHaiyang Zhang struct netvsc_device *net_device; 13495fa0405SHaiyang Zhang 13595fa0405SHaiyang Zhang net_device = hv_get_drvdata(hv_dev); 13695fa0405SHaiyang Zhang netdev = net_device->ndev; 13795fa0405SHaiyang Zhang 13895fa0405SHaiyang Zhang switch (rndis_msg->ndis_msg_type) { 13951491167SLinus Walleij case RNDIS_MSG_PACKET: 14051491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, " 14195fa0405SHaiyang Zhang "data offset %u data len %u, # oob %u, " 14295fa0405SHaiyang Zhang "oob offset %u, oob len %u, pkt offset %u, " 14395fa0405SHaiyang Zhang "pkt len %u\n", 14495fa0405SHaiyang Zhang rndis_msg->msg_len, 14595fa0405SHaiyang Zhang rndis_msg->msg.pkt.data_offset, 14695fa0405SHaiyang Zhang rndis_msg->msg.pkt.data_len, 14795fa0405SHaiyang Zhang rndis_msg->msg.pkt.num_oob_data_elements, 14895fa0405SHaiyang Zhang rndis_msg->msg.pkt.oob_data_offset, 14995fa0405SHaiyang Zhang rndis_msg->msg.pkt.oob_data_len, 15095fa0405SHaiyang Zhang rndis_msg->msg.pkt.per_pkt_info_offset, 15195fa0405SHaiyang Zhang rndis_msg->msg.pkt.per_pkt_info_len); 15295fa0405SHaiyang Zhang break; 15395fa0405SHaiyang Zhang 15451491167SLinus Walleij case RNDIS_MSG_INIT_C: 15551491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_INIT_C " 15695fa0405SHaiyang Zhang "(len %u, id 0x%x, status 0x%x, major %d, minor %d, " 15795fa0405SHaiyang Zhang "device flags %d, max xfer size 0x%x, max pkts %u, " 15895fa0405SHaiyang Zhang "pkt aligned %u)\n", 15995fa0405SHaiyang Zhang rndis_msg->msg_len, 16095fa0405SHaiyang Zhang rndis_msg->msg.init_complete.req_id, 16195fa0405SHaiyang Zhang rndis_msg->msg.init_complete.status, 16295fa0405SHaiyang Zhang rndis_msg->msg.init_complete.major_ver, 16395fa0405SHaiyang Zhang rndis_msg->msg.init_complete.minor_ver, 16495fa0405SHaiyang Zhang rndis_msg->msg.init_complete.dev_flags, 16595fa0405SHaiyang Zhang rndis_msg->msg.init_complete.max_xfer_size, 16695fa0405SHaiyang Zhang rndis_msg->msg.init_complete. 16795fa0405SHaiyang Zhang max_pkt_per_msg, 16895fa0405SHaiyang Zhang rndis_msg->msg.init_complete. 16995fa0405SHaiyang Zhang pkt_alignment_factor); 17095fa0405SHaiyang Zhang break; 17195fa0405SHaiyang Zhang 17251491167SLinus Walleij case RNDIS_MSG_QUERY_C: 17351491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_QUERY_C " 17495fa0405SHaiyang Zhang "(len %u, id 0x%x, status 0x%x, buf len %u, " 17595fa0405SHaiyang Zhang "buf offset %u)\n", 17695fa0405SHaiyang Zhang rndis_msg->msg_len, 17795fa0405SHaiyang Zhang rndis_msg->msg.query_complete.req_id, 17895fa0405SHaiyang Zhang rndis_msg->msg.query_complete.status, 17995fa0405SHaiyang Zhang rndis_msg->msg.query_complete. 18095fa0405SHaiyang Zhang info_buflen, 18195fa0405SHaiyang Zhang rndis_msg->msg.query_complete. 18295fa0405SHaiyang Zhang info_buf_offset); 18395fa0405SHaiyang Zhang break; 18495fa0405SHaiyang Zhang 18551491167SLinus Walleij case RNDIS_MSG_SET_C: 18695fa0405SHaiyang Zhang netdev_dbg(netdev, 18751491167SLinus Walleij "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n", 18895fa0405SHaiyang Zhang rndis_msg->msg_len, 18995fa0405SHaiyang Zhang rndis_msg->msg.set_complete.req_id, 19095fa0405SHaiyang Zhang rndis_msg->msg.set_complete.status); 19195fa0405SHaiyang Zhang break; 19295fa0405SHaiyang Zhang 19351491167SLinus Walleij case RNDIS_MSG_INDICATE: 19451491167SLinus Walleij netdev_dbg(netdev, "RNDIS_MSG_INDICATE " 19595fa0405SHaiyang Zhang "(len %u, status 0x%x, buf len %u, buf offset %u)\n", 19695fa0405SHaiyang Zhang rndis_msg->msg_len, 19795fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status, 19895fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status_buflen, 19995fa0405SHaiyang Zhang rndis_msg->msg.indicate_status.status_buf_offset); 20095fa0405SHaiyang Zhang break; 20195fa0405SHaiyang Zhang 20295fa0405SHaiyang Zhang default: 20395fa0405SHaiyang Zhang netdev_dbg(netdev, "0x%x (len %u)\n", 20495fa0405SHaiyang Zhang rndis_msg->ndis_msg_type, 20595fa0405SHaiyang Zhang rndis_msg->msg_len); 20695fa0405SHaiyang Zhang break; 20795fa0405SHaiyang Zhang } 20895fa0405SHaiyang Zhang } 20995fa0405SHaiyang Zhang 21095fa0405SHaiyang Zhang static int rndis_filter_send_request(struct rndis_device *dev, 21195fa0405SHaiyang Zhang struct rndis_request *req) 21295fa0405SHaiyang Zhang { 21395fa0405SHaiyang Zhang int ret; 21495fa0405SHaiyang Zhang struct hv_netvsc_packet *packet; 21595fa0405SHaiyang Zhang 21695fa0405SHaiyang Zhang /* Setup the packet to send it */ 21795fa0405SHaiyang Zhang packet = &req->pkt; 21895fa0405SHaiyang Zhang 21995fa0405SHaiyang Zhang packet->is_data_pkt = false; 22095fa0405SHaiyang Zhang packet->total_data_buflen = req->request_msg.msg_len; 22195fa0405SHaiyang Zhang packet->page_buf_cnt = 1; 22295fa0405SHaiyang Zhang 22395fa0405SHaiyang Zhang packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >> 22495fa0405SHaiyang Zhang PAGE_SHIFT; 22595fa0405SHaiyang Zhang packet->page_buf[0].len = req->request_msg.msg_len; 22695fa0405SHaiyang Zhang packet->page_buf[0].offset = 22795fa0405SHaiyang Zhang (unsigned long)&req->request_msg & (PAGE_SIZE - 1); 22895fa0405SHaiyang Zhang 22999e3fcfaSHaiyang Zhang /* Add one page_buf when request_msg crossing page boundary */ 23099e3fcfaSHaiyang Zhang if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) { 23199e3fcfaSHaiyang Zhang packet->page_buf_cnt++; 23299e3fcfaSHaiyang Zhang packet->page_buf[0].len = PAGE_SIZE - 23399e3fcfaSHaiyang Zhang packet->page_buf[0].offset; 23499e3fcfaSHaiyang Zhang packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg 23599e3fcfaSHaiyang Zhang + packet->page_buf[0].len) >> PAGE_SHIFT; 23699e3fcfaSHaiyang Zhang packet->page_buf[1].offset = 0; 23799e3fcfaSHaiyang Zhang packet->page_buf[1].len = req->request_msg.msg_len - 23899e3fcfaSHaiyang Zhang packet->page_buf[0].len; 23999e3fcfaSHaiyang Zhang } 24099e3fcfaSHaiyang Zhang 241f1ea3cd7SHaiyang Zhang packet->completion.send.send_completion = NULL; 24295fa0405SHaiyang Zhang 24395fa0405SHaiyang Zhang ret = netvsc_send(dev->net_dev->dev, packet); 24495fa0405SHaiyang Zhang return ret; 24595fa0405SHaiyang Zhang } 24695fa0405SHaiyang Zhang 24795fa0405SHaiyang Zhang static void rndis_filter_receive_response(struct rndis_device *dev, 24895fa0405SHaiyang Zhang struct rndis_message *resp) 24995fa0405SHaiyang Zhang { 25095fa0405SHaiyang Zhang struct rndis_request *request = NULL; 25195fa0405SHaiyang Zhang bool found = false; 25295fa0405SHaiyang Zhang unsigned long flags; 25395fa0405SHaiyang Zhang struct net_device *ndev; 25495fa0405SHaiyang Zhang 25595fa0405SHaiyang Zhang ndev = dev->net_dev->ndev; 25695fa0405SHaiyang Zhang 25795fa0405SHaiyang Zhang spin_lock_irqsave(&dev->request_lock, flags); 25895fa0405SHaiyang Zhang list_for_each_entry(request, &dev->req_list, list_ent) { 25995fa0405SHaiyang Zhang /* 26095fa0405SHaiyang Zhang * All request/response message contains RequestId as the 1st 26195fa0405SHaiyang Zhang * field 26295fa0405SHaiyang Zhang */ 26395fa0405SHaiyang Zhang if (request->request_msg.msg.init_req.req_id 26495fa0405SHaiyang Zhang == resp->msg.init_complete.req_id) { 26595fa0405SHaiyang Zhang found = true; 26695fa0405SHaiyang Zhang break; 26795fa0405SHaiyang Zhang } 26895fa0405SHaiyang Zhang } 26995fa0405SHaiyang Zhang spin_unlock_irqrestore(&dev->request_lock, flags); 27095fa0405SHaiyang Zhang 27195fa0405SHaiyang Zhang if (found) { 272a3a6cab5SHaiyang Zhang if (resp->msg_len <= 273a3a6cab5SHaiyang Zhang sizeof(struct rndis_message) + RNDIS_EXT_LEN) { 27495fa0405SHaiyang Zhang memcpy(&request->response_msg, resp, 27595fa0405SHaiyang Zhang resp->msg_len); 27695fa0405SHaiyang Zhang } else { 27795fa0405SHaiyang Zhang netdev_err(ndev, 27895fa0405SHaiyang Zhang "rndis response buffer overflow " 27995fa0405SHaiyang Zhang "detected (size %u max %zu)\n", 28095fa0405SHaiyang Zhang resp->msg_len, 28195fa0405SHaiyang Zhang sizeof(struct rndis_filter_packet)); 28295fa0405SHaiyang Zhang 28395fa0405SHaiyang Zhang if (resp->ndis_msg_type == 28451491167SLinus Walleij RNDIS_MSG_RESET_C) { 28595fa0405SHaiyang Zhang /* does not have a request id field */ 28695fa0405SHaiyang Zhang request->response_msg.msg.reset_complete. 287007e5c8eSLinus Walleij status = RNDIS_STATUS_BUFFER_OVERFLOW; 28895fa0405SHaiyang Zhang } else { 28995fa0405SHaiyang Zhang request->response_msg.msg. 29095fa0405SHaiyang Zhang init_complete.status = 291007e5c8eSLinus Walleij RNDIS_STATUS_BUFFER_OVERFLOW; 29295fa0405SHaiyang Zhang } 29395fa0405SHaiyang Zhang } 29495fa0405SHaiyang Zhang 29595fa0405SHaiyang Zhang complete(&request->wait_event); 29695fa0405SHaiyang Zhang } else { 29795fa0405SHaiyang Zhang netdev_err(ndev, 29895fa0405SHaiyang Zhang "no rndis request found for this response " 29995fa0405SHaiyang Zhang "(id 0x%x res type 0x%x)\n", 30095fa0405SHaiyang Zhang resp->msg.init_complete.req_id, 30195fa0405SHaiyang Zhang resp->ndis_msg_type); 30295fa0405SHaiyang Zhang } 30395fa0405SHaiyang Zhang } 30495fa0405SHaiyang Zhang 30595fa0405SHaiyang Zhang static void rndis_filter_receive_indicate_status(struct rndis_device *dev, 30695fa0405SHaiyang Zhang struct rndis_message *resp) 30795fa0405SHaiyang Zhang { 30895fa0405SHaiyang Zhang struct rndis_indicate_status *indicate = 30995fa0405SHaiyang Zhang &resp->msg.indicate_status; 31095fa0405SHaiyang Zhang 31195fa0405SHaiyang Zhang if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) { 31295fa0405SHaiyang Zhang netvsc_linkstatus_callback( 31395fa0405SHaiyang Zhang dev->net_dev->dev, 1); 31495fa0405SHaiyang Zhang } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) { 31595fa0405SHaiyang Zhang netvsc_linkstatus_callback( 31695fa0405SHaiyang Zhang dev->net_dev->dev, 0); 31795fa0405SHaiyang Zhang } else { 31895fa0405SHaiyang Zhang /* 31995fa0405SHaiyang Zhang * TODO: 32095fa0405SHaiyang Zhang */ 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; 35795fa0405SHaiyang Zhang 35895fa0405SHaiyang Zhang rndis_pkt = &msg->msg.pkt; 35995fa0405SHaiyang Zhang 36095fa0405SHaiyang Zhang /* Remove the rndis header and pass it back up the stack */ 36195fa0405SHaiyang Zhang data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset; 36295fa0405SHaiyang Zhang 36395fa0405SHaiyang Zhang pkt->total_data_buflen -= data_offset; 3644b8a8bc9SWei Yongjun 3654b8a8bc9SWei Yongjun /* 3664b8a8bc9SWei Yongjun * Make sure we got a valid RNDIS message, now total_data_buflen 3674b8a8bc9SWei Yongjun * should be the data packet size plus the trailer padding size 3684b8a8bc9SWei Yongjun */ 3694b8a8bc9SWei Yongjun if (pkt->total_data_buflen < rndis_pkt->data_len) { 3704b8a8bc9SWei Yongjun netdev_err(dev->net_dev->ndev, "rndis message buffer " 3714b8a8bc9SWei Yongjun "overflow detected (got %u, min %u)" 3724b8a8bc9SWei Yongjun "...dropping this message!\n", 3734b8a8bc9SWei Yongjun pkt->total_data_buflen, rndis_pkt->data_len); 3744b8a8bc9SWei Yongjun return; 3754b8a8bc9SWei Yongjun } 3764b8a8bc9SWei Yongjun 3774b8a8bc9SWei Yongjun /* 3784b8a8bc9SWei Yongjun * Remove the rndis trailer padding from rndis packet message 3794b8a8bc9SWei Yongjun * rndis_pkt->data_len tell us the real data length, we only copy 3804b8a8bc9SWei Yongjun * the data packet to the stack, without the rndis trailer padding 3814b8a8bc9SWei Yongjun */ 3824b8a8bc9SWei Yongjun pkt->total_data_buflen = rndis_pkt->data_len; 38345326342SHaiyang Zhang pkt->data = (void *)((unsigned long)pkt->data + data_offset); 38495fa0405SHaiyang Zhang 38595fa0405SHaiyang Zhang pkt->is_data_pkt = true; 38695fa0405SHaiyang Zhang 3871f5f3a75SHaiyang Zhang vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO); 3881f5f3a75SHaiyang Zhang if (vlan) { 3891f5f3a75SHaiyang Zhang pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid | 3901f5f3a75SHaiyang Zhang (vlan->pri << VLAN_PRIO_SHIFT); 3911f5f3a75SHaiyang Zhang } else { 3921f5f3a75SHaiyang Zhang pkt->vlan_tci = 0; 3931f5f3a75SHaiyang Zhang } 3941f5f3a75SHaiyang Zhang 39595fa0405SHaiyang Zhang netvsc_recv_callback(dev->net_dev->dev, pkt); 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 */ 449ef31bef6SHaiyang Zhang rndis_filter_receive_indicate_status(rndis_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; 47495fa0405SHaiyang Zhang int 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 49495fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 49595fa0405SHaiyang Zhang if (ret != 0) 49695fa0405SHaiyang Zhang goto cleanup; 49795fa0405SHaiyang Zhang 49895fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 49995fa0405SHaiyang Zhang if (t == 0) { 50095fa0405SHaiyang Zhang ret = -ETIMEDOUT; 50195fa0405SHaiyang Zhang goto cleanup; 50295fa0405SHaiyang Zhang } 50395fa0405SHaiyang Zhang 50495fa0405SHaiyang Zhang /* Copy the response back */ 50595fa0405SHaiyang Zhang query_complete = &request->response_msg.msg.query_complete; 50695fa0405SHaiyang Zhang 50795fa0405SHaiyang Zhang if (query_complete->info_buflen > inresult_size) { 50895fa0405SHaiyang Zhang ret = -1; 50995fa0405SHaiyang Zhang goto cleanup; 51095fa0405SHaiyang Zhang } 51195fa0405SHaiyang Zhang 51295fa0405SHaiyang Zhang memcpy(result, 51395fa0405SHaiyang Zhang (void *)((unsigned long)query_complete + 51495fa0405SHaiyang Zhang query_complete->info_buf_offset), 51595fa0405SHaiyang Zhang query_complete->info_buflen); 51695fa0405SHaiyang Zhang 51795fa0405SHaiyang Zhang *result_size = query_complete->info_buflen; 51895fa0405SHaiyang Zhang 51995fa0405SHaiyang Zhang cleanup: 52095fa0405SHaiyang Zhang if (request) 52195fa0405SHaiyang Zhang put_rndis_request(dev, request); 52295fa0405SHaiyang Zhang 52395fa0405SHaiyang Zhang return ret; 52495fa0405SHaiyang Zhang } 52595fa0405SHaiyang Zhang 52695fa0405SHaiyang Zhang static int rndis_filter_query_device_mac(struct rndis_device *dev) 52795fa0405SHaiyang Zhang { 52895fa0405SHaiyang Zhang u32 size = ETH_ALEN; 52995fa0405SHaiyang Zhang 53095fa0405SHaiyang Zhang return rndis_filter_query_device(dev, 53195fa0405SHaiyang Zhang RNDIS_OID_802_3_PERMANENT_ADDRESS, 53295fa0405SHaiyang Zhang dev->hw_mac_adr, &size); 53395fa0405SHaiyang Zhang } 53495fa0405SHaiyang Zhang 5351ce09e89SHaiyang Zhang #define NWADR_STR "NetworkAddress" 5361ce09e89SHaiyang Zhang #define NWADR_STRLEN 14 5371ce09e89SHaiyang Zhang 5381ce09e89SHaiyang Zhang int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac) 5391ce09e89SHaiyang Zhang { 5401ce09e89SHaiyang Zhang struct netvsc_device *nvdev = hv_get_drvdata(hdev); 5411ce09e89SHaiyang Zhang struct rndis_device *rdev = nvdev->extension; 5421ce09e89SHaiyang Zhang struct net_device *ndev = nvdev->ndev; 5431ce09e89SHaiyang Zhang struct rndis_request *request; 5441ce09e89SHaiyang Zhang struct rndis_set_request *set; 5451ce09e89SHaiyang Zhang struct rndis_config_parameter_info *cpi; 5461ce09e89SHaiyang Zhang wchar_t *cfg_nwadr, *cfg_mac; 5471ce09e89SHaiyang Zhang struct rndis_set_complete *set_complete; 5481ce09e89SHaiyang Zhang char macstr[2*ETH_ALEN+1]; 5491ce09e89SHaiyang Zhang u32 extlen = sizeof(struct rndis_config_parameter_info) + 5501ce09e89SHaiyang Zhang 2*NWADR_STRLEN + 4*ETH_ALEN; 5511ce09e89SHaiyang Zhang int ret, t; 5521ce09e89SHaiyang Zhang 5531ce09e89SHaiyang Zhang request = get_rndis_request(rdev, RNDIS_MSG_SET, 5541ce09e89SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); 5551ce09e89SHaiyang Zhang if (!request) 5561ce09e89SHaiyang Zhang return -ENOMEM; 5571ce09e89SHaiyang Zhang 5581ce09e89SHaiyang Zhang set = &request->request_msg.msg.set_req; 5591ce09e89SHaiyang Zhang set->oid = RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER; 5601ce09e89SHaiyang Zhang set->info_buflen = extlen; 5611ce09e89SHaiyang Zhang set->info_buf_offset = sizeof(struct rndis_set_request); 5621ce09e89SHaiyang Zhang set->dev_vc_handle = 0; 5631ce09e89SHaiyang Zhang 5641ce09e89SHaiyang Zhang cpi = (struct rndis_config_parameter_info *)((ulong)set + 5651ce09e89SHaiyang Zhang set->info_buf_offset); 5661ce09e89SHaiyang Zhang cpi->parameter_name_offset = 5671ce09e89SHaiyang Zhang sizeof(struct rndis_config_parameter_info); 5681ce09e89SHaiyang Zhang /* Multiply by 2 because host needs 2 bytes (utf16) for each char */ 5691ce09e89SHaiyang Zhang cpi->parameter_name_length = 2*NWADR_STRLEN; 5701ce09e89SHaiyang Zhang cpi->parameter_type = RNDIS_CONFIG_PARAM_TYPE_STRING; 5711ce09e89SHaiyang Zhang cpi->parameter_value_offset = 5721ce09e89SHaiyang Zhang cpi->parameter_name_offset + cpi->parameter_name_length; 5731ce09e89SHaiyang Zhang /* Multiply by 4 because each MAC byte displayed as 2 utf16 chars */ 5741ce09e89SHaiyang Zhang cpi->parameter_value_length = 4*ETH_ALEN; 5751ce09e89SHaiyang Zhang 5761ce09e89SHaiyang Zhang cfg_nwadr = (wchar_t *)((ulong)cpi + cpi->parameter_name_offset); 5771ce09e89SHaiyang Zhang cfg_mac = (wchar_t *)((ulong)cpi + cpi->parameter_value_offset); 5781ce09e89SHaiyang Zhang ret = utf8s_to_utf16s(NWADR_STR, NWADR_STRLEN, UTF16_HOST_ENDIAN, 5791ce09e89SHaiyang Zhang cfg_nwadr, NWADR_STRLEN); 5801ce09e89SHaiyang Zhang if (ret < 0) 5811ce09e89SHaiyang Zhang goto cleanup; 5821ce09e89SHaiyang Zhang snprintf(macstr, 2*ETH_ALEN+1, "%pm", mac); 5831ce09e89SHaiyang Zhang ret = utf8s_to_utf16s(macstr, 2*ETH_ALEN, UTF16_HOST_ENDIAN, 5841ce09e89SHaiyang Zhang cfg_mac, 2*ETH_ALEN); 5851ce09e89SHaiyang Zhang if (ret < 0) 5861ce09e89SHaiyang Zhang goto cleanup; 5871ce09e89SHaiyang Zhang 5881ce09e89SHaiyang Zhang ret = rndis_filter_send_request(rdev, request); 5891ce09e89SHaiyang Zhang if (ret != 0) 5901ce09e89SHaiyang Zhang goto cleanup; 5911ce09e89SHaiyang Zhang 5921ce09e89SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 5931ce09e89SHaiyang Zhang if (t == 0) { 5941ce09e89SHaiyang Zhang netdev_err(ndev, "timeout before we got a set response...\n"); 5951ce09e89SHaiyang Zhang /* 5961ce09e89SHaiyang Zhang * can't put_rndis_request, since we may still receive a 5971ce09e89SHaiyang Zhang * send-completion. 5981ce09e89SHaiyang Zhang */ 5991ce09e89SHaiyang Zhang return -EBUSY; 6001ce09e89SHaiyang Zhang } else { 6011ce09e89SHaiyang Zhang set_complete = &request->response_msg.msg.set_complete; 602b02a8067SHaiyang Zhang if (set_complete->status != RNDIS_STATUS_SUCCESS) { 603b02a8067SHaiyang Zhang netdev_err(ndev, "Fail to set MAC on host side:0x%x\n", 604b02a8067SHaiyang Zhang set_complete->status); 6051ce09e89SHaiyang Zhang ret = -EINVAL; 6061ce09e89SHaiyang Zhang } 607b02a8067SHaiyang Zhang } 6081ce09e89SHaiyang Zhang 6091ce09e89SHaiyang Zhang cleanup: 6101ce09e89SHaiyang Zhang put_rndis_request(rdev, request); 6111ce09e89SHaiyang Zhang return ret; 6121ce09e89SHaiyang Zhang } 6131ce09e89SHaiyang Zhang 6141ce09e89SHaiyang Zhang 61595fa0405SHaiyang Zhang static int rndis_filter_query_device_link_status(struct rndis_device *dev) 61695fa0405SHaiyang Zhang { 61795fa0405SHaiyang Zhang u32 size = sizeof(u32); 61895fa0405SHaiyang Zhang u32 link_status; 61995fa0405SHaiyang Zhang int ret; 62095fa0405SHaiyang Zhang 62195fa0405SHaiyang Zhang ret = rndis_filter_query_device(dev, 62295fa0405SHaiyang Zhang RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, 62395fa0405SHaiyang Zhang &link_status, &size); 62495fa0405SHaiyang Zhang dev->link_state = (link_status != 0) ? true : false; 62595fa0405SHaiyang Zhang 62695fa0405SHaiyang Zhang return ret; 62795fa0405SHaiyang Zhang } 62895fa0405SHaiyang Zhang 629d426b2e3SHaiyang Zhang int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) 63095fa0405SHaiyang Zhang { 63195fa0405SHaiyang Zhang struct rndis_request *request; 63295fa0405SHaiyang Zhang struct rndis_set_request *set; 63395fa0405SHaiyang Zhang struct rndis_set_complete *set_complete; 63495fa0405SHaiyang Zhang u32 status; 63595fa0405SHaiyang Zhang int ret, t; 63695fa0405SHaiyang Zhang struct net_device *ndev; 63795fa0405SHaiyang Zhang 63895fa0405SHaiyang Zhang ndev = dev->net_dev->ndev; 63995fa0405SHaiyang Zhang 64051491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_SET, 64195fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_set_request) + 64295fa0405SHaiyang Zhang sizeof(u32)); 64395fa0405SHaiyang Zhang if (!request) { 64495fa0405SHaiyang Zhang ret = -ENOMEM; 64595fa0405SHaiyang Zhang goto cleanup; 64695fa0405SHaiyang Zhang } 64795fa0405SHaiyang Zhang 64895fa0405SHaiyang Zhang /* Setup the rndis set */ 64995fa0405SHaiyang Zhang set = &request->request_msg.msg.set_req; 65095fa0405SHaiyang Zhang set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; 65195fa0405SHaiyang Zhang set->info_buflen = sizeof(u32); 65295fa0405SHaiyang Zhang set->info_buf_offset = sizeof(struct rndis_set_request); 65395fa0405SHaiyang Zhang 65495fa0405SHaiyang Zhang memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), 65595fa0405SHaiyang Zhang &new_filter, sizeof(u32)); 65695fa0405SHaiyang Zhang 65795fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 65895fa0405SHaiyang Zhang if (ret != 0) 65995fa0405SHaiyang Zhang goto cleanup; 66095fa0405SHaiyang Zhang 66195fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 66295fa0405SHaiyang Zhang 66395fa0405SHaiyang Zhang if (t == 0) { 66495fa0405SHaiyang Zhang netdev_err(ndev, 66595fa0405SHaiyang Zhang "timeout before we got a set response...\n"); 666ea496374SHaiyang Zhang ret = -ETIMEDOUT; 66795fa0405SHaiyang Zhang /* 66895fa0405SHaiyang Zhang * We can't deallocate the request since we may still receive a 66995fa0405SHaiyang Zhang * send completion for it. 67095fa0405SHaiyang Zhang */ 67195fa0405SHaiyang Zhang goto exit; 67295fa0405SHaiyang Zhang } else { 67395fa0405SHaiyang Zhang set_complete = &request->response_msg.msg.set_complete; 67495fa0405SHaiyang Zhang status = set_complete->status; 67595fa0405SHaiyang Zhang } 67695fa0405SHaiyang Zhang 67795fa0405SHaiyang Zhang cleanup: 67895fa0405SHaiyang Zhang if (request) 67995fa0405SHaiyang Zhang put_rndis_request(dev, request); 68095fa0405SHaiyang Zhang exit: 68195fa0405SHaiyang Zhang return ret; 68295fa0405SHaiyang Zhang } 68395fa0405SHaiyang Zhang 68495fa0405SHaiyang Zhang 68595fa0405SHaiyang Zhang static int rndis_filter_init_device(struct rndis_device *dev) 68695fa0405SHaiyang Zhang { 68795fa0405SHaiyang Zhang struct rndis_request *request; 68895fa0405SHaiyang Zhang struct rndis_initialize_request *init; 68995fa0405SHaiyang Zhang struct rndis_initialize_complete *init_complete; 69095fa0405SHaiyang Zhang u32 status; 69195fa0405SHaiyang Zhang int ret, t; 69295fa0405SHaiyang Zhang 69351491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_INIT, 69495fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); 69595fa0405SHaiyang Zhang if (!request) { 69695fa0405SHaiyang Zhang ret = -ENOMEM; 69795fa0405SHaiyang Zhang goto cleanup; 69895fa0405SHaiyang Zhang } 69995fa0405SHaiyang Zhang 70095fa0405SHaiyang Zhang /* Setup the rndis set */ 70195fa0405SHaiyang Zhang init = &request->request_msg.msg.init_req; 70295fa0405SHaiyang Zhang init->major_ver = RNDIS_MAJOR_VERSION; 70395fa0405SHaiyang Zhang init->minor_ver = RNDIS_MINOR_VERSION; 704fb1d074eSHaiyang Zhang init->max_xfer_size = 0x4000; 70595fa0405SHaiyang Zhang 70695fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZING; 70795fa0405SHaiyang Zhang 70895fa0405SHaiyang Zhang ret = rndis_filter_send_request(dev, request); 70995fa0405SHaiyang Zhang if (ret != 0) { 71095fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 71195fa0405SHaiyang Zhang goto cleanup; 71295fa0405SHaiyang Zhang } 71395fa0405SHaiyang Zhang 71495fa0405SHaiyang Zhang 71595fa0405SHaiyang Zhang t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 71695fa0405SHaiyang Zhang 71795fa0405SHaiyang Zhang if (t == 0) { 71895fa0405SHaiyang Zhang ret = -ETIMEDOUT; 71995fa0405SHaiyang Zhang goto cleanup; 72095fa0405SHaiyang Zhang } 72195fa0405SHaiyang Zhang 72295fa0405SHaiyang Zhang init_complete = &request->response_msg.msg.init_complete; 72395fa0405SHaiyang Zhang status = init_complete->status; 72495fa0405SHaiyang Zhang if (status == RNDIS_STATUS_SUCCESS) { 72595fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZED; 72695fa0405SHaiyang Zhang ret = 0; 72795fa0405SHaiyang Zhang } else { 72895fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 72995fa0405SHaiyang Zhang ret = -EINVAL; 73095fa0405SHaiyang Zhang } 73195fa0405SHaiyang Zhang 73295fa0405SHaiyang Zhang cleanup: 73395fa0405SHaiyang Zhang if (request) 73495fa0405SHaiyang Zhang put_rndis_request(dev, request); 73595fa0405SHaiyang Zhang 73695fa0405SHaiyang Zhang return ret; 73795fa0405SHaiyang Zhang } 73895fa0405SHaiyang Zhang 73995fa0405SHaiyang Zhang static void rndis_filter_halt_device(struct rndis_device *dev) 74095fa0405SHaiyang Zhang { 74195fa0405SHaiyang Zhang struct rndis_request *request; 74295fa0405SHaiyang Zhang struct rndis_halt_request *halt; 743ae9e63bbSHaiyang Zhang struct netvsc_device *nvdev = dev->net_dev; 744ae9e63bbSHaiyang Zhang struct hv_device *hdev = nvdev->dev; 745ae9e63bbSHaiyang Zhang ulong flags; 74695fa0405SHaiyang Zhang 74795fa0405SHaiyang Zhang /* Attempt to do a rndis device halt */ 74851491167SLinus Walleij request = get_rndis_request(dev, RNDIS_MSG_HALT, 74995fa0405SHaiyang Zhang RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); 75095fa0405SHaiyang Zhang if (!request) 75195fa0405SHaiyang Zhang goto cleanup; 75295fa0405SHaiyang Zhang 75395fa0405SHaiyang Zhang /* Setup the rndis set */ 75495fa0405SHaiyang Zhang halt = &request->request_msg.msg.halt_req; 75595fa0405SHaiyang Zhang halt->req_id = atomic_inc_return(&dev->new_req_id); 75695fa0405SHaiyang Zhang 75795fa0405SHaiyang Zhang /* Ignore return since this msg is optional. */ 75895fa0405SHaiyang Zhang rndis_filter_send_request(dev, request); 75995fa0405SHaiyang Zhang 76095fa0405SHaiyang Zhang dev->state = RNDIS_DEV_UNINITIALIZED; 76195fa0405SHaiyang Zhang 76295fa0405SHaiyang Zhang cleanup: 763ae9e63bbSHaiyang Zhang spin_lock_irqsave(&hdev->channel->inbound_lock, flags); 764ae9e63bbSHaiyang Zhang nvdev->destroy = true; 765ae9e63bbSHaiyang Zhang spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags); 766ae9e63bbSHaiyang Zhang 767ae9e63bbSHaiyang Zhang /* Wait for all send completions */ 768ae9e63bbSHaiyang Zhang wait_event(nvdev->wait_drain, 769ae9e63bbSHaiyang Zhang atomic_read(&nvdev->num_outstanding_sends) == 0); 770ae9e63bbSHaiyang Zhang 77195fa0405SHaiyang Zhang if (request) 77295fa0405SHaiyang Zhang put_rndis_request(dev, request); 77395fa0405SHaiyang Zhang return; 77495fa0405SHaiyang Zhang } 77595fa0405SHaiyang Zhang 77695fa0405SHaiyang Zhang static int rndis_filter_open_device(struct rndis_device *dev) 77795fa0405SHaiyang Zhang { 77895fa0405SHaiyang Zhang int ret; 77995fa0405SHaiyang Zhang 78095fa0405SHaiyang Zhang if (dev->state != RNDIS_DEV_INITIALIZED) 78195fa0405SHaiyang Zhang return 0; 78295fa0405SHaiyang Zhang 78395fa0405SHaiyang Zhang ret = rndis_filter_set_packet_filter(dev, 78495fa0405SHaiyang Zhang NDIS_PACKET_TYPE_BROADCAST | 78595fa0405SHaiyang Zhang NDIS_PACKET_TYPE_ALL_MULTICAST | 78695fa0405SHaiyang Zhang NDIS_PACKET_TYPE_DIRECTED); 78795fa0405SHaiyang Zhang if (ret == 0) 78895fa0405SHaiyang Zhang dev->state = RNDIS_DEV_DATAINITIALIZED; 78995fa0405SHaiyang Zhang 79095fa0405SHaiyang Zhang return ret; 79195fa0405SHaiyang Zhang } 79295fa0405SHaiyang Zhang 79395fa0405SHaiyang Zhang static int rndis_filter_close_device(struct rndis_device *dev) 79495fa0405SHaiyang Zhang { 79595fa0405SHaiyang Zhang int ret; 79695fa0405SHaiyang Zhang 79795fa0405SHaiyang Zhang if (dev->state != RNDIS_DEV_DATAINITIALIZED) 79895fa0405SHaiyang Zhang return 0; 79995fa0405SHaiyang Zhang 80095fa0405SHaiyang Zhang ret = rndis_filter_set_packet_filter(dev, 0); 80195fa0405SHaiyang Zhang if (ret == 0) 80295fa0405SHaiyang Zhang dev->state = RNDIS_DEV_INITIALIZED; 80395fa0405SHaiyang Zhang 80495fa0405SHaiyang Zhang return ret; 80595fa0405SHaiyang Zhang } 80695fa0405SHaiyang Zhang 80795fa0405SHaiyang Zhang int rndis_filter_device_add(struct hv_device *dev, 80895fa0405SHaiyang Zhang void *additional_info) 80995fa0405SHaiyang Zhang { 81095fa0405SHaiyang Zhang int ret; 81195fa0405SHaiyang Zhang struct netvsc_device *net_device; 81295fa0405SHaiyang Zhang struct rndis_device *rndis_device; 81395fa0405SHaiyang Zhang struct netvsc_device_info *device_info = additional_info; 81495fa0405SHaiyang Zhang 81595fa0405SHaiyang Zhang rndis_device = get_rndis_device(); 81695fa0405SHaiyang Zhang if (!rndis_device) 81795fa0405SHaiyang Zhang return -ENODEV; 81895fa0405SHaiyang Zhang 81995fa0405SHaiyang Zhang /* 82095fa0405SHaiyang Zhang * Let the inner driver handle this first to create the netvsc channel 82195fa0405SHaiyang Zhang * NOTE! Once the channel is created, we may get a receive callback 82295fa0405SHaiyang Zhang * (RndisFilterOnReceive()) before this call is completed 82395fa0405SHaiyang Zhang */ 82495fa0405SHaiyang Zhang ret = netvsc_device_add(dev, additional_info); 82595fa0405SHaiyang Zhang if (ret != 0) { 82695fa0405SHaiyang Zhang kfree(rndis_device); 82795fa0405SHaiyang Zhang return ret; 82895fa0405SHaiyang Zhang } 82995fa0405SHaiyang Zhang 83095fa0405SHaiyang Zhang 83195fa0405SHaiyang Zhang /* Initialize the rndis device */ 83295fa0405SHaiyang Zhang net_device = hv_get_drvdata(dev); 83395fa0405SHaiyang Zhang 83495fa0405SHaiyang Zhang net_device->extension = rndis_device; 83595fa0405SHaiyang Zhang rndis_device->net_dev = net_device; 83695fa0405SHaiyang Zhang 83795fa0405SHaiyang Zhang /* Send the rndis initialization message */ 83895fa0405SHaiyang Zhang ret = rndis_filter_init_device(rndis_device); 83995fa0405SHaiyang Zhang if (ret != 0) { 8405243e7bdSHaiyang Zhang rndis_filter_device_remove(dev); 8415243e7bdSHaiyang Zhang return ret; 84295fa0405SHaiyang Zhang } 84395fa0405SHaiyang Zhang 84495fa0405SHaiyang Zhang /* Get the mac address */ 84595fa0405SHaiyang Zhang ret = rndis_filter_query_device_mac(rndis_device); 84695fa0405SHaiyang Zhang if (ret != 0) { 8475243e7bdSHaiyang Zhang rndis_filter_device_remove(dev); 8485243e7bdSHaiyang Zhang return ret; 84995fa0405SHaiyang Zhang } 85095fa0405SHaiyang Zhang 85195fa0405SHaiyang Zhang memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); 85295fa0405SHaiyang Zhang 85395fa0405SHaiyang Zhang rndis_filter_query_device_link_status(rndis_device); 85495fa0405SHaiyang Zhang 85595fa0405SHaiyang Zhang device_info->link_state = rndis_device->link_state; 85695fa0405SHaiyang Zhang 85795fa0405SHaiyang Zhang dev_info(&dev->device, "Device MAC %pM link state %s\n", 85895fa0405SHaiyang Zhang rndis_device->hw_mac_adr, 85995fa0405SHaiyang Zhang device_info->link_state ? "down" : "up"); 86095fa0405SHaiyang Zhang 86195fa0405SHaiyang Zhang return ret; 86295fa0405SHaiyang Zhang } 86395fa0405SHaiyang Zhang 86495fa0405SHaiyang Zhang void rndis_filter_device_remove(struct hv_device *dev) 86595fa0405SHaiyang Zhang { 86695fa0405SHaiyang Zhang struct netvsc_device *net_dev = hv_get_drvdata(dev); 86795fa0405SHaiyang Zhang struct rndis_device *rndis_dev = net_dev->extension; 86895fa0405SHaiyang Zhang 86995fa0405SHaiyang Zhang /* Halt and release the rndis device */ 87095fa0405SHaiyang Zhang rndis_filter_halt_device(rndis_dev); 87195fa0405SHaiyang Zhang 87295fa0405SHaiyang Zhang kfree(rndis_dev); 87395fa0405SHaiyang Zhang net_dev->extension = NULL; 87495fa0405SHaiyang Zhang 87595fa0405SHaiyang Zhang netvsc_device_remove(dev); 87695fa0405SHaiyang Zhang } 87795fa0405SHaiyang Zhang 87895fa0405SHaiyang Zhang 87995fa0405SHaiyang Zhang int rndis_filter_open(struct hv_device *dev) 88095fa0405SHaiyang Zhang { 88195fa0405SHaiyang Zhang struct netvsc_device *net_device = hv_get_drvdata(dev); 88295fa0405SHaiyang Zhang 88395fa0405SHaiyang Zhang if (!net_device) 88495fa0405SHaiyang Zhang return -EINVAL; 88595fa0405SHaiyang Zhang 88695fa0405SHaiyang Zhang return rndis_filter_open_device(net_device->extension); 88795fa0405SHaiyang Zhang } 88895fa0405SHaiyang Zhang 88995fa0405SHaiyang Zhang int rndis_filter_close(struct hv_device *dev) 89095fa0405SHaiyang Zhang { 8915fccab3bSHaiyang Zhang struct netvsc_device *nvdev = hv_get_drvdata(dev); 89295fa0405SHaiyang Zhang 8935fccab3bSHaiyang Zhang if (!nvdev) 89495fa0405SHaiyang Zhang return -EINVAL; 89595fa0405SHaiyang Zhang 8965fccab3bSHaiyang Zhang return rndis_filter_close_device(nvdev->extension); 89795fa0405SHaiyang Zhang } 89895fa0405SHaiyang Zhang 89995fa0405SHaiyang Zhang int rndis_filter_send(struct hv_device *dev, 90095fa0405SHaiyang Zhang struct hv_netvsc_packet *pkt) 90195fa0405SHaiyang Zhang { 90295fa0405SHaiyang Zhang int ret; 9035fccab3bSHaiyang Zhang struct rndis_filter_packet *filter_pkt; 9045fccab3bSHaiyang Zhang struct rndis_message *rndis_msg; 9055fccab3bSHaiyang Zhang struct rndis_packet *rndis_pkt; 9065fccab3bSHaiyang Zhang u32 rndis_msg_size; 9071f5f3a75SHaiyang Zhang bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT; 90895fa0405SHaiyang Zhang 90995fa0405SHaiyang Zhang /* Add the rndis header */ 9105fccab3bSHaiyang Zhang filter_pkt = (struct rndis_filter_packet *)pkt->extension; 91195fa0405SHaiyang Zhang 9125fccab3bSHaiyang Zhang rndis_msg = &filter_pkt->msg; 9135fccab3bSHaiyang Zhang rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); 9141f5f3a75SHaiyang Zhang if (isvlan) 9151f5f3a75SHaiyang Zhang rndis_msg_size += NDIS_VLAN_PPI_SIZE; 91695fa0405SHaiyang Zhang 91751491167SLinus Walleij rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; 9185fccab3bSHaiyang Zhang rndis_msg->msg_len = pkt->total_data_buflen + 9195fccab3bSHaiyang Zhang rndis_msg_size; 92095fa0405SHaiyang Zhang 9215fccab3bSHaiyang Zhang rndis_pkt = &rndis_msg->msg.pkt; 9225fccab3bSHaiyang Zhang rndis_pkt->data_offset = sizeof(struct rndis_packet); 9231f5f3a75SHaiyang Zhang if (isvlan) 9241f5f3a75SHaiyang Zhang rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE; 9255fccab3bSHaiyang Zhang rndis_pkt->data_len = pkt->total_data_buflen; 92695fa0405SHaiyang Zhang 9271f5f3a75SHaiyang Zhang if (isvlan) { 9281f5f3a75SHaiyang Zhang struct rndis_per_packet_info *ppi; 9291f5f3a75SHaiyang Zhang struct ndis_pkt_8021q_info *vlan; 9301f5f3a75SHaiyang Zhang 9311f5f3a75SHaiyang Zhang rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); 9321f5f3a75SHaiyang Zhang rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE; 9331f5f3a75SHaiyang Zhang 9341f5f3a75SHaiyang Zhang ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt + 9351f5f3a75SHaiyang Zhang rndis_pkt->per_pkt_info_offset); 9361f5f3a75SHaiyang Zhang ppi->size = NDIS_VLAN_PPI_SIZE; 9371f5f3a75SHaiyang Zhang ppi->type = IEEE_8021Q_INFO; 9381f5f3a75SHaiyang Zhang ppi->ppi_offset = sizeof(struct rndis_per_packet_info); 9391f5f3a75SHaiyang Zhang 9401f5f3a75SHaiyang Zhang vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi + 9411f5f3a75SHaiyang Zhang ppi->ppi_offset); 9421f5f3a75SHaiyang Zhang vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK; 9431f5f3a75SHaiyang Zhang vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 9441f5f3a75SHaiyang Zhang } 9451f5f3a75SHaiyang Zhang 94695fa0405SHaiyang Zhang pkt->is_data_pkt = true; 9475fccab3bSHaiyang Zhang pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT; 94895fa0405SHaiyang Zhang pkt->page_buf[0].offset = 9495fccab3bSHaiyang Zhang (unsigned long)rndis_msg & (PAGE_SIZE-1); 9505fccab3bSHaiyang Zhang pkt->page_buf[0].len = rndis_msg_size; 95195fa0405SHaiyang Zhang 952c31c151bSHaiyang Zhang /* Add one page_buf if the rndis msg goes beyond page boundary */ 9535fccab3bSHaiyang Zhang if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) { 954c31c151bSHaiyang Zhang int i; 955c31c151bSHaiyang Zhang for (i = pkt->page_buf_cnt; i > 1; i--) 956c31c151bSHaiyang Zhang pkt->page_buf[i] = pkt->page_buf[i-1]; 957c31c151bSHaiyang Zhang pkt->page_buf_cnt++; 958c31c151bSHaiyang Zhang pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset; 959c31c151bSHaiyang Zhang pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong) 9605fccab3bSHaiyang Zhang rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT; 961c31c151bSHaiyang Zhang pkt->page_buf[1].offset = 0; 9625fccab3bSHaiyang Zhang pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len; 963c31c151bSHaiyang Zhang } 964c31c151bSHaiyang Zhang 96595fa0405SHaiyang Zhang /* Save the packet send completion and context */ 9665fccab3bSHaiyang Zhang filter_pkt->completion = pkt->completion.send.send_completion; 9675fccab3bSHaiyang Zhang filter_pkt->completion_ctx = 96895fa0405SHaiyang Zhang pkt->completion.send.send_completion_ctx; 96995fa0405SHaiyang Zhang 97095fa0405SHaiyang Zhang /* Use ours */ 97195fa0405SHaiyang Zhang pkt->completion.send.send_completion = rndis_filter_send_completion; 9725fccab3bSHaiyang Zhang pkt->completion.send.send_completion_ctx = filter_pkt; 97395fa0405SHaiyang Zhang 97495fa0405SHaiyang Zhang ret = netvsc_send(dev, pkt); 97595fa0405SHaiyang Zhang if (ret != 0) { 97695fa0405SHaiyang Zhang /* 97795fa0405SHaiyang Zhang * Reset the completion to originals to allow retries from 97895fa0405SHaiyang Zhang * above 97995fa0405SHaiyang Zhang */ 98095fa0405SHaiyang Zhang pkt->completion.send.send_completion = 9815fccab3bSHaiyang Zhang filter_pkt->completion; 98295fa0405SHaiyang Zhang pkt->completion.send.send_completion_ctx = 9835fccab3bSHaiyang Zhang filter_pkt->completion_ctx; 98495fa0405SHaiyang Zhang } 98595fa0405SHaiyang Zhang 98695fa0405SHaiyang Zhang return ret; 98795fa0405SHaiyang Zhang } 98895fa0405SHaiyang Zhang 98995fa0405SHaiyang Zhang static void rndis_filter_send_completion(void *ctx) 99095fa0405SHaiyang Zhang { 9915fccab3bSHaiyang Zhang struct rndis_filter_packet *filter_pkt = ctx; 99295fa0405SHaiyang Zhang 99395fa0405SHaiyang Zhang /* Pass it back to the original handler */ 9945fccab3bSHaiyang Zhang filter_pkt->completion(filter_pkt->completion_ctx); 99595fa0405SHaiyang Zhang } 996