blob: dbb520199756b2ef294be80d4c8376c990c0bd34 [file] [log] [blame]
Hank Janssenfceaf242009-07-13 15:34:54 -07001/*
Hank Janssenfceaf242009-07-13 15:34:54 -07002 * Copyright (c) 2009, Microsoft Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Authors:
18 * Haiyang Zhang <haiyangz@microsoft.com>
19 * Hank Janssen <hjanssen@microsoft.com>
Hank Janssenfceaf242009-07-13 15:34:54 -070020 */
Greg Kroah-Hartman5654e932009-07-14 15:08:20 -070021#include <linux/kernel.h>
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -080022#include <linux/sched.h>
23#include <linux/wait.h>
Bill Pemberton45da89e2009-07-29 17:00:15 -040024#include <linux/highmem.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -070026#include <linux/io.h>
Stephen Hemminger9f8bd8b2010-05-04 09:58:54 -070027#include <linux/if_ether.h>
Hank Jansseneb335bc2011-03-29 13:58:48 -070028#include <linux/netdevice.h>
K. Y. Srinivasan3f335ea2011-05-12 19:34:15 -070029
30#include "hyperv.h"
K. Y. Srinivasan5ca72522011-05-12 19:34:37 -070031#include "hyperv_net.h"
Hank Janssenfceaf242009-07-13 15:34:54 -070032
Hank Janssenfceaf242009-07-13 15:34:54 -070033
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070034enum rndis_device_state {
Hank Janssenfceaf242009-07-13 15:34:54 -070035 RNDIS_DEV_UNINITIALIZED = 0,
36 RNDIS_DEV_INITIALIZING,
37 RNDIS_DEV_INITIALIZED,
38 RNDIS_DEV_DATAINITIALIZED,
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070039};
Hank Janssenfceaf242009-07-13 15:34:54 -070040
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070041struct rndis_device {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080042 struct netvsc_device *net_dev;
Hank Janssenfceaf242009-07-13 15:34:54 -070043
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080044 enum rndis_device_state state;
45 u32 link_stat;
46 atomic_t new_req_id;
Hank Janssenfceaf242009-07-13 15:34:54 -070047
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -070048 spinlock_t request_lock;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080049 struct list_head req_list;
Hank Janssenfceaf242009-07-13 15:34:54 -070050
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080051 unsigned char hw_mac_adr[ETH_ALEN];
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070052};
Hank Janssenfceaf242009-07-13 15:34:54 -070053
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070054struct rndis_request {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080055 struct list_head list_ent;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -070056 struct completion wait_event;
Hank Janssenfceaf242009-07-13 15:34:54 -070057
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -070058 /*
59 * FIXME: We assumed a fixed size response here. If we do ever need to
60 * handle a bigger response, we can either define a max response
61 * message or add a response buffer variable above this field
62 */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080063 struct rndis_message response_msg;
Hank Janssenfceaf242009-07-13 15:34:54 -070064
Bill Pemberton454f18a2009-07-27 16:47:24 -040065 /* Simplify allocation by having a netvsc packet inline */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080066 struct hv_netvsc_packet pkt;
67 struct hv_page_buffer buf;
Bill Pemberton454f18a2009-07-27 16:47:24 -040068 /* FIXME: We assumed a fixed size request here. */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080069 struct rndis_message request_msg;
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070070};
Hank Janssenfceaf242009-07-13 15:34:54 -070071
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080072static void rndis_filter_send_completion(void *ctx);
Hank Janssenfceaf242009-07-13 15:34:54 -070073
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080074static void rndis_filter_send_request_completion(void *ctx);
Bill Pemberton454f18a2009-07-27 16:47:24 -040075
76
Hank Janssenfceaf242009-07-13 15:34:54 -070077
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080078static struct rndis_device *get_rndis_device(void)
Hank Janssenfceaf242009-07-13 15:34:54 -070079{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070080 struct rndis_device *device;
Hank Janssenfceaf242009-07-13 15:34:54 -070081
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070082 device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL);
Hank Janssenfceaf242009-07-13 15:34:54 -070083 if (!device)
Hank Janssenfceaf242009-07-13 15:34:54 -070084 return NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -070085
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -070086 spin_lock_init(&device->request_lock);
Hank Janssenfceaf242009-07-13 15:34:54 -070087
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080088 INIT_LIST_HEAD(&device->req_list);
Hank Janssenfceaf242009-07-13 15:34:54 -070089
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080090 device->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -070091
92 return device;
93}
94
Haiyang Zhang9c26aa02010-12-10 12:03:57 -080095static struct rndis_request *get_rndis_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -080096 u32 msg_type,
97 u32 msg_len)
Hank Janssenfceaf242009-07-13 15:34:54 -070098{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -070099 struct rndis_request *request;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800100 struct rndis_message *rndis_msg;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700101 struct rndis_set_request *set;
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700102 unsigned long flags;
Hank Janssenfceaf242009-07-13 15:34:54 -0700103
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700104 request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL);
Hank Janssenfceaf242009-07-13 15:34:54 -0700105 if (!request)
Hank Janssenfceaf242009-07-13 15:34:54 -0700106 return NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700107
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700108 init_completion(&request->wait_event);
Hank Janssenfceaf242009-07-13 15:34:54 -0700109
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800110 rndis_msg = &request->request_msg;
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800111 rndis_msg->ndis_msg_type = msg_type;
112 rndis_msg->msg_len = msg_len;
Hank Janssenfceaf242009-07-13 15:34:54 -0700113
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700114 /*
115 * Set the request id. This field is always after the rndis header for
116 * request/response packet types so we just used the SetRequest as a
117 * template
118 */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800119 set = &rndis_msg->msg.set_req;
120 set->req_id = atomic_inc_return(&dev->new_req_id);
Hank Janssenfceaf242009-07-13 15:34:54 -0700121
Bill Pemberton454f18a2009-07-27 16:47:24 -0400122 /* Add to the request list */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800123 spin_lock_irqsave(&dev->request_lock, flags);
124 list_add_tail(&request->list_ent, &dev->req_list);
125 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700126
127 return request;
128}
129
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800130static void put_rndis_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800131 struct rndis_request *req)
Hank Janssenfceaf242009-07-13 15:34:54 -0700132{
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700133 unsigned long flags;
134
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800135 spin_lock_irqsave(&dev->request_lock, flags);
136 list_del(&req->list_ent);
137 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700138
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800139 kfree(req);
Hank Janssenfceaf242009-07-13 15:34:54 -0700140}
141
Haiyang Zhang729a2842011-05-27 06:21:54 -0700142static void dump_rndis_message(struct hv_device *hv_dev,
143 struct rndis_message *rndis_msg)
Hank Janssenfceaf242009-07-13 15:34:54 -0700144{
Haiyang Zhang729a2842011-05-27 06:21:54 -0700145 struct net_device *netdev = dev_get_drvdata(&hv_dev->device);
146
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800147 switch (rndis_msg->ndis_msg_type) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700148 case REMOTE_NDIS_PACKET_MSG:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700149 netdev_dbg(netdev, "REMOTE_NDIS_PACKET_MSG (len %u, "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700150 "data offset %u data len %u, # oob %u, "
151 "oob offset %u, oob len %u, pkt offset %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700152 "pkt len %u\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800153 rndis_msg->msg_len,
154 rndis_msg->msg.pkt.data_offset,
155 rndis_msg->msg.pkt.data_len,
156 rndis_msg->msg.pkt.num_oob_data_elements,
157 rndis_msg->msg.pkt.oob_data_offset,
158 rndis_msg->msg.pkt.oob_data_len,
159 rndis_msg->msg.pkt.per_pkt_info_offset,
160 rndis_msg->msg.pkt.per_pkt_info_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700161 break;
162
163 case REMOTE_NDIS_INITIALIZE_CMPLT:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700164 netdev_dbg(netdev, "REMOTE_NDIS_INITIALIZE_CMPLT "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700165 "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
166 "device flags %d, max xfer size 0x%x, max pkts %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700167 "pkt aligned %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800168 rndis_msg->msg_len,
169 rndis_msg->msg.init_complete.req_id,
170 rndis_msg->msg.init_complete.status,
171 rndis_msg->msg.init_complete.major_ver,
172 rndis_msg->msg.init_complete.minor_ver,
173 rndis_msg->msg.init_complete.dev_flags,
174 rndis_msg->msg.init_complete.max_xfer_size,
175 rndis_msg->msg.init_complete.
176 max_pkt_per_msg,
177 rndis_msg->msg.init_complete.
178 pkt_alignment_factor);
Hank Janssenfceaf242009-07-13 15:34:54 -0700179 break;
180
181 case REMOTE_NDIS_QUERY_CMPLT:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700182 netdev_dbg(netdev, "REMOTE_NDIS_QUERY_CMPLT "
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700183 "(len %u, id 0x%x, status 0x%x, buf len %u, "
Haiyang Zhang729a2842011-05-27 06:21:54 -0700184 "buf offset %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800185 rndis_msg->msg_len,
186 rndis_msg->msg.query_complete.req_id,
187 rndis_msg->msg.query_complete.status,
188 rndis_msg->msg.query_complete.
189 info_buflen,
190 rndis_msg->msg.query_complete.
191 info_buf_offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700192 break;
193
194 case REMOTE_NDIS_SET_CMPLT:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700195 netdev_dbg(netdev,
196 "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800197 rndis_msg->msg_len,
198 rndis_msg->msg.set_complete.req_id,
199 rndis_msg->msg.set_complete.status);
Hank Janssenfceaf242009-07-13 15:34:54 -0700200 break;
201
202 case REMOTE_NDIS_INDICATE_STATUS_MSG:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700203 netdev_dbg(netdev, "REMOTE_NDIS_INDICATE_STATUS_MSG "
204 "(len %u, status 0x%x, buf len %u, buf offset %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800205 rndis_msg->msg_len,
206 rndis_msg->msg.indicate_status.status,
207 rndis_msg->msg.indicate_status.status_buflen,
208 rndis_msg->msg.indicate_status.status_buf_offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700209 break;
210
211 default:
Haiyang Zhang729a2842011-05-27 06:21:54 -0700212 netdev_dbg(netdev, "0x%x (len %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800213 rndis_msg->ndis_msg_type,
214 rndis_msg->msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700215 break;
216 }
217}
218
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800219static int rndis_filter_send_request(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800220 struct rndis_request *req)
Hank Janssenfceaf242009-07-13 15:34:54 -0700221{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700222 int ret;
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200223 struct hv_netvsc_packet *packet;
Hank Janssenfceaf242009-07-13 15:34:54 -0700224
Bill Pemberton454f18a2009-07-27 16:47:24 -0400225 /* Setup the packet to send it */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800226 packet = &req->pkt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700227
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800228 packet->is_data_pkt = false;
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800229 packet->total_data_buflen = req->request_msg.msg_len;
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800230 packet->page_buf_cnt = 1;
Hank Janssenfceaf242009-07-13 15:34:54 -0700231
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800232 packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700233 PAGE_SHIFT;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800234 packet->page_buf[0].len = req->request_msg.msg_len;
235 packet->page_buf[0].offset =
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800236 (unsigned long)&req->request_msg & (PAGE_SIZE - 1);
Hank Janssenfceaf242009-07-13 15:34:54 -0700237
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800238 packet->completion.send.send_completion_ctx = req;/* packet; */
239 packet->completion.send.send_completion =
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800240 rndis_filter_send_request_completion;
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800241 packet->completion.send.send_completion_tid = (unsigned long)dev;
Hank Janssenfceaf242009-07-13 15:34:54 -0700242
K. Y. Srinivasan0ec6ff42011-05-12 19:34:55 -0700243 ret = netvsc_send(dev->net_dev->dev, packet);
Hank Janssenfceaf242009-07-13 15:34:54 -0700244 return ret;
245}
246
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800247static void rndis_filter_receive_response(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800248 struct rndis_message *resp)
Hank Janssenfceaf242009-07-13 15:34:54 -0700249{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700250 struct rndis_request *request = NULL;
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700251 bool found = false;
Greg Kroah-Hartman880fb892009-07-15 14:55:29 -0700252 unsigned long flags;
Hank Janssenfceaf242009-07-13 15:34:54 -0700253
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800254 spin_lock_irqsave(&dev->request_lock, flags);
255 list_for_each_entry(request, &dev->req_list, list_ent) {
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700256 /*
257 * All request/response message contains RequestId as the 1st
258 * field
259 */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800260 if (request->request_msg.msg.init_req.req_id
261 == resp->msg.init_complete.req_id) {
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700262 found = true;
Hank Janssenfceaf242009-07-13 15:34:54 -0700263 break;
264 }
265 }
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800266 spin_unlock_irqrestore(&dev->request_lock, flags);
Hank Janssenfceaf242009-07-13 15:34:54 -0700267
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700268 if (found) {
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800269 if (resp->msg_len <= sizeof(struct rndis_message)) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800270 memcpy(&request->response_msg, resp,
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800271 resp->msg_len);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700272 } else {
Hank Jansseneb335bc2011-03-29 13:58:48 -0700273 dev_err(&dev->net_dev->dev->device,
274 "rndis response buffer overflow "
275 "detected (size %u max %zu)\n",
276 resp->msg_len,
277 sizeof(struct rndis_filter_packet));
Hank Janssenfceaf242009-07-13 15:34:54 -0700278
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800279 if (resp->ndis_msg_type ==
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700280 REMOTE_NDIS_RESET_CMPLT) {
281 /* does not have a request id field */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800282 request->response_msg.msg.reset_complete.
283 status = STATUS_BUFFER_OVERFLOW;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700284 } else {
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800285 request->response_msg.msg.
286 init_complete.status =
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800287 STATUS_BUFFER_OVERFLOW;
Hank Janssenfceaf242009-07-13 15:34:54 -0700288 }
289 }
290
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700291 complete(&request->wait_event);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700292 } else {
Hank Jansseneb335bc2011-03-29 13:58:48 -0700293 dev_err(&dev->net_dev->dev->device,
294 "no rndis request found for this response "
295 "(id 0x%x res type 0x%x)\n",
296 resp->msg.init_complete.req_id,
297 resp->ndis_msg_type);
Hank Janssenfceaf242009-07-13 15:34:54 -0700298 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700299}
300
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800301static void rndis_filter_receive_indicate_status(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800302 struct rndis_message *resp)
Hank Janssenfceaf242009-07-13 15:34:54 -0700303{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700304 struct rndis_indicate_status *indicate =
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800305 &resp->msg.indicate_status;
Hank Janssenfceaf242009-07-13 15:34:54 -0700306
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800307 if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) {
K. Y. Srinivasan39fb6aa2011-05-12 19:34:56 -0700308 netvsc_linkstatus_callback(
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800309 dev->net_dev->dev, 1);
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800310 } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) {
K. Y. Srinivasan39fb6aa2011-05-12 19:34:56 -0700311 netvsc_linkstatus_callback(
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800312 dev->net_dev->dev, 0);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700313 } else {
314 /*
315 * TODO:
316 */
Hank Janssenfceaf242009-07-13 15:34:54 -0700317 }
318}
319
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800320static void rndis_filter_receive_data(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800321 struct rndis_message *msg,
322 struct hv_netvsc_packet *pkt)
Hank Janssenfceaf242009-07-13 15:34:54 -0700323{
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800324 struct rndis_packet *rndis_pkt;
325 u32 data_offset;
Hank Janssenfceaf242009-07-13 15:34:54 -0700326
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800327 rndis_pkt = &msg->msg.pkt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700328
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700329 /*
330 * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this
331 * netvsc packet (ie TotalDataBufferLength != MessageLength)
332 */
Hank Janssenfceaf242009-07-13 15:34:54 -0700333
Bill Pemberton454f18a2009-07-27 16:47:24 -0400334 /* Remove the rndis header and pass it back up the stack */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800335 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
Hank Janssenfceaf242009-07-13 15:34:54 -0700336
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800337 pkt->total_data_buflen -= data_offset;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800338 pkt->page_buf[0].offset += data_offset;
339 pkt->page_buf[0].len -= data_offset;
Hank Janssenfceaf242009-07-13 15:34:54 -0700340
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800341 pkt->is_data_pkt = true;
Hank Janssenfceaf242009-07-13 15:34:54 -0700342
K. Y. Srinivasana25e1db2011-05-12 19:34:57 -0700343 netvsc_recv_callback(dev->net_dev->dev, pkt);
Hank Janssenfceaf242009-07-13 15:34:54 -0700344}
345
K. Y. Srinivasan5fcc4112011-05-12 19:34:52 -0700346int rndis_filter_receive(struct hv_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800347 struct hv_netvsc_packet *pkt)
Hank Janssenfceaf242009-07-13 15:34:54 -0700348{
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800349 struct netvsc_device *net_dev = dev->ext;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800350 struct rndis_device *rndis_dev;
351 struct rndis_message rndis_msg;
352 struct rndis_message *rndis_hdr;
Hank Janssenfceaf242009-07-13 15:34:54 -0700353
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800354 if (!net_dev)
Bill Pemberton8a62d712010-05-05 15:27:47 -0400355 return -EINVAL;
356
Bill Pemberton454f18a2009-07-27 16:47:24 -0400357 /* Make sure the rndis device state is initialized */
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800358 if (!net_dev->extension) {
Hank Jansseneb335bc2011-03-29 13:58:48 -0700359 dev_err(&dev->device, "got rndis message but no rndis device - "
360 "dropping this message!\n");
Hank Janssenfceaf242009-07-13 15:34:54 -0700361 return -1;
362 }
363
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800364 rndis_dev = (struct rndis_device *)net_dev->extension;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800365 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
Hank Jansseneb335bc2011-03-29 13:58:48 -0700366 dev_err(&dev->device, "got rndis message but rndis device "
367 "uninitialized...dropping this message!\n");
Hank Janssenfceaf242009-07-13 15:34:54 -0700368 return -1;
369 }
370
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800371 rndis_hdr = (struct rndis_message *)kmap_atomic(
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800372 pfn_to_page(pkt->page_buf[0].pfn), KM_IRQ0);
Hank Janssenfceaf242009-07-13 15:34:54 -0700373
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800374 rndis_hdr = (void *)((unsigned long)rndis_hdr +
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800375 pkt->page_buf[0].offset);
Hank Janssenfceaf242009-07-13 15:34:54 -0700376
Bill Pemberton454f18a2009-07-27 16:47:24 -0400377 /* Make sure we got a valid rndis message */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800378 if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
379 (rndis_hdr->msg_len > sizeof(struct rndis_message))) {
Hank Jansseneb335bc2011-03-29 13:58:48 -0700380 dev_err(&dev->device, "incoming rndis message buffer overflow "
381 "detected (got %u, max %zu)..marking it an error!\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800382 rndis_hdr->msg_len,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700383 sizeof(struct rndis_message));
Hank Janssenfceaf242009-07-13 15:34:54 -0700384 }
385
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800386 memcpy(&rndis_msg, rndis_hdr,
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800387 (rndis_hdr->msg_len > sizeof(struct rndis_message)) ?
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700388 sizeof(struct rndis_message) :
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800389 rndis_hdr->msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700390
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800391 kunmap_atomic(rndis_hdr - pkt->page_buf[0].offset, KM_IRQ0);
Hank Janssenfceaf242009-07-13 15:34:54 -0700392
Haiyang Zhang729a2842011-05-27 06:21:54 -0700393 dump_rndis_message(dev, &rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700394
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800395 switch (rndis_msg.ndis_msg_type) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700396 case REMOTE_NDIS_PACKET_MSG:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700397 /* data msg */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800398 rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt);
Hank Janssenfceaf242009-07-13 15:34:54 -0700399 break;
400
Hank Janssenfceaf242009-07-13 15:34:54 -0700401 case REMOTE_NDIS_INITIALIZE_CMPLT:
402 case REMOTE_NDIS_QUERY_CMPLT:
403 case REMOTE_NDIS_SET_CMPLT:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700404 /* completion msgs */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800405 rndis_filter_receive_response(rndis_dev, &rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700406 break;
407
Hank Janssenfceaf242009-07-13 15:34:54 -0700408 case REMOTE_NDIS_INDICATE_STATUS_MSG:
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700409 /* notification msgs */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800410 rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg);
Hank Janssenfceaf242009-07-13 15:34:54 -0700411 break;
412 default:
Hank Jansseneb335bc2011-03-29 13:58:48 -0700413 dev_err(&dev->device,
414 "unhandled rndis message (type %u len %u)\n",
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800415 rndis_msg.ndis_msg_type,
416 rndis_msg.msg_len);
Hank Janssenfceaf242009-07-13 15:34:54 -0700417 break;
418 }
419
Hank Janssenfceaf242009-07-13 15:34:54 -0700420 return 0;
421}
422
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800423static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800424 void *result, u32 *result_size)
Hank Janssenfceaf242009-07-13 15:34:54 -0700425{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700426 struct rndis_request *request;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800427 u32 inresult_size = *result_size;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700428 struct rndis_query_request *query;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800429 struct rndis_query_complete *query_complete;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700430 int ret = 0;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700431 int t;
Hank Janssenfceaf242009-07-13 15:34:54 -0700432
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800433 if (!result)
Bill Pemberton8a62d712010-05-05 15:27:47 -0400434 return -EINVAL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700435
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800436 *result_size = 0;
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800437 request = get_rndis_request(dev, REMOTE_NDIS_QUERY_MSG,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700438 RNDIS_MESSAGE_SIZE(struct rndis_query_request));
439 if (!request) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700440 ret = -1;
441 goto Cleanup;
442 }
443
Bill Pemberton454f18a2009-07-27 16:47:24 -0400444 /* Setup the rndis query */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800445 query = &request->request_msg.msg.query_req;
446 query->oid = oid;
447 query->info_buf_offset = sizeof(struct rndis_query_request);
448 query->info_buflen = 0;
449 query->dev_vc_handle = 0;
Hank Janssenfceaf242009-07-13 15:34:54 -0700450
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800451 ret = rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700452 if (ret != 0)
Hank Janssenfceaf242009-07-13 15:34:54 -0700453 goto Cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700454
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700455 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700456 if (t == 0) {
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800457 ret = -ETIMEDOUT;
458 goto Cleanup;
459 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700460
Bill Pemberton454f18a2009-07-27 16:47:24 -0400461 /* Copy the response back */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800462 query_complete = &request->response_msg.msg.query_complete;
Hank Janssenfceaf242009-07-13 15:34:54 -0700463
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800464 if (query_complete->info_buflen > inresult_size) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700465 ret = -1;
466 goto Cleanup;
467 }
468
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800469 memcpy(result,
470 (void *)((unsigned long)query_complete +
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800471 query_complete->info_buf_offset),
472 query_complete->info_buflen);
Hank Janssenfceaf242009-07-13 15:34:54 -0700473
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800474 *result_size = query_complete->info_buflen;
Hank Janssenfceaf242009-07-13 15:34:54 -0700475
476Cleanup:
477 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800478 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700479
480 return ret;
481}
482
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800483static int rndis_filter_query_device_mac(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700484{
Stephen Hemminger9f8bd8b2010-05-04 09:58:54 -0700485 u32 size = ETH_ALEN;
Hank Janssenfceaf242009-07-13 15:34:54 -0700486
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800487 return rndis_filter_query_device(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700488 RNDIS_OID_802_3_PERMANENT_ADDRESS,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800489 dev->hw_mac_adr, &size);
Hank Janssenfceaf242009-07-13 15:34:54 -0700490}
491
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800492static int rndis_filter_query_device_link_status(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700493{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700494 u32 size = sizeof(u32);
Hank Janssenfceaf242009-07-13 15:34:54 -0700495
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800496 return rndis_filter_query_device(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700497 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800498 &dev->link_stat, &size);
Hank Janssenfceaf242009-07-13 15:34:54 -0700499}
500
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800501static int rndis_filter_set_packet_filter(struct rndis_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800502 u32 new_filter)
Hank Janssenfceaf242009-07-13 15:34:54 -0700503{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700504 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700505 struct rndis_set_request *set;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800506 struct rndis_set_complete *set_complete;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700507 u32 status;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700508 int ret, t;
Hank Janssenfceaf242009-07-13 15:34:54 -0700509
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800510 request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700511 RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
512 sizeof(u32));
513 if (!request) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700514 ret = -1;
515 goto Cleanup;
516 }
517
Bill Pemberton454f18a2009-07-27 16:47:24 -0400518 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800519 set = &request->request_msg.msg.set_req;
520 set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
521 set->info_buflen = sizeof(u32);
522 set->info_buf_offset = sizeof(struct rndis_set_request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700523
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700524 memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800525 &new_filter, sizeof(u32));
Hank Janssenfceaf242009-07-13 15:34:54 -0700526
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800527 ret = rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700528 if (ret != 0)
Hank Janssenfceaf242009-07-13 15:34:54 -0700529 goto Cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700530
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700531 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700532
533 if (t == 0) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700534 ret = -1;
Hank Jansseneb335bc2011-03-29 13:58:48 -0700535 dev_err(&dev->net_dev->dev->device,
536 "timeout before we got a set response...\n");
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700537 /*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300538 * We can't deallocate the request since we may still receive a
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700539 * send completion for it.
540 */
Hank Janssenfceaf242009-07-13 15:34:54 -0700541 goto Exit;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700542 } else {
Hank Janssenfceaf242009-07-13 15:34:54 -0700543 if (ret > 0)
Hank Janssenfceaf242009-07-13 15:34:54 -0700544 ret = 0;
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800545 set_complete = &request->response_msg.msg.set_complete;
546 status = set_complete->status;
Hank Janssenfceaf242009-07-13 15:34:54 -0700547 }
548
549Cleanup:
550 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800551 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700552Exit:
Hank Janssenfceaf242009-07-13 15:34:54 -0700553 return ret;
554}
555
Hank Janssenfceaf242009-07-13 15:34:54 -0700556
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800557static int rndis_filter_init_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700558{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700559 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700560 struct rndis_initialize_request *init;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800561 struct rndis_initialize_complete *init_complete;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700562 u32 status;
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700563 int ret, t;
Hank Janssenfceaf242009-07-13 15:34:54 -0700564
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800565 request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700566 RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
567 if (!request) {
Hank Janssenfceaf242009-07-13 15:34:54 -0700568 ret = -1;
569 goto Cleanup;
570 }
571
Bill Pemberton454f18a2009-07-27 16:47:24 -0400572 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800573 init = &request->request_msg.msg.init_req;
574 init->major_ver = RNDIS_MAJOR_VERSION;
575 init->minor_ver = RNDIS_MINOR_VERSION;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700576 /* FIXME: Use 1536 - rounded ethernet frame size */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800577 init->max_xfer_size = 2048;
Hank Janssenfceaf242009-07-13 15:34:54 -0700578
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800579 dev->state = RNDIS_DEV_INITIALIZING;
Hank Janssenfceaf242009-07-13 15:34:54 -0700580
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800581 ret = rndis_filter_send_request(dev, request);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700582 if (ret != 0) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800583 dev->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700584 goto Cleanup;
585 }
586
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800587
K. Y. Srinivasan5c5781b32011-06-16 13:16:35 -0700588 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
K. Y. Srinivasan98d79692011-05-10 07:55:42 -0700589
590 if (t == 0) {
K. Y. Srinivasan0c3b7b22011-02-11 09:59:43 -0800591 ret = -ETIMEDOUT;
592 goto Cleanup;
593 }
Hank Janssenfceaf242009-07-13 15:34:54 -0700594
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800595 init_complete = &request->response_msg.msg.init_complete;
596 status = init_complete->status;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700597 if (status == RNDIS_STATUS_SUCCESS) {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800598 dev->state = RNDIS_DEV_INITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700599 ret = 0;
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700600 } else {
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800601 dev->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700602 ret = -1;
603 }
604
605Cleanup:
606 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800607 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700608
609 return ret;
610}
611
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800612static void rndis_filter_halt_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700613{
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700614 struct rndis_request *request;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700615 struct rndis_halt_request *halt;
Hank Janssenfceaf242009-07-13 15:34:54 -0700616
Bill Pemberton454f18a2009-07-27 16:47:24 -0400617 /* Attempt to do a rndis device halt */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800618 request = get_rndis_request(dev, REMOTE_NDIS_HALT_MSG,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700619 RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
Hank Janssenfceaf242009-07-13 15:34:54 -0700620 if (!request)
Hank Janssenfceaf242009-07-13 15:34:54 -0700621 goto Cleanup;
Hank Janssenfceaf242009-07-13 15:34:54 -0700622
Bill Pemberton454f18a2009-07-27 16:47:24 -0400623 /* Setup the rndis set */
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800624 halt = &request->request_msg.msg.halt_req;
625 halt->req_id = atomic_inc_return(&dev->new_req_id);
Hank Janssenfceaf242009-07-13 15:34:54 -0700626
Bill Pemberton454f18a2009-07-27 16:47:24 -0400627 /* Ignore return since this msg is optional. */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800628 rndis_filter_send_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700629
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800630 dev->state = RNDIS_DEV_UNINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700631
632Cleanup:
633 if (request)
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800634 put_rndis_request(dev, request);
Hank Janssenfceaf242009-07-13 15:34:54 -0700635 return;
636}
637
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800638static int rndis_filter_open_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700639{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700640 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700641
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800642 if (dev->state != RNDIS_DEV_INITIALIZED)
Hank Janssenfceaf242009-07-13 15:34:54 -0700643 return 0;
644
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800645 ret = rndis_filter_set_packet_filter(dev,
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700646 NDIS_PACKET_TYPE_BROADCAST |
Haiyang Zhang95beae92010-04-19 15:32:11 +0000647 NDIS_PACKET_TYPE_ALL_MULTICAST |
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700648 NDIS_PACKET_TYPE_DIRECTED);
Hank Janssenfceaf242009-07-13 15:34:54 -0700649 if (ret == 0)
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800650 dev->state = RNDIS_DEV_DATAINITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700651
Hank Janssenfceaf242009-07-13 15:34:54 -0700652 return ret;
653}
654
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800655static int rndis_filter_close_device(struct rndis_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700656{
657 int ret;
658
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800659 if (dev->state != RNDIS_DEV_DATAINITIALIZED)
Hank Janssenfceaf242009-07-13 15:34:54 -0700660 return 0;
661
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800662 ret = rndis_filter_set_packet_filter(dev, 0);
Hank Janssenfceaf242009-07-13 15:34:54 -0700663 if (ret == 0)
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800664 dev->state = RNDIS_DEV_INITIALIZED;
Hank Janssenfceaf242009-07-13 15:34:54 -0700665
Hank Janssenfceaf242009-07-13 15:34:54 -0700666 return ret;
667}
668
Haiyang Zhangbdbad572011-05-23 09:03:49 -0700669int rndis_filter_device_add(struct hv_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800670 void *additional_info)
Hank Janssenfceaf242009-07-13 15:34:54 -0700671{
672 int ret;
Greg Kroah-Hartmance9ea4c2009-09-02 10:35:56 -0700673 struct netvsc_device *netDevice;
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700674 struct rndis_device *rndisDevice;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800675 struct netvsc_device_info *deviceInfo = additional_info;
Hank Janssenfceaf242009-07-13 15:34:54 -0700676
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800677 rndisDevice = get_rndis_device();
Greg Kroah-Hartman83c720e2010-07-22 15:14:04 -0700678 if (!rndisDevice)
Hank Janssenfceaf242009-07-13 15:34:54 -0700679 return -1;
Hank Janssenfceaf242009-07-13 15:34:54 -0700680
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700681 /*
682 * Let the inner driver handle this first to create the netvsc channel
683 * NOTE! Once the channel is created, we may get a receive callback
684 * (RndisFilterOnReceive()) before this call is completed
685 */
K. Y. Srinivasance5bf662011-05-10 07:55:00 -0700686 ret = netvsc_device_add(dev, additional_info);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700687 if (ret != 0) {
688 kfree(rndisDevice);
Hank Janssenfceaf242009-07-13 15:34:54 -0700689 return ret;
690 }
691
Bill Pemberton454f18a2009-07-27 16:47:24 -0400692
693 /* Initialize the rndis device */
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800694 netDevice = dev->ext;
Hank Janssenfceaf242009-07-13 15:34:54 -0700695
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800696 netDevice->extension = rndisDevice;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800697 rndisDevice->net_dev = netDevice;
Hank Janssenfceaf242009-07-13 15:34:54 -0700698
Bill Pemberton454f18a2009-07-27 16:47:24 -0400699 /* Send the rndis initialization message */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800700 ret = rndis_filter_init_device(rndisDevice);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700701 if (ret != 0) {
702 /*
703 * TODO: If rndis init failed, we will need to shut down the
704 * channel
705 */
Hank Janssenfceaf242009-07-13 15:34:54 -0700706 }
707
Bill Pemberton454f18a2009-07-27 16:47:24 -0400708 /* Get the mac address */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800709 ret = rndis_filter_query_device_mac(rndisDevice);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700710 if (ret != 0) {
711 /*
712 * TODO: shutdown rndis device and the channel
713 */
Hank Janssenfceaf242009-07-13 15:34:54 -0700714 }
715
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800716 memcpy(deviceInfo->mac_adr, rndisDevice->hw_mac_adr, ETH_ALEN);
Hank Janssenfceaf242009-07-13 15:34:54 -0700717
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800718 rndis_filter_query_device_link_status(rndisDevice);
Hank Janssenfceaf242009-07-13 15:34:54 -0700719
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800720 deviceInfo->link_state = rndisDevice->link_stat;
Hank Jansseneb335bc2011-03-29 13:58:48 -0700721
722 dev_info(&dev->device, "Device MAC %pM link state %s",
723 rndisDevice->hw_mac_adr,
724 ((deviceInfo->link_state) ? ("down\n") : ("up\n")));
Hank Janssenfceaf242009-07-13 15:34:54 -0700725
Hank Janssenfceaf242009-07-13 15:34:54 -0700726 return ret;
727}
728
Haiyang Zhangdf06bcf2011-05-23 09:03:47 -0700729void rndis_filter_device_remove(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700730{
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800731 struct netvsc_device *net_dev = dev->ext;
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800732 struct rndis_device *rndis_dev = net_dev->extension;
Hank Janssenfceaf242009-07-13 15:34:54 -0700733
Bill Pemberton454f18a2009-07-27 16:47:24 -0400734 /* Halt and release the rndis device */
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800735 rndis_filter_halt_device(rndis_dev);
Hank Janssenfceaf242009-07-13 15:34:54 -0700736
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800737 kfree(rndis_dev);
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800738 net_dev->extension = NULL;
Hank Janssenfceaf242009-07-13 15:34:54 -0700739
K. Y. Srinivasan3fae5c82011-05-10 07:55:02 -0700740 netvsc_device_remove(dev);
Hank Janssenfceaf242009-07-13 15:34:54 -0700741}
742
Hank Janssenfceaf242009-07-13 15:34:54 -0700743
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800744int rndis_filter_open(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700745{
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800746 struct netvsc_device *netDevice = dev->ext;
Hank Janssenfceaf242009-07-13 15:34:54 -0700747
Bill Pemberton8a62d712010-05-05 15:27:47 -0400748 if (!netDevice)
749 return -EINVAL;
750
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800751 return rndis_filter_open_device(netDevice->extension);
Hank Janssenfceaf242009-07-13 15:34:54 -0700752}
753
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800754int rndis_filter_close(struct hv_device *dev)
Hank Janssenfceaf242009-07-13 15:34:54 -0700755{
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800756 struct netvsc_device *netDevice = dev->ext;
Hank Janssenfceaf242009-07-13 15:34:54 -0700757
Bill Pemberton8a62d712010-05-05 15:27:47 -0400758 if (!netDevice)
759 return -EINVAL;
760
Haiyang Zhang53d21fd2010-12-10 12:03:59 -0800761 return rndis_filter_close_device(netDevice->extension);
Hank Janssenfceaf242009-07-13 15:34:54 -0700762}
763
K. Y. Srinivasan0652aeb2011-05-12 19:34:53 -0700764int rndis_filter_send(struct hv_device *dev,
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800765 struct hv_netvsc_packet *pkt)
Hank Janssenfceaf242009-07-13 15:34:54 -0700766{
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700767 int ret;
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700768 struct rndis_filter_packet *filterPacket;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700769 struct rndis_message *rndisMessage;
770 struct rndis_packet *rndisPacket;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700771 u32 rndisMessageSize;
Hank Janssenfceaf242009-07-13 15:34:54 -0700772
Bill Pemberton454f18a2009-07-27 16:47:24 -0400773 /* Add the rndis header */
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800774 filterPacket = (struct rndis_filter_packet *)pkt->extension;
Hank Janssenfceaf242009-07-13 15:34:54 -0700775
Greg Kroah-Hartmane681b952009-08-28 16:26:27 -0700776 memset(filterPacket, 0, sizeof(struct rndis_filter_packet));
Hank Janssenfceaf242009-07-13 15:34:54 -0700777
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800778 rndisMessage = &filterPacket->msg;
Greg Kroah-Hartman9f33d052009-08-19 16:26:24 -0700779 rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet);
Hank Janssenfceaf242009-07-13 15:34:54 -0700780
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800781 rndisMessage->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
782 rndisMessage->msg_len = pkt->total_data_buflen +
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700783 rndisMessageSize;
Hank Janssenfceaf242009-07-13 15:34:54 -0700784
Haiyang Zhanga388eb12010-12-10 12:04:00 -0800785 rndisPacket = &rndisMessage->msg.pkt;
786 rndisPacket->data_offset = sizeof(struct rndis_packet);
787 rndisPacket->data_len = pkt->total_data_buflen;
Hank Janssenfceaf242009-07-13 15:34:54 -0700788
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800789 pkt->is_data_pkt = true;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800790 pkt->page_buf[0].pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT;
791 pkt->page_buf[0].offset =
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700792 (unsigned long)rndisMessage & (PAGE_SIZE-1);
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800793 pkt->page_buf[0].len = rndisMessageSize;
Hank Janssenfceaf242009-07-13 15:34:54 -0700794
Bill Pemberton454f18a2009-07-27 16:47:24 -0400795 /* Save the packet send completion and context */
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800796 filterPacket->completion = pkt->completion.send.send_completion;
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800797 filterPacket->completion_ctx =
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800798 pkt->completion.send.send_completion_ctx;
Hank Janssenfceaf242009-07-13 15:34:54 -0700799
Bill Pemberton454f18a2009-07-27 16:47:24 -0400800 /* Use ours */
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800801 pkt->completion.send.send_completion = rndis_filter_send_completion;
802 pkt->completion.send.send_completion_ctx = filterPacket;
Hank Janssenfceaf242009-07-13 15:34:54 -0700803
K. Y. Srinivasan0ec6ff42011-05-12 19:34:55 -0700804 ret = netvsc_send(dev, pkt);
Greg Kroah-Hartman0120ee02009-09-02 09:17:52 -0700805 if (ret != 0) {
806 /*
807 * Reset the completion to originals to allow retries from
808 * above
809 */
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800810 pkt->completion.send.send_completion =
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800811 filterPacket->completion;
Haiyang Zhang72a2f5b2010-12-10 12:03:58 -0800812 pkt->completion.send.send_completion_ctx =
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800813 filterPacket->completion_ctx;
Hank Janssenfceaf242009-07-13 15:34:54 -0700814 }
815
Hank Janssenfceaf242009-07-13 15:34:54 -0700816 return ret;
817}
818
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800819static void rndis_filter_send_completion(void *ctx)
Hank Janssenfceaf242009-07-13 15:34:54 -0700820{
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800821 struct rndis_filter_packet *filterPacket = ctx;
Hank Janssenfceaf242009-07-13 15:34:54 -0700822
Bill Pemberton454f18a2009-07-27 16:47:24 -0400823 /* Pass it back to the original handler */
Haiyang Zhangc2a4efd2010-12-10 12:03:56 -0800824 filterPacket->completion(filterPacket->completion_ctx);
Hank Janssenfceaf242009-07-13 15:34:54 -0700825}
826
827
Haiyang Zhang9c26aa02010-12-10 12:03:57 -0800828static void rndis_filter_send_request_completion(void *ctx)
Hank Janssenfceaf242009-07-13 15:34:54 -0700829{
Bill Pemberton454f18a2009-07-27 16:47:24 -0400830 /* Noop */
Hank Janssenfceaf242009-07-13 15:34:54 -0700831}