Commit | Line | Data |
---|---|---|
fceaf24a | 1 | /* |
fceaf24a HJ |
2 | * 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> | |
fceaf24a | 20 | */ |
5654e932 | 21 | #include <linux/kernel.h> |
45da89e5 | 22 | #include <linux/highmem.h> |
5a0e3ad6 | 23 | #include <linux/slab.h> |
0120ee0d | 24 | #include <linux/io.h> |
4983b39a | 25 | #include "osd.h" |
645954c5 | 26 | #include "logging.h" |
cc211812 | 27 | #include "NetVscApi.h" |
fceaf24a HJ |
28 | #include "RndisFilter.h" |
29 | ||
454f18a9 | 30 | /* Data types */ |
e681b954 | 31 | struct rndis_filter_driver_object { |
454f18a9 | 32 | /* The original driver */ |
7e23a6e9 | 33 | struct netvsc_driver InnerDriver; |
e681b954 | 34 | }; |
fceaf24a | 35 | |
e681b954 | 36 | enum rndis_device_state { |
fceaf24a HJ |
37 | RNDIS_DEV_UNINITIALIZED = 0, |
38 | RNDIS_DEV_INITIALIZING, | |
39 | RNDIS_DEV_INITIALIZED, | |
40 | RNDIS_DEV_DATAINITIALIZED, | |
e681b954 | 41 | }; |
fceaf24a | 42 | |
e681b954 | 43 | struct rndis_device { |
ce9ea4cf | 44 | struct netvsc_device *NetDevice; |
fceaf24a | 45 | |
e681b954 | 46 | enum rndis_device_state State; |
0120ee0d | 47 | u32 LinkStatus; |
f4888417 | 48 | atomic_t NewRequestId; |
fceaf24a | 49 | |
880fb89c | 50 | spinlock_t request_lock; |
1f5459bc | 51 | struct list_head RequestList; |
fceaf24a | 52 | |
0120ee0d | 53 | unsigned char HwMacAddr[HW_MACADDR_LEN]; |
e681b954 | 54 | }; |
fceaf24a | 55 | |
e681b954 | 56 | struct rndis_request { |
1f5459bc | 57 | struct list_head ListEntry; |
aedb444a | 58 | struct osd_waitevent *WaitEvent; |
fceaf24a | 59 | |
0120ee0d GKH |
60 | /* |
61 | * FIXME: We assumed a fixed size response here. If we do ever need to | |
62 | * handle a bigger response, we can either define a max response | |
63 | * message or add a response buffer variable above this field | |
64 | */ | |
9f33d054 | 65 | struct rndis_message ResponseMessage; |
fceaf24a | 66 | |
454f18a9 | 67 | /* Simplify allocation by having a netvsc packet inline */ |
4193d4f4 | 68 | struct hv_netvsc_packet Packet; |
ee3d7ddf | 69 | struct hv_page_buffer Buffer; |
454f18a9 | 70 | /* FIXME: We assumed a fixed size request here. */ |
9f33d054 | 71 | struct rndis_message RequestMessage; |
e681b954 | 72 | }; |
fceaf24a HJ |
73 | |
74 | ||
e681b954 | 75 | struct rndis_filter_packet { |
0120ee0d | 76 | void *CompletionContext; |
211ccd6e | 77 | void (*OnCompletion)(void *context); |
9f33d054 | 78 | struct rndis_message Message; |
e681b954 | 79 | }; |
fceaf24a | 80 | |
454f18a9 | 81 | |
0120ee0d GKH |
82 | static int RndisFilterOnDeviceAdd(struct hv_device *Device, |
83 | void *AdditionalInfo); | |
454f18a9 | 84 | |
0120ee0d | 85 | static int RndisFilterOnDeviceRemove(struct hv_device *Device); |
fceaf24a | 86 | |
0120ee0d | 87 | static void RndisFilterOnCleanup(struct hv_driver *Driver); |
fceaf24a | 88 | |
0120ee0d GKH |
89 | static int RndisFilterOnSend(struct hv_device *Device, |
90 | struct hv_netvsc_packet *Packet); | |
91 | ||
92 | static void RndisFilterOnSendCompletion(void *Context); | |
93 | ||
94 | static void RndisFilterOnSendRequestCompletion(void *Context); | |
454f18a9 BP |
95 | |
96 | ||
97 | /* The one and only */ | |
e681b954 | 98 | static struct rndis_filter_driver_object gRndisFilter; |
fceaf24a | 99 | |
0120ee0d | 100 | static struct rndis_device *GetRndisDevice(void) |
fceaf24a | 101 | { |
e681b954 | 102 | struct rndis_device *device; |
fceaf24a | 103 | |
e681b954 | 104 | device = kzalloc(sizeof(struct rndis_device), GFP_KERNEL); |
fceaf24a | 105 | if (!device) |
fceaf24a | 106 | return NULL; |
fceaf24a | 107 | |
880fb89c | 108 | spin_lock_init(&device->request_lock); |
fceaf24a | 109 | |
1f5459bc | 110 | INIT_LIST_HEAD(&device->RequestList); |
fceaf24a HJ |
111 | |
112 | device->State = RNDIS_DEV_UNINITIALIZED; | |
113 | ||
114 | return device; | |
115 | } | |
116 | ||
0120ee0d GKH |
117 | static struct rndis_request *GetRndisRequest(struct rndis_device *Device, |
118 | u32 MessageType, | |
119 | u32 MessageLength) | |
fceaf24a | 120 | { |
e681b954 | 121 | struct rndis_request *request; |
9f33d054 GKH |
122 | struct rndis_message *rndisMessage; |
123 | struct rndis_set_request *set; | |
880fb89c | 124 | unsigned long flags; |
fceaf24a | 125 | |
e681b954 | 126 | request = kzalloc(sizeof(struct rndis_request), GFP_KERNEL); |
fceaf24a | 127 | if (!request) |
fceaf24a | 128 | return NULL; |
fceaf24a | 129 | |
bfc30aae | 130 | request->WaitEvent = osd_WaitEventCreate(); |
0120ee0d | 131 | if (!request->WaitEvent) { |
8c69f52a | 132 | kfree(request); |
fceaf24a HJ |
133 | return NULL; |
134 | } | |
135 | ||
136 | rndisMessage = &request->RequestMessage; | |
137 | rndisMessage->NdisMessageType = MessageType; | |
138 | rndisMessage->MessageLength = MessageLength; | |
139 | ||
0120ee0d GKH |
140 | /* |
141 | * Set the request id. This field is always after the rndis header for | |
142 | * request/response packet types so we just used the SetRequest as a | |
143 | * template | |
144 | */ | |
fceaf24a | 145 | set = &rndisMessage->Message.SetRequest; |
f4888417 | 146 | set->RequestId = atomic_inc_return(&Device->NewRequestId); |
fceaf24a | 147 | |
454f18a9 | 148 | /* Add to the request list */ |
880fb89c | 149 | spin_lock_irqsave(&Device->request_lock, flags); |
1f5459bc | 150 | list_add_tail(&request->ListEntry, &Device->RequestList); |
880fb89c | 151 | spin_unlock_irqrestore(&Device->request_lock, flags); |
fceaf24a HJ |
152 | |
153 | return request; | |
154 | } | |
155 | ||
0120ee0d GKH |
156 | static void PutRndisRequest(struct rndis_device *Device, |
157 | struct rndis_request *Request) | |
fceaf24a | 158 | { |
880fb89c GKH |
159 | unsigned long flags; |
160 | ||
161 | spin_lock_irqsave(&Device->request_lock, flags); | |
1f5459bc | 162 | list_del(&Request->ListEntry); |
880fb89c | 163 | spin_unlock_irqrestore(&Device->request_lock, flags); |
fceaf24a | 164 | |
420beac4 | 165 | kfree(Request->WaitEvent); |
8c69f52a | 166 | kfree(Request); |
fceaf24a HJ |
167 | } |
168 | ||
0120ee0d | 169 | static void DumpRndisMessage(struct rndis_message *RndisMessage) |
fceaf24a | 170 | { |
0120ee0d | 171 | switch (RndisMessage->NdisMessageType) { |
fceaf24a | 172 | case REMOTE_NDIS_PACKET_MSG: |
0120ee0d GKH |
173 | DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, " |
174 | "data offset %u data len %u, # oob %u, " | |
175 | "oob offset %u, oob len %u, pkt offset %u, " | |
176 | "pkt len %u", | |
177 | RndisMessage->MessageLength, | |
178 | RndisMessage->Message.Packet.DataOffset, | |
179 | RndisMessage->Message.Packet.DataLength, | |
180 | RndisMessage->Message.Packet.NumOOBDataElements, | |
181 | RndisMessage->Message.Packet.OOBDataOffset, | |
182 | RndisMessage->Message.Packet.OOBDataLength, | |
183 | RndisMessage->Message.Packet.PerPacketInfoOffset, | |
184 | RndisMessage->Message.Packet.PerPacketInfoLength); | |
fceaf24a HJ |
185 | break; |
186 | ||
187 | case REMOTE_NDIS_INITIALIZE_CMPLT: | |
0120ee0d GKH |
188 | DPRINT_DBG(NETVSC, "REMOTE_NDIS_INITIALIZE_CMPLT " |
189 | "(len %u, id 0x%x, status 0x%x, major %d, minor %d, " | |
190 | "device flags %d, max xfer size 0x%x, max pkts %u, " | |
191 | "pkt aligned %u)", | |
fceaf24a HJ |
192 | RndisMessage->MessageLength, |
193 | RndisMessage->Message.InitializeComplete.RequestId, | |
194 | RndisMessage->Message.InitializeComplete.Status, | |
195 | RndisMessage->Message.InitializeComplete.MajorVersion, | |
196 | RndisMessage->Message.InitializeComplete.MinorVersion, | |
197 | RndisMessage->Message.InitializeComplete.DeviceFlags, | |
198 | RndisMessage->Message.InitializeComplete.MaxTransferSize, | |
199 | RndisMessage->Message.InitializeComplete.MaxPacketsPerMessage, | |
200 | RndisMessage->Message.InitializeComplete.PacketAlignmentFactor); | |
201 | break; | |
202 | ||
203 | case REMOTE_NDIS_QUERY_CMPLT: | |
0120ee0d GKH |
204 | DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT " |
205 | "(len %u, id 0x%x, status 0x%x, buf len %u, " | |
206 | "buf offset %u)", | |
fceaf24a HJ |
207 | RndisMessage->MessageLength, |
208 | RndisMessage->Message.QueryComplete.RequestId, | |
209 | RndisMessage->Message.QueryComplete.Status, | |
210 | RndisMessage->Message.QueryComplete.InformationBufferLength, | |
211 | RndisMessage->Message.QueryComplete.InformationBufferOffset); | |
212 | break; | |
213 | ||
214 | case REMOTE_NDIS_SET_CMPLT: | |
0120ee0d GKH |
215 | DPRINT_DBG(NETVSC, |
216 | "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)", | |
fceaf24a HJ |
217 | RndisMessage->MessageLength, |
218 | RndisMessage->Message.SetComplete.RequestId, | |
219 | RndisMessage->Message.SetComplete.Status); | |
220 | break; | |
221 | ||
222 | case REMOTE_NDIS_INDICATE_STATUS_MSG: | |
0120ee0d GKH |
223 | DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG " |
224 | "(len %u, status 0x%x, buf len %u, buf offset %u)", | |
fceaf24a HJ |
225 | RndisMessage->MessageLength, |
226 | RndisMessage->Message.IndicateStatus.Status, | |
227 | RndisMessage->Message.IndicateStatus.StatusBufferLength, | |
228 | RndisMessage->Message.IndicateStatus.StatusBufferOffset); | |
229 | break; | |
230 | ||
231 | default: | |
232 | DPRINT_DBG(NETVSC, "0x%x (len %u)", | |
233 | RndisMessage->NdisMessageType, | |
234 | RndisMessage->MessageLength); | |
235 | break; | |
236 | } | |
237 | } | |
238 | ||
0120ee0d GKH |
239 | static int RndisFilterSendRequest(struct rndis_device *Device, |
240 | struct rndis_request *Request) | |
fceaf24a | 241 | { |
0120ee0d | 242 | int ret; |
4193d4f4 | 243 | struct hv_netvsc_packet *packet; |
fceaf24a HJ |
244 | |
245 | DPRINT_ENTER(NETVSC); | |
246 | ||
454f18a9 | 247 | /* Setup the packet to send it */ |
fceaf24a HJ |
248 | packet = &Request->Packet; |
249 | ||
0e727613 | 250 | packet->IsDataPacket = false; |
fceaf24a HJ |
251 | packet->TotalDataBufferLength = Request->RequestMessage.MessageLength; |
252 | packet->PageBufferCount = 1; | |
253 | ||
0120ee0d GKH |
254 | packet->PageBuffers[0].Pfn = virt_to_phys(&Request->RequestMessage) >> |
255 | PAGE_SHIFT; | |
fceaf24a | 256 | packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength; |
0120ee0d GKH |
257 | packet->PageBuffers[0].Offset = |
258 | (unsigned long)&Request->RequestMessage & (PAGE_SIZE - 1); | |
fceaf24a | 259 | |
454f18a9 | 260 | packet->Completion.Send.SendCompletionContext = Request;/* packet; */ |
0120ee0d GKH |
261 | packet->Completion.Send.OnSendCompletion = |
262 | RndisFilterOnSendRequestCompletion; | |
c4b0bc94 | 263 | packet->Completion.Send.SendCompletionTid = (unsigned long)Device; |
fceaf24a HJ |
264 | |
265 | ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet); | |
266 | DPRINT_EXIT(NETVSC); | |
267 | return ret; | |
268 | } | |
269 | ||
e681b954 | 270 | static void RndisFilterReceiveResponse(struct rndis_device *Device, |
9f33d054 | 271 | struct rndis_message *Response) |
fceaf24a | 272 | { |
e681b954 | 273 | struct rndis_request *request = NULL; |
0e727613 | 274 | bool found = false; |
880fb89c | 275 | unsigned long flags; |
fceaf24a HJ |
276 | |
277 | DPRINT_ENTER(NETVSC); | |
278 | ||
880fb89c | 279 | spin_lock_irqsave(&Device->request_lock, flags); |
1f5459bc | 280 | list_for_each_entry(request, &Device->RequestList, ListEntry) { |
0120ee0d GKH |
281 | /* |
282 | * All request/response message contains RequestId as the 1st | |
283 | * field | |
284 | */ | |
285 | if (request->RequestMessage.Message.InitializeRequest.RequestId | |
286 | == Response->Message.InitializeComplete.RequestId) { | |
287 | DPRINT_DBG(NETVSC, "found rndis request for " | |
288 | "this response (id 0x%x req type 0x%x res " | |
289 | "type 0x%x)", | |
290 | request->RequestMessage.Message.InitializeRequest.RequestId, | |
291 | request->RequestMessage.NdisMessageType, | |
292 | Response->NdisMessageType); | |
fceaf24a | 293 | |
0e727613 | 294 | found = true; |
fceaf24a HJ |
295 | break; |
296 | } | |
297 | } | |
880fb89c | 298 | spin_unlock_irqrestore(&Device->request_lock, flags); |
fceaf24a | 299 | |
0120ee0d GKH |
300 | if (found) { |
301 | if (Response->MessageLength <= sizeof(struct rndis_message)) { | |
302 | memcpy(&request->ResponseMessage, Response, | |
303 | Response->MessageLength); | |
304 | } else { | |
305 | DPRINT_ERR(NETVSC, "rndis response buffer overflow " | |
306 | "detected (size %u max %zu)", | |
307 | Response->MessageLength, | |
308 | sizeof(struct rndis_filter_packet)); | |
309 | ||
310 | if (Response->NdisMessageType == | |
311 | REMOTE_NDIS_RESET_CMPLT) { | |
312 | /* does not have a request id field */ | |
fceaf24a | 313 | request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW; |
0120ee0d | 314 | } else { |
fceaf24a HJ |
315 | request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW; |
316 | } | |
317 | } | |
318 | ||
bfc30aae | 319 | osd_WaitEventSet(request->WaitEvent); |
0120ee0d GKH |
320 | } else { |
321 | DPRINT_ERR(NETVSC, "no rndis request found for this response " | |
322 | "(id 0x%x res type 0x%x)", | |
323 | Response->Message.InitializeComplete.RequestId, | |
324 | Response->NdisMessageType); | |
fceaf24a HJ |
325 | } |
326 | ||
327 | DPRINT_EXIT(NETVSC); | |
328 | } | |
329 | ||
e681b954 | 330 | static void RndisFilterReceiveIndicateStatus(struct rndis_device *Device, |
9f33d054 | 331 | struct rndis_message *Response) |
fceaf24a | 332 | { |
0120ee0d GKH |
333 | struct rndis_indicate_status *indicate = |
334 | &Response->Message.IndicateStatus; | |
fceaf24a | 335 | |
0120ee0d | 336 | if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) { |
fceaf24a | 337 | gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 1); |
0120ee0d | 338 | } else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) { |
fceaf24a | 339 | gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 0); |
0120ee0d GKH |
340 | } else { |
341 | /* | |
342 | * TODO: | |
343 | */ | |
fceaf24a HJ |
344 | } |
345 | } | |
346 | ||
e681b954 | 347 | static void RndisFilterReceiveData(struct rndis_device *Device, |
9f33d054 GKH |
348 | struct rndis_message *Message, |
349 | struct hv_netvsc_packet *Packet) | |
fceaf24a | 350 | { |
9f33d054 | 351 | struct rndis_packet *rndisPacket; |
4d643114 | 352 | u32 dataOffset; |
fceaf24a HJ |
353 | |
354 | DPRINT_ENTER(NETVSC); | |
355 | ||
454f18a9 | 356 | /* empty ethernet frame ?? */ |
0120ee0d GKH |
357 | ASSERT(Packet->PageBuffers[0].Length > |
358 | RNDIS_MESSAGE_SIZE(struct rndis_packet)); | |
fceaf24a HJ |
359 | |
360 | rndisPacket = &Message->Message.Packet; | |
361 | ||
0120ee0d GKH |
362 | /* |
363 | * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this | |
364 | * netvsc packet (ie TotalDataBufferLength != MessageLength) | |
365 | */ | |
fceaf24a | 366 | |
454f18a9 | 367 | /* Remove the rndis header and pass it back up the stack */ |
fceaf24a HJ |
368 | dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset; |
369 | ||
370 | Packet->TotalDataBufferLength -= dataOffset; | |
371 | Packet->PageBuffers[0].Offset += dataOffset; | |
372 | Packet->PageBuffers[0].Length -= dataOffset; | |
373 | ||
0e727613 | 374 | Packet->IsDataPacket = true; |
fceaf24a | 375 | |
0120ee0d GKH |
376 | gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device, |
377 | Packet); | |
fceaf24a HJ |
378 | |
379 | DPRINT_EXIT(NETVSC); | |
380 | } | |
381 | ||
0120ee0d GKH |
382 | static int RndisFilterOnReceive(struct hv_device *Device, |
383 | struct hv_netvsc_packet *Packet) | |
fceaf24a | 384 | { |
ce9ea4cf | 385 | struct netvsc_device *netDevice = Device->Extension; |
e681b954 | 386 | struct rndis_device *rndisDevice; |
9f33d054 GKH |
387 | struct rndis_message rndisMessage; |
388 | struct rndis_message *rndisHeader; | |
fceaf24a HJ |
389 | |
390 | DPRINT_ENTER(NETVSC); | |
391 | ||
392 | ASSERT(netDevice); | |
454f18a9 | 393 | /* Make sure the rndis device state is initialized */ |
0120ee0d GKH |
394 | if (!netDevice->Extension) { |
395 | DPRINT_ERR(NETVSC, "got rndis message but no rndis device..." | |
396 | "dropping this message!"); | |
fceaf24a HJ |
397 | DPRINT_EXIT(NETVSC); |
398 | return -1; | |
399 | } | |
400 | ||
0120ee0d GKH |
401 | rndisDevice = (struct rndis_device *)netDevice->Extension; |
402 | if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED) { | |
403 | DPRINT_ERR(NETVSC, "got rndis message but rndis device " | |
404 | "uninitialized...dropping this message!"); | |
fceaf24a HJ |
405 | DPRINT_EXIT(NETVSC); |
406 | return -1; | |
407 | } | |
408 | ||
0120ee0d GKH |
409 | rndisHeader = (struct rndis_message *)kmap_atomic( |
410 | pfn_to_page(Packet->PageBuffers[0].Pfn), KM_IRQ0); | |
fceaf24a | 411 | |
0120ee0d GKH |
412 | rndisHeader = (void *)((unsigned long)rndisHeader + |
413 | Packet->PageBuffers[0].Offset); | |
fceaf24a | 414 | |
454f18a9 | 415 | /* Make sure we got a valid rndis message */ |
0120ee0d GKH |
416 | /* |
417 | * FIXME: There seems to be a bug in set completion msg where its | |
418 | * MessageLength is 16 bytes but the ByteCount field in the xfer page | |
419 | * range shows 52 bytes | |
420 | * */ | |
fceaf24a | 421 | #if 0 |
0120ee0d GKH |
422 | if (Packet->TotalDataBufferLength != rndisHeader->MessageLength) { |
423 | kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, | |
424 | KM_IRQ0); | |
425 | ||
426 | DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u " | |
427 | "bytes got %u)...dropping this message!", | |
428 | rndisHeader->MessageLength, | |
429 | Packet->TotalDataBufferLength); | |
fceaf24a HJ |
430 | DPRINT_EXIT(NETVSC); |
431 | return -1; | |
432 | } | |
433 | #endif | |
434 | ||
0120ee0d GKH |
435 | if ((rndisHeader->NdisMessageType != REMOTE_NDIS_PACKET_MSG) && |
436 | (rndisHeader->MessageLength > sizeof(struct rndis_message))) { | |
437 | DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow " | |
438 | "detected (got %u, max %zu)...marking it an error!", | |
439 | rndisHeader->MessageLength, | |
440 | sizeof(struct rndis_message)); | |
fceaf24a HJ |
441 | } |
442 | ||
0120ee0d GKH |
443 | memcpy(&rndisMessage, rndisHeader, |
444 | (rndisHeader->MessageLength > sizeof(struct rndis_message)) ? | |
445 | sizeof(struct rndis_message) : | |
446 | rndisHeader->MessageLength); | |
fceaf24a | 447 | |
45da89e5 | 448 | kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, KM_IRQ0); |
fceaf24a HJ |
449 | |
450 | DumpRndisMessage(&rndisMessage); | |
451 | ||
0120ee0d | 452 | switch (rndisMessage.NdisMessageType) { |
fceaf24a | 453 | case REMOTE_NDIS_PACKET_MSG: |
0120ee0d | 454 | /* data msg */ |
fceaf24a HJ |
455 | RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet); |
456 | break; | |
457 | ||
fceaf24a HJ |
458 | case REMOTE_NDIS_INITIALIZE_CMPLT: |
459 | case REMOTE_NDIS_QUERY_CMPLT: | |
460 | case REMOTE_NDIS_SET_CMPLT: | |
454f18a9 BP |
461 | /* case REMOTE_NDIS_RESET_CMPLT: */ |
462 | /* case REMOTE_NDIS_KEEPALIVE_CMPLT: */ | |
0120ee0d | 463 | /* completion msgs */ |
fceaf24a HJ |
464 | RndisFilterReceiveResponse(rndisDevice, &rndisMessage); |
465 | break; | |
466 | ||
fceaf24a | 467 | case REMOTE_NDIS_INDICATE_STATUS_MSG: |
0120ee0d | 468 | /* notification msgs */ |
fceaf24a HJ |
469 | RndisFilterReceiveIndicateStatus(rndisDevice, &rndisMessage); |
470 | break; | |
471 | default: | |
0120ee0d GKH |
472 | DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)", |
473 | rndisMessage.NdisMessageType, | |
474 | rndisMessage.MessageLength); | |
fceaf24a HJ |
475 | break; |
476 | } | |
477 | ||
478 | DPRINT_EXIT(NETVSC); | |
479 | return 0; | |
480 | } | |
481 | ||
0120ee0d GKH |
482 | static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid, |
483 | void *Result, u32 *ResultSize) | |
fceaf24a | 484 | { |
e681b954 | 485 | struct rndis_request *request; |
4d643114 | 486 | u32 inresultSize = *ResultSize; |
9f33d054 GKH |
487 | struct rndis_query_request *query; |
488 | struct rndis_query_complete *queryComplete; | |
0120ee0d | 489 | int ret = 0; |
fceaf24a HJ |
490 | |
491 | DPRINT_ENTER(NETVSC); | |
492 | ||
493 | ASSERT(Result); | |
494 | ||
495 | *ResultSize = 0; | |
0120ee0d GKH |
496 | request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG, |
497 | RNDIS_MESSAGE_SIZE(struct rndis_query_request)); | |
498 | if (!request) { | |
fceaf24a HJ |
499 | ret = -1; |
500 | goto Cleanup; | |
501 | } | |
502 | ||
454f18a9 | 503 | /* Setup the rndis query */ |
fceaf24a HJ |
504 | query = &request->RequestMessage.Message.QueryRequest; |
505 | query->Oid = Oid; | |
9f33d054 | 506 | query->InformationBufferOffset = sizeof(struct rndis_query_request); |
fceaf24a HJ |
507 | query->InformationBufferLength = 0; |
508 | query->DeviceVcHandle = 0; | |
509 | ||
510 | ret = RndisFilterSendRequest(Device, request); | |
511 | if (ret != 0) | |
fceaf24a | 512 | goto Cleanup; |
fceaf24a | 513 | |
bfc30aae | 514 | osd_WaitEventWait(request->WaitEvent); |
fceaf24a | 515 | |
454f18a9 | 516 | /* Copy the response back */ |
fceaf24a HJ |
517 | queryComplete = &request->ResponseMessage.Message.QueryComplete; |
518 | ||
0120ee0d | 519 | if (queryComplete->InformationBufferLength > inresultSize) { |
fceaf24a HJ |
520 | ret = -1; |
521 | goto Cleanup; | |
522 | } | |
523 | ||
524 | memcpy(Result, | |
0120ee0d GKH |
525 | (void *)((unsigned long)queryComplete + |
526 | queryComplete->InformationBufferOffset), | |
527 | queryComplete->InformationBufferLength); | |
fceaf24a HJ |
528 | |
529 | *ResultSize = queryComplete->InformationBufferLength; | |
530 | ||
531 | Cleanup: | |
532 | if (request) | |
fceaf24a | 533 | PutRndisRequest(Device, request); |
fceaf24a HJ |
534 | DPRINT_EXIT(NETVSC); |
535 | ||
536 | return ret; | |
537 | } | |
538 | ||
0120ee0d | 539 | static int RndisFilterQueryDeviceMac(struct rndis_device *Device) |
fceaf24a | 540 | { |
0120ee0d | 541 | u32 size = HW_MACADDR_LEN; |
fceaf24a HJ |
542 | |
543 | return RndisFilterQueryDevice(Device, | |
0120ee0d GKH |
544 | RNDIS_OID_802_3_PERMANENT_ADDRESS, |
545 | Device->HwMacAddr, &size); | |
fceaf24a HJ |
546 | } |
547 | ||
0120ee0d | 548 | static int RndisFilterQueryDeviceLinkStatus(struct rndis_device *Device) |
fceaf24a | 549 | { |
0120ee0d | 550 | u32 size = sizeof(u32); |
fceaf24a HJ |
551 | |
552 | return RndisFilterQueryDevice(Device, | |
0120ee0d GKH |
553 | RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, |
554 | &Device->LinkStatus, &size); | |
fceaf24a HJ |
555 | } |
556 | ||
0120ee0d GKH |
557 | static int RndisFilterSetPacketFilter(struct rndis_device *Device, |
558 | u32 NewFilter) | |
fceaf24a | 559 | { |
e681b954 | 560 | struct rndis_request *request; |
9f33d054 GKH |
561 | struct rndis_set_request *set; |
562 | struct rndis_set_complete *setComplete; | |
4d643114 | 563 | u32 status; |
fceaf24a HJ |
564 | int ret; |
565 | ||
566 | DPRINT_ENTER(NETVSC); | |
567 | ||
0120ee0d GKH |
568 | ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= |
569 | sizeof(struct rndis_message)); | |
fceaf24a | 570 | |
0120ee0d GKH |
571 | request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG, |
572 | RNDIS_MESSAGE_SIZE(struct rndis_set_request) + | |
573 | sizeof(u32)); | |
574 | if (!request) { | |
fceaf24a HJ |
575 | ret = -1; |
576 | goto Cleanup; | |
577 | } | |
578 | ||
454f18a9 | 579 | /* Setup the rndis set */ |
fceaf24a HJ |
580 | set = &request->RequestMessage.Message.SetRequest; |
581 | set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; | |
4d643114 | 582 | set->InformationBufferLength = sizeof(u32); |
9f33d054 | 583 | set->InformationBufferOffset = sizeof(struct rndis_set_request); |
fceaf24a | 584 | |
0120ee0d GKH |
585 | memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), |
586 | &NewFilter, sizeof(u32)); | |
fceaf24a HJ |
587 | |
588 | ret = RndisFilterSendRequest(Device, request); | |
589 | if (ret != 0) | |
fceaf24a | 590 | goto Cleanup; |
fceaf24a | 591 | |
bfc30aae | 592 | ret = osd_WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/); |
0120ee0d | 593 | if (!ret) { |
fceaf24a HJ |
594 | ret = -1; |
595 | DPRINT_ERR(NETVSC, "timeout before we got a set response..."); | |
0120ee0d GKH |
596 | /* |
597 | * We cant deallocate the request since we may still receive a | |
598 | * send completion for it. | |
599 | */ | |
fceaf24a | 600 | goto Exit; |
0120ee0d | 601 | } else { |
fceaf24a | 602 | if (ret > 0) |
fceaf24a | 603 | ret = 0; |
fceaf24a HJ |
604 | setComplete = &request->ResponseMessage.Message.SetComplete; |
605 | status = setComplete->Status; | |
606 | } | |
607 | ||
608 | Cleanup: | |
609 | if (request) | |
fceaf24a | 610 | PutRndisRequest(Device, request); |
fceaf24a HJ |
611 | Exit: |
612 | DPRINT_EXIT(NETVSC); | |
613 | ||
614 | return ret; | |
615 | } | |
616 | ||
7e23a6e9 | 617 | int RndisFilterInit(struct netvsc_driver *Driver) |
fceaf24a HJ |
618 | { |
619 | DPRINT_ENTER(NETVSC); | |
620 | ||
0120ee0d GKH |
621 | DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd", |
622 | sizeof(struct rndis_filter_packet)); | |
fceaf24a | 623 | |
e681b954 | 624 | Driver->RequestExtSize = sizeof(struct rndis_filter_packet); |
454f18a9 | 625 | Driver->AdditionalRequestPageBufferCount = 1; /* For rndis header */ |
fceaf24a | 626 | |
454f18a9 | 627 | /* Driver->Context = rndisDriver; */ |
fceaf24a | 628 | |
e681b954 | 629 | memset(&gRndisFilter, 0, sizeof(struct rndis_filter_driver_object)); |
fceaf24a HJ |
630 | |
631 | /*rndisDriver->Driver = Driver; | |
632 | ||
633 | ASSERT(Driver->OnLinkStatusChanged); | |
634 | rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/ | |
635 | ||
454f18a9 | 636 | /* Save the original dispatch handlers before we override it */ |
fceaf24a | 637 | gRndisFilter.InnerDriver.Base.OnDeviceAdd = Driver->Base.OnDeviceAdd; |
0120ee0d GKH |
638 | gRndisFilter.InnerDriver.Base.OnDeviceRemove = |
639 | Driver->Base.OnDeviceRemove; | |
fceaf24a HJ |
640 | gRndisFilter.InnerDriver.Base.OnCleanup = Driver->Base.OnCleanup; |
641 | ||
642 | ASSERT(Driver->OnSend); | |
643 | ASSERT(Driver->OnReceiveCallback); | |
644 | gRndisFilter.InnerDriver.OnSend = Driver->OnSend; | |
645 | gRndisFilter.InnerDriver.OnReceiveCallback = Driver->OnReceiveCallback; | |
0120ee0d GKH |
646 | gRndisFilter.InnerDriver.OnLinkStatusChanged = |
647 | Driver->OnLinkStatusChanged; | |
fceaf24a | 648 | |
454f18a9 | 649 | /* Override */ |
fceaf24a HJ |
650 | Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd; |
651 | Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove; | |
652 | Driver->Base.OnCleanup = RndisFilterOnCleanup; | |
653 | Driver->OnSend = RndisFilterOnSend; | |
454f18a9 | 654 | /* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */ |
fceaf24a HJ |
655 | Driver->OnReceiveCallback = RndisFilterOnReceive; |
656 | ||
657 | DPRINT_EXIT(NETVSC); | |
658 | ||
659 | return 0; | |
660 | } | |
661 | ||
e681b954 | 662 | static int RndisFilterInitDevice(struct rndis_device *Device) |
fceaf24a | 663 | { |
e681b954 | 664 | struct rndis_request *request; |
9f33d054 GKH |
665 | struct rndis_initialize_request *init; |
666 | struct rndis_initialize_complete *initComplete; | |
4d643114 | 667 | u32 status; |
fceaf24a HJ |
668 | int ret; |
669 | ||
670 | DPRINT_ENTER(NETVSC); | |
671 | ||
0120ee0d GKH |
672 | request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG, |
673 | RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); | |
674 | if (!request) { | |
fceaf24a HJ |
675 | ret = -1; |
676 | goto Cleanup; | |
677 | } | |
678 | ||
454f18a9 | 679 | /* Setup the rndis set */ |
fceaf24a HJ |
680 | init = &request->RequestMessage.Message.InitializeRequest; |
681 | init->MajorVersion = RNDIS_MAJOR_VERSION; | |
682 | init->MinorVersion = RNDIS_MINOR_VERSION; | |
0120ee0d GKH |
683 | /* FIXME: Use 1536 - rounded ethernet frame size */ |
684 | init->MaxTransferSize = 2048; | |
fceaf24a HJ |
685 | |
686 | Device->State = RNDIS_DEV_INITIALIZING; | |
687 | ||
688 | ret = RndisFilterSendRequest(Device, request); | |
0120ee0d | 689 | if (ret != 0) { |
fceaf24a HJ |
690 | Device->State = RNDIS_DEV_UNINITIALIZED; |
691 | goto Cleanup; | |
692 | } | |
693 | ||
bfc30aae | 694 | osd_WaitEventWait(request->WaitEvent); |
fceaf24a HJ |
695 | |
696 | initComplete = &request->ResponseMessage.Message.InitializeComplete; | |
697 | status = initComplete->Status; | |
0120ee0d | 698 | if (status == RNDIS_STATUS_SUCCESS) { |
fceaf24a HJ |
699 | Device->State = RNDIS_DEV_INITIALIZED; |
700 | ret = 0; | |
0120ee0d | 701 | } else { |
fceaf24a HJ |
702 | Device->State = RNDIS_DEV_UNINITIALIZED; |
703 | ret = -1; | |
704 | } | |
705 | ||
706 | Cleanup: | |
707 | if (request) | |
fceaf24a | 708 | PutRndisRequest(Device, request); |
fceaf24a HJ |
709 | DPRINT_EXIT(NETVSC); |
710 | ||
711 | return ret; | |
712 | } | |
713 | ||
e681b954 | 714 | static void RndisFilterHaltDevice(struct rndis_device *Device) |
fceaf24a | 715 | { |
e681b954 | 716 | struct rndis_request *request; |
9f33d054 | 717 | struct rndis_halt_request *halt; |
fceaf24a HJ |
718 | |
719 | DPRINT_ENTER(NETVSC); | |
720 | ||
454f18a9 | 721 | /* Attempt to do a rndis device halt */ |
0120ee0d GKH |
722 | request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG, |
723 | RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); | |
fceaf24a | 724 | if (!request) |
fceaf24a | 725 | goto Cleanup; |
fceaf24a | 726 | |
454f18a9 | 727 | /* Setup the rndis set */ |
fceaf24a | 728 | halt = &request->RequestMessage.Message.HaltRequest; |
f4888417 | 729 | halt->RequestId = atomic_inc_return(&Device->NewRequestId); |
fceaf24a | 730 | |
454f18a9 | 731 | /* Ignore return since this msg is optional. */ |
fceaf24a HJ |
732 | RndisFilterSendRequest(Device, request); |
733 | ||
734 | Device->State = RNDIS_DEV_UNINITIALIZED; | |
735 | ||
736 | Cleanup: | |
737 | if (request) | |
fceaf24a | 738 | PutRndisRequest(Device, request); |
fceaf24a HJ |
739 | DPRINT_EXIT(NETVSC); |
740 | return; | |
741 | } | |
742 | ||
e681b954 | 743 | static int RndisFilterOpenDevice(struct rndis_device *Device) |
fceaf24a | 744 | { |
0120ee0d | 745 | int ret; |
fceaf24a HJ |
746 | |
747 | DPRINT_ENTER(NETVSC); | |
748 | ||
749 | if (Device->State != RNDIS_DEV_INITIALIZED) | |
750 | return 0; | |
751 | ||
0120ee0d GKH |
752 | ret = RndisFilterSetPacketFilter(Device, |
753 | NDIS_PACKET_TYPE_BROADCAST | | |
754 | NDIS_PACKET_TYPE_DIRECTED); | |
fceaf24a | 755 | if (ret == 0) |
fceaf24a | 756 | Device->State = RNDIS_DEV_DATAINITIALIZED; |
fceaf24a HJ |
757 | |
758 | DPRINT_EXIT(NETVSC); | |
759 | return ret; | |
760 | } | |
761 | ||
e681b954 | 762 | static int RndisFilterCloseDevice(struct rndis_device *Device) |
fceaf24a HJ |
763 | { |
764 | int ret; | |
765 | ||
766 | DPRINT_ENTER(NETVSC); | |
767 | ||
768 | if (Device->State != RNDIS_DEV_DATAINITIALIZED) | |
769 | return 0; | |
770 | ||
771 | ret = RndisFilterSetPacketFilter(Device, 0); | |
772 | if (ret == 0) | |
fceaf24a | 773 | Device->State = RNDIS_DEV_INITIALIZED; |
fceaf24a HJ |
774 | |
775 | DPRINT_EXIT(NETVSC); | |
776 | ||
777 | return ret; | |
778 | } | |
779 | ||
0120ee0d GKH |
780 | static int RndisFilterOnDeviceAdd(struct hv_device *Device, |
781 | void *AdditionalInfo) | |
fceaf24a HJ |
782 | { |
783 | int ret; | |
ce9ea4cf | 784 | struct netvsc_device *netDevice; |
e681b954 | 785 | struct rndis_device *rndisDevice; |
0120ee0d | 786 | struct netvsc_device_info *deviceInfo = AdditionalInfo; |
fceaf24a HJ |
787 | |
788 | DPRINT_ENTER(NETVSC); | |
789 | ||
fceaf24a | 790 | rndisDevice = GetRndisDevice(); |
0120ee0d | 791 | if (!rndisDevice) { |
fceaf24a HJ |
792 | DPRINT_EXIT(NETVSC); |
793 | return -1; | |
794 | } | |
795 | ||
796 | DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice); | |
797 | ||
0120ee0d GKH |
798 | /* |
799 | * Let the inner driver handle this first to create the netvsc channel | |
800 | * NOTE! Once the channel is created, we may get a receive callback | |
801 | * (RndisFilterOnReceive()) before this call is completed | |
802 | */ | |
fceaf24a | 803 | ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo); |
0120ee0d GKH |
804 | if (ret != 0) { |
805 | kfree(rndisDevice); | |
fceaf24a HJ |
806 | DPRINT_EXIT(NETVSC); |
807 | return ret; | |
808 | } | |
809 | ||
454f18a9 BP |
810 | |
811 | /* Initialize the rndis device */ | |
0120ee0d | 812 | netDevice = Device->Extension; |
fceaf24a HJ |
813 | ASSERT(netDevice); |
814 | ASSERT(netDevice->Device); | |
815 | ||
816 | netDevice->Extension = rndisDevice; | |
817 | rndisDevice->NetDevice = netDevice; | |
818 | ||
454f18a9 | 819 | /* Send the rndis initialization message */ |
fceaf24a | 820 | ret = RndisFilterInitDevice(rndisDevice); |
0120ee0d GKH |
821 | if (ret != 0) { |
822 | /* | |
823 | * TODO: If rndis init failed, we will need to shut down the | |
824 | * channel | |
825 | */ | |
fceaf24a HJ |
826 | } |
827 | ||
454f18a9 | 828 | /* Get the mac address */ |
fceaf24a | 829 | ret = RndisFilterQueryDeviceMac(rndisDevice); |
0120ee0d GKH |
830 | if (ret != 0) { |
831 | /* | |
832 | * TODO: shutdown rndis device and the channel | |
833 | */ | |
fceaf24a HJ |
834 | } |
835 | ||
836 | DPRINT_INFO(NETVSC, "Device 0x%p mac addr %02x%02x%02x%02x%02x%02x", | |
0120ee0d GKH |
837 | rndisDevice, |
838 | rndisDevice->HwMacAddr[0], | |
839 | rndisDevice->HwMacAddr[1], | |
840 | rndisDevice->HwMacAddr[2], | |
841 | rndisDevice->HwMacAddr[3], | |
842 | rndisDevice->HwMacAddr[4], | |
843 | rndisDevice->HwMacAddr[5]); | |
fceaf24a HJ |
844 | |
845 | memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, HW_MACADDR_LEN); | |
846 | ||
847 | RndisFilterQueryDeviceLinkStatus(rndisDevice); | |
848 | ||
849 | deviceInfo->LinkState = rndisDevice->LinkStatus; | |
0120ee0d GKH |
850 | DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice, |
851 | ((deviceInfo->LinkState) ? ("down") : ("up"))); | |
fceaf24a HJ |
852 | |
853 | DPRINT_EXIT(NETVSC); | |
854 | ||
855 | return ret; | |
856 | } | |
857 | ||
0120ee0d | 858 | static int RndisFilterOnDeviceRemove(struct hv_device *Device) |
fceaf24a | 859 | { |
ce9ea4cf | 860 | struct netvsc_device *netDevice = Device->Extension; |
0120ee0d | 861 | struct rndis_device *rndisDevice = netDevice->Extension; |
fceaf24a HJ |
862 | |
863 | DPRINT_ENTER(NETVSC); | |
864 | ||
454f18a9 | 865 | /* Halt and release the rndis device */ |
fceaf24a HJ |
866 | RndisFilterHaltDevice(rndisDevice); |
867 | ||
0120ee0d | 868 | kfree(rndisDevice); |
fceaf24a HJ |
869 | netDevice->Extension = NULL; |
870 | ||
454f18a9 | 871 | /* Pass control to inner driver to remove the device */ |
fceaf24a HJ |
872 | gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device); |
873 | ||
874 | DPRINT_EXIT(NETVSC); | |
875 | ||
876 | return 0; | |
877 | } | |
878 | ||
0120ee0d | 879 | static void RndisFilterOnCleanup(struct hv_driver *Driver) |
fceaf24a HJ |
880 | { |
881 | DPRINT_ENTER(NETVSC); | |
882 | ||
883 | DPRINT_EXIT(NETVSC); | |
884 | } | |
885 | ||
2d075346 | 886 | int RndisFilterOnOpen(struct hv_device *Device) |
fceaf24a HJ |
887 | { |
888 | int ret; | |
ce9ea4cf | 889 | struct netvsc_device *netDevice = Device->Extension; |
fceaf24a HJ |
890 | |
891 | DPRINT_ENTER(NETVSC); | |
892 | ||
893 | ASSERT(netDevice); | |
0120ee0d | 894 | ret = RndisFilterOpenDevice(netDevice->Extension); |
fceaf24a HJ |
895 | |
896 | DPRINT_EXIT(NETVSC); | |
897 | ||
898 | return ret; | |
899 | } | |
900 | ||
4f28900b | 901 | int RndisFilterOnClose(struct hv_device *Device) |
fceaf24a HJ |
902 | { |
903 | int ret; | |
ce9ea4cf | 904 | struct netvsc_device *netDevice = Device->Extension; |
fceaf24a HJ |
905 | |
906 | DPRINT_ENTER(NETVSC); | |
907 | ||
908 | ASSERT(netDevice); | |
0120ee0d | 909 | ret = RndisFilterCloseDevice(netDevice->Extension); |
fceaf24a HJ |
910 | |
911 | DPRINT_EXIT(NETVSC); | |
912 | ||
913 | return ret; | |
914 | } | |
915 | ||
0120ee0d GKH |
916 | static int RndisFilterOnSend(struct hv_device *Device, |
917 | struct hv_netvsc_packet *Packet) | |
fceaf24a | 918 | { |
0120ee0d | 919 | int ret; |
e681b954 | 920 | struct rndis_filter_packet *filterPacket; |
9f33d054 GKH |
921 | struct rndis_message *rndisMessage; |
922 | struct rndis_packet *rndisPacket; | |
4d643114 | 923 | u32 rndisMessageSize; |
fceaf24a HJ |
924 | |
925 | DPRINT_ENTER(NETVSC); | |
926 | ||
454f18a9 | 927 | /* Add the rndis header */ |
e681b954 | 928 | filterPacket = (struct rndis_filter_packet *)Packet->Extension; |
fceaf24a HJ |
929 | ASSERT(filterPacket); |
930 | ||
e681b954 | 931 | memset(filterPacket, 0, sizeof(struct rndis_filter_packet)); |
fceaf24a HJ |
932 | |
933 | rndisMessage = &filterPacket->Message; | |
9f33d054 | 934 | rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet); |
fceaf24a HJ |
935 | |
936 | rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG; | |
0120ee0d GKH |
937 | rndisMessage->MessageLength = Packet->TotalDataBufferLength + |
938 | rndisMessageSize; | |
fceaf24a HJ |
939 | |
940 | rndisPacket = &rndisMessage->Message.Packet; | |
9f33d054 | 941 | rndisPacket->DataOffset = sizeof(struct rndis_packet); |
fceaf24a HJ |
942 | rndisPacket->DataLength = Packet->TotalDataBufferLength; |
943 | ||
0e727613 | 944 | Packet->IsDataPacket = true; |
0120ee0d GKH |
945 | Packet->PageBuffers[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; |
946 | Packet->PageBuffers[0].Offset = | |
947 | (unsigned long)rndisMessage & (PAGE_SIZE-1); | |
948 | Packet->PageBuffers[0].Length = rndisMessageSize; | |
fceaf24a | 949 | |
454f18a9 | 950 | /* Save the packet send completion and context */ |
fceaf24a | 951 | filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion; |
0120ee0d GKH |
952 | filterPacket->CompletionContext = |
953 | Packet->Completion.Send.SendCompletionContext; | |
fceaf24a | 954 | |
454f18a9 | 955 | /* Use ours */ |
fceaf24a HJ |
956 | Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion; |
957 | Packet->Completion.Send.SendCompletionContext = filterPacket; | |
958 | ||
959 | ret = gRndisFilter.InnerDriver.OnSend(Device, Packet); | |
0120ee0d GKH |
960 | if (ret != 0) { |
961 | /* | |
962 | * Reset the completion to originals to allow retries from | |
963 | * above | |
964 | */ | |
965 | Packet->Completion.Send.OnSendCompletion = | |
966 | filterPacket->OnCompletion; | |
967 | Packet->Completion.Send.SendCompletionContext = | |
968 | filterPacket->CompletionContext; | |
fceaf24a HJ |
969 | } |
970 | ||
971 | DPRINT_EXIT(NETVSC); | |
972 | ||
973 | return ret; | |
974 | } | |
975 | ||
0120ee0d | 976 | static void RndisFilterOnSendCompletion(void *Context) |
fceaf24a | 977 | { |
0120ee0d | 978 | struct rndis_filter_packet *filterPacket = Context; |
fceaf24a HJ |
979 | |
980 | DPRINT_ENTER(NETVSC); | |
981 | ||
454f18a9 | 982 | /* Pass it back to the original handler */ |
fceaf24a HJ |
983 | filterPacket->OnCompletion(filterPacket->CompletionContext); |
984 | ||
985 | DPRINT_EXIT(NETVSC); | |
986 | } | |
987 | ||
988 | ||
0120ee0d | 989 | static void RndisFilterOnSendRequestCompletion(void *Context) |
fceaf24a HJ |
990 | { |
991 | DPRINT_ENTER(NETVSC); | |
992 | ||
454f18a9 | 993 | /* Noop */ |
fceaf24a HJ |
994 | DPRINT_EXIT(NETVSC); |
995 | } |