winverbs: return STATUS_SUCCESS when reporting a successful disconnect
[mirror/winof/.git] / core / winverbs / kernel / wv_ep.c
1 /*\r
2  * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  */\r
29 \r
30 #include <ntifs.h>\r
31 #include <iba/ib_rdma_cm.h>\r
32 \r
33 #include "wv_ep.h"\r
34 #include "wv_qp.h"\r
35 #include "wv_ioctl.h"\r
36 #include "wv_driver.h"\r
37 \r
38 #define WV_AF_INET      2\r
39 #define WV_AF_INET6     23\r
40 \r
41 static void WvEpGet(WV_ENDPOINT *pEndpoint)\r
42 {\r
43         InterlockedIncrement(&pEndpoint->Ref);\r
44 }\r
45 \r
46 static void WvEpPut(WV_ENDPOINT *pEndpoint)\r
47 {\r
48         if (InterlockedDecrement(&pEndpoint->Ref) == 0) {\r
49                 KeSetEvent(&pEndpoint->Event, 0, FALSE);\r
50         }\r
51 }\r
52 \r
53 WV_ENDPOINT *WvEpAcquire(WV_PROVIDER *pProvider, UINT64 Id)\r
54 {\r
55         WV_ENDPOINT *ep;\r
56 \r
57         KeAcquireGuardedMutex(&pProvider->Lock);\r
58         WvProviderDisableRemove(pProvider);\r
59         ep = IndexListAt(&pProvider->EpIndex, (SIZE_T) Id);\r
60         if (ep != NULL) {\r
61                 WvEpGet(ep);\r
62         } else {\r
63                 ep = NULL;\r
64                 WvProviderEnableRemove(pProvider);\r
65         }\r
66         KeReleaseGuardedMutex(&pProvider->Lock);\r
67 \r
68         return ep;\r
69 }\r
70 \r
71 void WvEpRelease(WV_ENDPOINT *pEndpoint)\r
72 {\r
73         WvProviderEnableRemove(pEndpoint->pProvider);\r
74         WvEpPut(pEndpoint);\r
75 }\r
76 \r
77 static NTSTATUS WvEpAllocate(WV_PROVIDER *pProvider, UINT16 EpType,\r
78                                                          WV_ENDPOINT **ppEndpoint)\r
79 {\r
80         WV_ENDPOINT                     *ep;\r
81         NTSTATUS                        status;\r
82         WDF_IO_QUEUE_CONFIG     config;\r
83 \r
84         ep = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_ENDPOINT), 'pevw');\r
85         if (ep == NULL) {\r
86                 return STATUS_NO_MEMORY;\r
87         }\r
88 \r
89         RtlZeroMemory(ep, sizeof(WV_ENDPOINT));\r
90         ep->Ref = 1;\r
91         ep->pProvider = pProvider;\r
92         ep->EpType = EpType;\r
93         KeInitializeEvent(&ep->Event, NotificationEvent, FALSE);\r
94         InitializeListHead(&ep->Entry);\r
95 \r
96         WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);\r
97         status = WdfIoQueueCreate(ControlDevice, &config,\r
98                                                           WDF_NO_OBJECT_ATTRIBUTES, &ep->Queue);\r
99         if (!NT_SUCCESS(status)) {\r
100                 goto err;\r
101         }\r
102 \r
103         *ppEndpoint = ep;\r
104         return STATUS_SUCCESS;\r
105 \r
106 err:\r
107         ExFreePool(ep);\r
108         return status;\r
109 }\r
110 \r
111 void WvEpCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
112 {\r
113         UINT64                          *pId;\r
114         UINT64                          *type;\r
115         WV_ENDPOINT                     *ep;\r
116         NTSTATUS                        status;\r
117 \r
118         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &type, NULL);\r
119         if (!NT_SUCCESS(status)) {\r
120                 goto err1;\r
121         }\r
122         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT64), &pId, NULL);\r
123         if (!NT_SUCCESS(status)) {\r
124                 goto err1;\r
125         }\r
126 \r
127         status = WvEpAllocate(pProvider, (UINT16) *type, &ep);\r
128         if (!NT_SUCCESS(status)) {\r
129                 goto err1;\r
130         }\r
131 \r
132         KeAcquireGuardedMutex(&pProvider->Lock);\r
133         *pId = IndexListInsertHead(&pProvider->EpIndex, ep);\r
134         if (*pId == 0) {\r
135                 status = STATUS_NO_MEMORY;\r
136                 goto err2;\r
137         }\r
138         KeReleaseGuardedMutex(&pProvider->Lock);\r
139 \r
140         WdfRequestCompleteWithInformation(Request, status, sizeof(UINT64));\r
141         return;\r
142 \r
143 err2:\r
144         KeReleaseGuardedMutex(&pProvider->Lock);\r
145         WvEpFree(ep);\r
146 err1:\r
147         WdfRequestComplete(Request, status);\r
148 }\r
149 \r
150 void WvEpDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
151 {\r
152         WV_ENDPOINT             *ep;\r
153         UINT64                  *id;\r
154         NTSTATUS                status;\r
155 \r
156         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
157         if (!NT_SUCCESS(status)) {\r
158                 goto out;\r
159         }\r
160 \r
161         KeAcquireGuardedMutex(&pProvider->Lock);\r
162         WvProviderDisableRemove(pProvider);\r
163         ep = IndexListAt(&pProvider->EpIndex, (SIZE_T) *id);\r
164         if (ep == NULL) {\r
165                 status = STATUS_NOT_FOUND;\r
166         } else if (ep->Ref > 1) {\r
167                 status = STATUS_ACCESS_DENIED;\r
168         } else {\r
169                 IndexListRemove(&pProvider->EpIndex, (SIZE_T) *id);\r
170                 status = STATUS_SUCCESS;\r
171         }\r
172         KeReleaseGuardedMutex(&pProvider->Lock);\r
173 \r
174         if (NT_SUCCESS(status)) {\r
175                 WvEpFree(ep);\r
176         }\r
177         WvProviderEnableRemove(pProvider);\r
178 out:\r
179         WdfRequestComplete(Request, status);\r
180 }\r
181 \r
182 void WvEpFree(WV_ENDPOINT *pEndpoint)\r
183 {\r
184         if (pEndpoint->pIbCmId != NULL) {\r
185                 IbCmInterface.CM.destroy_id(pEndpoint->pIbCmId);\r
186         }\r
187 \r
188         if (InterlockedDecrement(&pEndpoint->Ref) > 0) {\r
189                 KeWaitForSingleObject(&pEndpoint->Event, Executive, KernelMode, FALSE, NULL);\r
190         }\r
191 \r
192         WdfIoQueuePurgeSynchronously(pEndpoint->Queue);\r
193         WdfObjectDelete(pEndpoint->Queue);\r
194         ExFreePool(pEndpoint);\r
195 }\r
196 \r
197 void WvEpQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
198 {\r
199         UINT64                          *id;\r
200         WV_IO_EP_ATTRIBUTES     *pattr;\r
201         WV_ENDPOINT                     *ep;\r
202         size_t                          len = 0;\r
203         NTSTATUS                        status;\r
204 \r
205         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
206         if (!NT_SUCCESS(status)) {\r
207                 goto complete;\r
208         }\r
209         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_EP_ATTRIBUTES),\r
210                                                                                         &pattr, NULL);\r
211         if (!NT_SUCCESS(status)) {\r
212                 goto complete;\r
213         }\r
214 \r
215         ep = WvEpAcquire(pProvider, *id);\r
216         if (ep == NULL) {\r
217                 status = STATUS_NOT_FOUND;\r
218                 goto complete;\r
219         }\r
220 \r
221         *pattr = ep->Attributes;\r
222         WvEpRelease(ep);\r
223         len = sizeof(WV_IO_EP_ATTRIBUTES);\r
224 \r
225 complete:\r
226         WdfRequestCompleteWithInformation(Request, status, len);\r
227 }\r
228 \r
229 void WvEpModify(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
230 {\r
231         WV_IO_ID                                *pId;\r
232         size_t                                  inlen;\r
233         WV_ENDPOINT                             *ep;\r
234         NTSTATUS                                status;\r
235 \r
236         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &pId, &inlen);\r
237         if (!NT_SUCCESS(status)) {\r
238                 goto complete;\r
239         }\r
240 \r
241         if (pId->Data != WV_IO_EP_OPTION_ROUTE) {\r
242                 status = STATUS_INVALID_PARAMETER;\r
243                 goto complete;\r
244         }\r
245 \r
246         if (inlen < sizeof(WV_IO_ID) + sizeof(ib_path_rec_t)) {\r
247                 status = STATUS_BUFFER_TOO_SMALL;\r
248                 goto complete;\r
249         }\r
250 \r
251         ep = WvEpAcquire(pProvider, pId->Id);\r
252         if (ep == NULL) {\r
253                 status = STATUS_NOT_FOUND;\r
254                 goto complete;\r
255         }\r
256 \r
257         WdfObjectAcquireLock(ep->Queue);\r
258         if (ep->State != WvEpAddressBound) {\r
259                 status = STATUS_NOT_SUPPORTED;\r
260                 goto release;\r
261         }\r
262 \r
263         RtlCopyMemory(&ep->Route, pId + 1, sizeof ep->Route);\r
264         ep->State = WvEpRouteResolved;\r
265 \r
266 release:\r
267         WdfObjectReleaseLock(ep->Queue);\r
268         WvEpRelease(ep);\r
269 complete:\r
270         WdfRequestComplete(Request, status);\r
271 }\r
272 \r
273 void WvEpBind(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
274 {\r
275         WV_IO_EP_BIND           *pattr;\r
276         WV_ENDPOINT                     *ep;\r
277         size_t                          len = 0;\r
278         NTSTATUS                        status;\r
279 \r
280         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_BIND),\r
281                                                                                    &pattr, NULL);\r
282         if (!NT_SUCCESS(status)) {\r
283                 goto complete;\r
284         }\r
285         status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_EP_BIND),\r
286                                                                                         &pattr, NULL);\r
287         if (!NT_SUCCESS(status)) {\r
288                 goto complete;\r
289         }\r
290 \r
291         ep = WvEpAcquire(pProvider, pattr->Id);\r
292         if (ep == NULL) {\r
293                 status = STATUS_NOT_FOUND;\r
294                 goto complete;\r
295         }\r
296 \r
297         WdfObjectAcquireLock(ep->Queue);\r
298         if (ep->State != WvEpIdle) {\r
299                 status = STATUS_NOT_SUPPORTED;\r
300                 goto release;\r
301         }\r
302 \r
303         ep->Attributes.LocalAddress = pattr->Address;\r
304         ep->Attributes.Device = pattr->Device;\r
305         len = sizeof(WV_IO_EP_BIND);\r
306         ep->State = WvEpAddressBound;\r
307 \r
308 release:\r
309         WdfObjectReleaseLock(ep->Queue);\r
310         WvEpRelease(ep);\r
311 complete:\r
312         WdfRequestCompleteWithInformation(Request, status, len);\r
313 }\r
314 \r
315 static UINT64 WvGetServiceId(UINT16 EpType, WV_IO_SOCKADDR_DATA *pAddress)\r
316 {\r
317         return RtlUlonglongByteSwap(((UINT64)EpType << 16) +\r
318                    RtlUshortByteSwap(pAddress->SockAddr.In.SinPort));\r
319 }\r
320 \r
321 static int WvAnyAddress(WV_IO_SOCKADDR_DATA *pAddress)\r
322 {\r
323         if (pAddress->SockAddr.Sa.SaFamily == WV_AF_INET) {\r
324                 return (pAddress->SockAddr.In.SinAddr == 0) ||\r
325                            ((pAddress->SockAddr.In.SinAddr & 0xff) == 0x7f);\r
326         } else {\r
327                 return (RtlCompareMemoryUlong(pAddress->SockAddr.In6.Sin6Addr, 16, 0) == 16);\r
328         }\r
329 }\r
330 \r
331 static void WvFormatCmaHeader(IB_CMA_HEADER *pHeader,\r
332                                                           WV_IO_SOCKADDR_DATA *pLocalAddress,\r
333                                                           WV_IO_SOCKADDR_DATA *pPeerAddress)\r
334 {\r
335         pHeader->CmaVersion = IB_CMA_VERSION;\r
336         if (pLocalAddress->SockAddr.Sa.SaFamily == WV_AF_INET) {\r
337                 pHeader->IpVersion = 4 << 4;\r
338                 pHeader->SrcAddress.Ip4.Address = pLocalAddress->SockAddr.In.SinAddr;\r
339                 pHeader->DstAddress.Ip4.Address = pPeerAddress->SockAddr.In.SinAddr;\r
340                 pHeader->Port = pLocalAddress->SockAddr.In.SinPort;\r
341         } else {\r
342                 pHeader->IpVersion = 6 << 4;\r
343                 RtlCopyMemory(pHeader->SrcAddress.Ip6Address,\r
344                                           pLocalAddress->SockAddr.In6.Sin6Addr, 16);\r
345                 RtlCopyMemory(pHeader->DstAddress.Ip6Address,\r
346                                           pPeerAddress->SockAddr.In6.Sin6Addr, 16);\r
347                 pHeader->Port = pLocalAddress->SockAddr.In6.Sin6Port;\r
348         }\r
349 }\r
350 \r
351 static void WvEpSaveReply(WV_ENDPOINT *pEndpoint, iba_cm_rep_event *pReply)\r
352 {\r
353         UINT8   len;\r
354 \r
355         len = sizeof(pEndpoint->Attributes.Param.Connect.Data);\r
356         RtlCopyMemory(pEndpoint->Attributes.Param.Connect.Data, pReply->rep.p_pdata, len);\r
357         pEndpoint->Attributes.Param.Connect.DataLength = len;\r
358         pEndpoint->Attributes.Param.Connect.InitiatorDepth = pReply->rep.resp_res;\r
359         pEndpoint->Attributes.Param.Connect.ResponderResources = pReply->rep.init_depth;\r
360         pEndpoint->Attributes.Param.Connect.RnrRetryCount = pReply->rep.rnr_retry_cnt;\r
361 }\r
362 \r
363 static void WvEpSaveReject(WV_ENDPOINT *pEndpoint, iba_cm_rej_event *pReject)\r
364 {\r
365         UINT8   len;\r
366 \r
367         len = sizeof(pEndpoint->Attributes.Param.Connect.Data);\r
368         RtlCopyMemory(pEndpoint->Attributes.Param.Connect.Data, pReject->p_pdata, len);\r
369         pEndpoint->Attributes.Param.Connect.DataLength = len;\r
370 }\r
371 \r
372 static NTSTATUS WvEpIbCmHandler(iba_cm_id *pId, iba_cm_event *pEvent)\r
373 {\r
374         WV_ENDPOINT     *ep;\r
375 \r
376         ep = pId->context;\r
377         switch (pEvent->type) {\r
378         case iba_cm_req_error:\r
379         case iba_cm_rep_error:\r
380         case iba_cm_dreq_error:\r
381                 WdfObjectAcquireLock(ep->Queue);\r
382                 ep->State = WvEpDisconnected;\r
383                 WvCompleteRequests(ep->Queue, STATUS_IO_TIMEOUT);\r
384                 WdfObjectReleaseLock(ep->Queue);\r
385                 break;\r
386         case iba_cm_rep_received:\r
387                 WdfObjectAcquireLock(ep->Queue);\r
388                 if (ep->State == WvEpActiveConnect) {\r
389                         WvEpSaveReply(ep, &pEvent->data.rep);\r
390                         WvCompleteRequests(ep->Queue, STATUS_SUCCESS);\r
391                 }\r
392                 WdfObjectReleaseLock(ep->Queue);\r
393                 break;\r
394         case iba_cm_rtu_received:\r
395                 WdfObjectAcquireLock(ep->Queue);\r
396                 if (ep->State == WvEpPassiveConnect) {\r
397                         WvCompleteRequestsWithInformation(ep->Queue, STATUS_SUCCESS);\r
398                         ep->State = WvEpConnected;\r
399                 }\r
400                 WdfObjectReleaseLock(ep->Queue);\r
401                 break;\r
402         case iba_cm_dreq_received:\r
403                 WdfObjectAcquireLock(ep->Queue);\r
404                 if (ep->State == WvEpConnected) {\r
405                         ep->State = WvEpPassiveDisconnect;\r
406                 } else {\r
407                         ep->State = WvEpDisconnected;\r
408                         IbCmInterface.CM.send_drep(pId, NULL, 0);\r
409                 }\r
410                 WvCompleteRequests(ep->Queue, STATUS_SUCCESS);\r
411                 WdfObjectReleaseLock(ep->Queue);\r
412                 break;\r
413         case iba_cm_drep_received:\r
414                 WdfObjectAcquireLock(ep->Queue);\r
415                 ep->State = WvEpDisconnected;\r
416                 WvCompleteRequests(ep->Queue, STATUS_SUCCESS);\r
417                 WdfObjectReleaseLock(ep->Queue);\r
418                 break;\r
419         case iba_cm_rej_received:\r
420                 WdfObjectAcquireLock(ep->Queue);\r
421                 if (ep->State == WvEpPassiveConnect || ep->State == WvEpActiveConnect) {\r
422                         ep->State = WvEpDisconnected;\r
423                         WvEpSaveReject(ep, &pEvent->data.rej);\r
424                         WvCompleteRequests(ep->Queue, STATUS_REQUEST_NOT_ACCEPTED);\r
425                 }\r
426                 WdfObjectReleaseLock(ep->Queue);\r
427                 break;\r
428         case iba_cm_mra_received:\r
429                 break;\r
430         default:\r
431                 WdfObjectAcquireLock(ep->Queue);\r
432                 ep->State = WvEpDisconnected;\r
433                 WvCompleteRequests(ep->Queue, STATUS_NOT_IMPLEMENTED);\r
434                 WdfObjectReleaseLock(ep->Queue);\r
435                 break;\r
436         }\r
437 \r
438         return STATUS_SUCCESS;\r
439 }\r
440 \r
441 void WvEpConnect(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
442 {\r
443         WV_IO_EP_CONNECT        *pattr;\r
444         WV_ENDPOINT                     *ep;\r
445         WV_QUEUE_PAIR           *qp;\r
446         iba_cm_req                      req;\r
447         NTSTATUS                        status;\r
448         UINT8                           data[IB_REQ_PDATA_SIZE];\r
449 \r
450         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_CONNECT),\r
451                                                                                    &pattr, NULL);\r
452         if (!NT_SUCCESS(status)) {\r
453                 goto complete;\r
454         }\r
455 \r
456         if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
457                 status = STATUS_INVALID_BUFFER_SIZE;\r
458                 goto complete;\r
459         }\r
460 \r
461         ep = WvEpAcquire(pProvider, pattr->Id);\r
462         if (ep == NULL) {\r
463                 status = STATUS_NOT_FOUND;\r
464                 goto complete;\r
465         }\r
466 \r
467         qp = WvQpAcquire(pProvider, pattr->QpId);\r
468         if (qp == NULL) {\r
469                 status = STATUS_NOT_FOUND;\r
470                 goto release;\r
471         }\r
472 \r
473         ep->Attributes.PeerAddress = pattr->PeerAddress;\r
474         WvFormatCmaHeader((IB_CMA_HEADER *) data, &ep->Attributes.LocalAddress,\r
475                                           &ep->Attributes.PeerAddress);\r
476 \r
477         req.service_id = WvGetServiceId(ep->EpType, &ep->Attributes.PeerAddress);\r
478         req.p_primary_path = &ep->Route;\r
479         req.p_alt_path = NULL;\r
480         req.qpn = qp->Qpn;\r
481         req.qp_type = IB_QPT_RELIABLE_CONN;\r
482         req.starting_psn = (net32_t) RtlRandomEx(&RandomSeed);\r
483         req.p_pdata = data;\r
484         RtlCopyMemory(data + sizeof(IB_CMA_HEADER), pattr->Param.Data,\r
485                                   pattr->Param.DataLength);\r
486         req.pdata_len = sizeof(IB_CMA_HEADER) + pattr->Param.DataLength;\r
487         req.max_cm_retries = IB_CMA_MAX_CM_RETRIES;\r
488         req.resp_res = (UINT8) pattr->Param.ResponderResources;\r
489         req.init_depth = (UINT8) pattr->Param.InitiatorDepth;\r
490         req.remote_resp_timeout = IB_CMA_CM_RESPONSE_TIMEOUT;\r
491         req.flow_ctrl = 1;\r
492         req.local_resp_timeout = IB_CMA_CM_RESPONSE_TIMEOUT;\r
493         req.rnr_retry_cnt = pattr->Param.RnrRetryCount;\r
494         req.retry_cnt = pattr->Param.RetryCount;\r
495         req.srq = (qp->pSrq != NULL);\r
496 \r
497         WvQpRelease(qp);\r
498         RtlCopyMemory(&ep->Attributes.Param.Connect, &pattr->Param,\r
499                                   sizeof(pattr->Param));\r
500 \r
501         WdfObjectAcquireLock(ep->Queue);\r
502         if (ep->State != WvEpRouteResolved) {\r
503                 status = STATUS_NOT_SUPPORTED;\r
504                 goto release;\r
505         }\r
506 \r
507         status = IbCmInterface.CM.create_id(WvEpIbCmHandler, ep, &ep->pIbCmId);\r
508         if (!NT_SUCCESS(status)) {\r
509                 goto release;\r
510         }\r
511 \r
512         ep->State = WvEpActiveConnect;\r
513         status = WdfRequestForwardToIoQueue(Request, ep->Queue);\r
514         if (NT_SUCCESS(status)) {\r
515                 status = IbCmInterface.CM.send_req(ep->pIbCmId, &req);\r
516         }\r
517 \r
518         if (!NT_SUCCESS(status)) {\r
519                 ep->State = WvEpDisconnected;\r
520         }\r
521 release:\r
522         WdfObjectReleaseLock(ep->Queue);\r
523         WvEpRelease(ep);\r
524 complete:\r
525         if (!NT_SUCCESS(status)) {\r
526                 WdfRequestComplete(Request, status);\r
527         }\r
528 }\r
529 \r
530 static NTSTATUS WvEpModifyQpRtr(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp,\r
531                                                                 UINT64 ResponderResources, UINT32 Psn,\r
532                                                                 UINT8 *pVerbsData, UINT32 VerbsSize)\r
533 {\r
534         ib_qp_mod_t                     attr;\r
535         ib_api_status_t         ib_status;\r
536         NTSTATUS                        status;\r
537 \r
538         status =IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_INIT, &attr);\r
539         if (!NT_SUCCESS(status)) {\r
540                 return status;\r
541         }\r
542         \r
543         ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
544                                                                                    VerbsSize, pVerbsData);\r
545         if (ib_status != IB_SUCCESS) {\r
546                 return STATUS_UNSUCCESSFUL;\r
547         }\r
548 \r
549         status = IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_RTR, &attr);\r
550         if (!NT_SUCCESS(status)) {\r
551                 return status;\r
552         }\r
553         \r
554         if (pEndpoint->State == WvEpPassiveConnect) {\r
555                 attr.state.rtr.resp_res = (UINT8) ResponderResources;\r
556                 attr.state.rtr.rq_psn = Psn;\r
557         }\r
558 \r
559         ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
560                                                                                    VerbsSize, pVerbsData);\r
561         if (ib_status != IB_SUCCESS) {\r
562                 return STATUS_UNSUCCESSFUL;\r
563         }\r
564 \r
565         return STATUS_SUCCESS;\r
566 }\r
567 \r
568 static NTSTATUS WvEpModifyQpRts(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp,\r
569                                                                 UINT64 InitiatorDepth,\r
570                                                                 UINT8 *pVerbsData, UINT32 VerbsSize)\r
571 {\r
572         ib_qp_mod_t                     attr;\r
573         ib_api_status_t         ib_status;\r
574         NTSTATUS                        status;\r
575 \r
576         status = IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_RTS, &attr);\r
577         if (!NT_SUCCESS(status)) {\r
578                 return status;\r
579         }\r
580         \r
581         if (pEndpoint->State == WvEpPassiveConnect) {\r
582                 attr.state.rts.init_depth = (UINT8) InitiatorDepth;\r
583         }\r
584 \r
585         ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
586                                                                                    VerbsSize, pVerbsData);\r
587         if (ib_status != IB_SUCCESS) {\r
588                 return STATUS_UNSUCCESSFUL;\r
589         }\r
590 \r
591         return STATUS_SUCCESS;\r
592 }\r
593 \r
594 static NTSTATUS WvEpAcceptActive(WDFREQUEST Request, UINT8 *pVerbsData, size_t VerbsSize,\r
595                                                                  WV_ENDPOINT *pEndpoint, WV_IO_EP_ACCEPT *pAttr)\r
596 {\r
597         WV_QUEUE_PAIR           *qp;\r
598         NTSTATUS                        status;\r
599 \r
600         qp = WvQpAcquire(pEndpoint->pProvider, pAttr->QpId);\r
601         if (qp == NULL) {\r
602                 return STATUS_NOT_FOUND;\r
603         }\r
604 \r
605         status = WvEpModifyQpRtr(pEndpoint, qp, 0, 0, pVerbsData, VerbsSize);\r
606         if (NT_SUCCESS(status)) {\r
607                 status = WvEpModifyQpRts(pEndpoint, qp, 0, pVerbsData, VerbsSize);\r
608         }\r
609 \r
610         WvQpRelease(qp);\r
611 \r
612         WdfObjectAcquireLock(pEndpoint->Queue);\r
613         if (pEndpoint->State != WvEpActiveConnect) {\r
614                 status = STATUS_NOT_SUPPORTED;\r
615                 goto release;\r
616         }\r
617 \r
618         pEndpoint->State = WvEpConnected;\r
619         status = IbCmInterface.CM.send_rtu(pEndpoint->pIbCmId, pAttr->Param.Data,\r
620                                                                            pAttr->Param.DataLength);\r
621         if (NT_SUCCESS(status)) {\r
622                 WdfRequestComplete(Request, STATUS_SUCCESS);\r
623         } else {\r
624                 pEndpoint->State = WvEpDisconnected;\r
625         }\r
626 \r
627 release:\r
628         WdfObjectReleaseLock(pEndpoint->Queue);\r
629         return status;\r
630 }\r
631 \r
632 static NTSTATUS WvEpAcceptPassive(WDFREQUEST Request, UINT8 *pVerbsData, size_t VerbsSize,\r
633                                                                   WV_ENDPOINT *pEndpoint, WV_IO_EP_ACCEPT *pAttr)\r
634 {\r
635         WV_QUEUE_PAIR           *qp;\r
636         iba_cm_rep                      rep;\r
637         NTSTATUS                        status;\r
638 \r
639         qp = WvQpAcquire(pEndpoint->pProvider, pAttr->QpId);\r
640         if (qp == NULL) {\r
641                 return STATUS_NOT_FOUND;\r
642         }\r
643 \r
644         rep.qpn = qp->Qpn;\r
645         rep.starting_psn = (net32_t) RtlRandomEx(&RandomSeed);\r
646         rep.p_pdata = pAttr->Param.Data;\r
647         rep.pdata_len = pAttr->Param.DataLength;\r
648         rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;\r
649         rep.resp_res = (UINT8) pAttr->Param.ResponderResources;\r
650         rep.init_depth = (UINT8) pAttr->Param.InitiatorDepth;\r
651         rep.flow_ctrl = 1;\r
652         rep.rnr_retry_cnt = pAttr->Param.RnrRetryCount;\r
653         rep.srq = (qp->pSrq != NULL);\r
654 \r
655         status = WvEpModifyQpRtr(pEndpoint, qp, pAttr->Param.ResponderResources,\r
656                                                          rep.starting_psn, pVerbsData, VerbsSize);\r
657         if (NT_SUCCESS(status)) {\r
658                 status = WvEpModifyQpRts(pEndpoint, qp, pAttr->Param.InitiatorDepth,\r
659                                                                  pVerbsData, VerbsSize);\r
660         }\r
661 \r
662         WvQpRelease(qp);\r
663 \r
664         if (!NT_SUCCESS(status)) {\r
665                 goto out;\r
666         }\r
667 \r
668         WdfObjectAcquireLock(pEndpoint->Queue);\r
669         if (pEndpoint->State != WvEpPassiveConnect) {\r
670                 status = STATUS_NOT_SUPPORTED;\r
671                 goto release;\r
672         }\r
673 \r
674         status = IbCmInterface.CM.send_rep(pEndpoint->pIbCmId, &rep);\r
675         if (NT_SUCCESS(status)) {\r
676                 status = WdfRequestForwardToIoQueue(Request, pEndpoint->Queue);\r
677         }\r
678         \r
679         if (!NT_SUCCESS(status)) {\r
680                 pEndpoint->State = WvEpDisconnected;\r
681         }\r
682 \r
683 release:\r
684         WdfObjectReleaseLock(pEndpoint->Queue);\r
685 out:\r
686         return status;\r
687 }\r
688 \r
689 void WvEpAccept(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
690 {\r
691         WV_IO_EP_ACCEPT         *pattr;\r
692         WV_ENDPOINT                     *ep;\r
693         NTSTATUS                        status;\r
694         UINT8                           *out;\r
695         size_t                          outlen;\r
696 \r
697         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_ACCEPT),\r
698                                                                                    &pattr, NULL);\r
699         if (!NT_SUCCESS(status)) {\r
700                 goto complete;\r
701         }\r
702 \r
703         status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen);\r
704         if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) {\r
705                 goto complete;\r
706         }\r
707 \r
708         if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
709                 status = STATUS_INVALID_BUFFER_SIZE;\r
710                 goto complete;\r
711         }\r
712 \r
713         ep = WvEpAcquire(pProvider, pattr->Id);\r
714         if (ep == NULL) {\r
715                 status = STATUS_NOT_FOUND;\r
716                 goto complete;\r
717         }\r
718 \r
719         switch (ep->State) {\r
720         case WvEpActiveConnect:\r
721                 status = WvEpAcceptActive(Request, out, outlen, ep, pattr);\r
722                 break;\r
723         case WvEpPassiveConnect:\r
724                 status = WvEpAcceptPassive(Request, out, outlen, ep, pattr);\r
725                 break;\r
726         default:\r
727                 status = STATUS_NOT_SUPPORTED;\r
728                 break;\r
729         }\r
730 \r
731         WvEpRelease(ep);\r
732 complete:\r
733         if (!NT_SUCCESS(status)) {\r
734                 WdfRequestComplete(Request, status);\r
735         }\r
736 }\r
737 \r
738 void WvEpReject(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
739 {\r
740         WV_IO_ID                        *id;\r
741         WV_ENDPOINT                     *ep;\r
742         NTSTATUS                        status;\r
743         size_t                          len;\r
744 \r
745         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, &len);\r
746         if (!NT_SUCCESS(status)) {\r
747                 goto complete;\r
748         }\r
749 \r
750         ep = WvEpAcquire(pProvider, id->Id);\r
751         if (ep == NULL) {\r
752                 status = STATUS_NOT_FOUND;\r
753                 goto complete;\r
754         }\r
755 \r
756         WdfObjectAcquireLock(ep->Queue);\r
757         if (ep->State != WvEpActiveConnect && ep->State != WvEpPassiveConnect) {\r
758                 status = STATUS_NOT_SUPPORTED;\r
759                 goto release;\r
760         }\r
761 \r
762         ep->State = WvEpDisconnected;\r
763         status = IbCmInterface.CM.send_rej(ep->pIbCmId, IB_REJ_USER_DEFINED,\r
764                                                                            NULL, 0, id + 1, len - sizeof(WV_IO_ID));\r
765 \r
766 release:\r
767         WdfObjectReleaseLock(ep->Queue);\r
768         WvEpRelease(ep);\r
769 complete:\r
770         WdfRequestComplete(Request, status);\r
771 }\r
772 \r
773 void WvEpDisconnect(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
774 {\r
775         UINT64                          *id;\r
776         WV_ENDPOINT                     *ep;\r
777         NTSTATUS                        status;\r
778 \r
779         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
780         if (!NT_SUCCESS(status)) {\r
781                 goto complete;\r
782         }\r
783 \r
784         ep = WvEpAcquire(pProvider, *id);\r
785         if (ep == NULL) {\r
786                 status = STATUS_NOT_FOUND;\r
787                 goto complete;\r
788         }\r
789 \r
790         WdfObjectAcquireLock(ep->Queue);\r
791         switch (ep->State) {\r
792         case WvEpConnected:\r
793                 ep->State = WvEpActiveDisconnect;\r
794                 status = IbCmInterface.CM.send_dreq(ep->pIbCmId, NULL, 0);\r
795                 break;\r
796         case WvEpPassiveDisconnect:\r
797                 ep->State = WvEpDisconnected;\r
798                 IbCmInterface.CM.send_drep(ep->pIbCmId, NULL, 0);\r
799                 status = STATUS_SUCCESS;\r
800                 break;\r
801         default:\r
802                 status = STATUS_NOT_SUPPORTED;\r
803                 break;\r
804         }\r
805 \r
806         WdfObjectReleaseLock(ep->Queue);\r
807         WvEpRelease(ep);\r
808 complete:\r
809         WdfRequestComplete(Request, status);\r
810 }\r
811 \r
812 void WvEpDisconnectNotify(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
813 {\r
814         UINT64                          *id;\r
815         WV_ENDPOINT                     *ep;\r
816         NTSTATUS                        status;\r
817 \r
818         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
819         if (!NT_SUCCESS(status)) {\r
820                 goto complete;\r
821         }\r
822 \r
823         ep = WvEpAcquire(pProvider, *id);\r
824         if (ep == NULL) {\r
825                 status = STATUS_NOT_FOUND;\r
826                 goto complete;\r
827         }\r
828 \r
829         WdfObjectAcquireLock(ep->Queue);\r
830         switch (ep->State) {\r
831         case WvEpConnected:\r
832         case WvEpActiveDisconnect:\r
833                 status = WdfRequestForwardToIoQueue(Request, ep->Queue);\r
834                 break;\r
835         case WvEpPassiveDisconnect:\r
836         case WvEpDisconnected:\r
837                 status = STATUS_SUCCESS;\r
838                 break;\r
839         default:\r
840                 status = STATUS_NOT_SUPPORTED;\r
841                 break;\r
842         }\r
843         WdfObjectReleaseLock(ep->Queue);\r
844 \r
845         WvEpRelease(ep);\r
846 complete:\r
847         if (!NT_SUCCESS(status)) {\r
848                 WdfRequestComplete(Request, status);\r
849         }\r
850 }\r
851 \r
852 static NTSTATUS WvEpIbListenHandler(iba_cm_id *pId, iba_cm_event *pEvent)\r
853 {\r
854         WV_ENDPOINT             *listen, *ep;\r
855         WDFREQUEST              request;\r
856         NTSTATUS                status;\r
857         IB_CMA_HEADER   *hdr;\r
858 \r
859         listen = ((iba_cm_id *) pId->context)->context;\r
860 \r
861         WdfObjectAcquireLock(listen->Queue);\r
862         status = WdfIoQueueRetrieveNextRequest(listen->Queue, &request);\r
863         if (!NT_SUCCESS(status)) {\r
864                 goto release;\r
865         }\r
866 \r
867         ep = CONTAINING_RECORD(RemoveHeadList(&listen->Entry), WV_ENDPOINT, Entry);\r
868         ep->pIbCmId = pId;\r
869         pId->callback = WvEpIbCmHandler;\r
870         pId->context = ep;\r
871 \r
872         hdr = pEvent->data.req.req.p_pdata;\r
873         if (hdr->IpVersion == 4) {\r
874                 ep->Attributes.LocalAddress.SockAddr.In.SinFamily = WV_AF_INET;\r
875                 ep->Attributes.LocalAddress.SockAddr.In.SinAddr = hdr->DstAddress.Ip4.Address;\r
876                 ep->Attributes.PeerAddress.SockAddr.In.SinFamily = WV_AF_INET;\r
877                 ep->Attributes.PeerAddress.SockAddr.In.SinAddr = hdr->SrcAddress.Ip4.Address;\r
878         } else {\r
879                 ep->Attributes.LocalAddress.SockAddr.In6.Sin6Family = WV_AF_INET6; \r
880                 RtlCopyMemory(ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr,\r
881                                           hdr->DstAddress.Ip6Address, 16);\r
882                 ep->Attributes.PeerAddress.SockAddr.In6.Sin6Family = WV_AF_INET6;\r
883                 RtlCopyMemory(ep->Attributes.PeerAddress.SockAddr.In6.Sin6Addr,\r
884                                           hdr->SrcAddress.Ip6Address, 16);\r
885         }\r
886         ep->Attributes.Device.DeviceGuid = pEvent->data.req.local_ca_guid;\r
887         ep->Attributes.Device.Pkey = pEvent->data.req.req.p_primary_path->pkey;\r
888         ep->Attributes.Device.PortNumber = pEvent->data.req.port_num;\r
889         ep->Attributes.Param.Connect.ResponderResources = pEvent->data.req.req.resp_res;\r
890         ep->Attributes.Param.Connect.InitiatorDepth = pEvent->data.req.req.init_depth;\r
891         ep->Attributes.Param.Connect.RetryCount = pEvent->data.req.req.retry_cnt;\r
892         ep->Attributes.Param.Connect.RnrRetryCount = pEvent->data.req.req.rnr_retry_cnt;\r
893         ep->Attributes.Param.Connect.DataLength = sizeof(ep->Attributes.Param.Connect.Data);\r
894         RtlCopyMemory(ep->Attributes.Param.Connect.Data, hdr + 1,\r
895                                   sizeof(ep->Attributes.Param.Connect.Data));\r
896         ep->Route = *pEvent->data.req.req.p_primary_path;\r
897 \r
898         ep->State = WvEpPassiveConnect;\r
899         WvEpPut(ep);\r
900 \r
901         WdfRequestComplete(request, STATUS_SUCCESS);\r
902 release:\r
903         WdfObjectReleaseLock(listen->Queue);\r
904         return status;\r
905 }\r
906 \r
907 void WvEpListen(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
908 {\r
909         WV_ENDPOINT                     *ep;\r
910         WV_IO_EP_LISTEN         *pattr;\r
911         NTSTATUS                        status;\r
912         void                            *buf;\r
913         UINT8                           offset, len;\r
914         UINT64                          sid;\r
915 \r
916         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_LISTEN),\r
917                                                                                    &pattr, NULL);\r
918         if (!NT_SUCCESS(status)) {\r
919                 goto complete;\r
920         }\r
921 \r
922         ep = WvEpAcquire(pProvider, pattr->Id);\r
923         if (ep == NULL) {\r
924                 status = STATUS_NOT_FOUND;\r
925                 goto complete;\r
926         }\r
927 \r
928         if (WvAnyAddress(&ep->Attributes.LocalAddress)) {\r
929                 buf = NULL;\r
930                 offset = 0;\r
931                 len = 0;\r
932         } else {\r
933                 if (ep->Attributes.LocalAddress.SockAddr.Sa.SaFamily == WV_AF_INET) {\r
934                         buf = &ep->Attributes.LocalAddress.SockAddr.In.SinAddr;\r
935                         len = sizeof ep->Attributes.LocalAddress.SockAddr.In.SinAddr;\r
936                         offset = FIELD_OFFSET(IB_CMA_HEADER, DstAddress.Ip4.Address);\r
937                 } else {\r
938                         buf = ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr;\r
939                         len = sizeof ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr;\r
940                         offset = FIELD_OFFSET(IB_CMA_HEADER, DstAddress.Ip6Address);\r
941                 }\r
942         }\r
943 \r
944         WdfObjectAcquireLock(ep->Queue);\r
945         if (ep->State != WvEpAddressBound) {\r
946                 status = STATUS_NOT_SUPPORTED;\r
947                 goto release;\r
948         }\r
949 \r
950         status = IbCmInterface.CM.create_id(WvEpIbListenHandler, ep, &ep->pIbCmId);\r
951         if (!NT_SUCCESS(status)) {\r
952                 goto release;\r
953         }\r
954 \r
955         ep->Attributes.Param.Backlog = pattr->Backlog;\r
956         ep->State = WvEpListening;\r
957         sid = WvGetServiceId(ep->EpType, &ep->Attributes.LocalAddress);\r
958         status = IbCmInterface.CM.listen(ep->pIbCmId, sid, buf, len, offset);\r
959 \r
960 release:\r
961         WdfObjectReleaseLock(ep->Queue);\r
962         WvEpRelease(ep);\r
963 complete:\r
964         WdfRequestComplete(Request, status);\r
965 }\r
966 \r
967 void WvEpGetRequest(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
968 {\r
969         WV_ENDPOINT                             *listen, *ep;\r
970         WV_IO_EP_GET_REQUEST    *req;\r
971         NTSTATUS                                status;\r
972 \r
973         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_GET_REQUEST),\r
974                                                                                    &req, NULL);\r
975         if (!NT_SUCCESS(status)) {\r
976                 goto complete;\r
977         }\r
978 \r
979         listen = WvEpAcquire(pProvider, req->Id);\r
980         if (listen == NULL) {\r
981                 status = STATUS_NOT_FOUND;\r
982                 goto complete;\r
983         }\r
984 \r
985         if (listen->State != WvEpListening) {\r
986                 status = STATUS_NOT_SUPPORTED;\r
987                 goto release1;\r
988         }\r
989 \r
990         ep = WvEpAcquire(pProvider, req->EpId);\r
991         if (ep == NULL) {\r
992                 status = STATUS_NOT_FOUND;\r
993                 goto release1;\r
994         }\r
995 \r
996         WdfObjectAcquireLock(ep->Queue);\r
997         if (ep->State == WvEpIdle) {\r
998                 ep->State = WvEpQueued;\r
999         } else {\r
1000                 status = STATUS_CONNECTION_IN_USE;\r
1001         }\r
1002         WdfObjectReleaseLock(ep->Queue);\r
1003 \r
1004         if (!NT_SUCCESS(status)) {\r
1005                 goto release2;\r
1006         }\r
1007 \r
1008         WdfObjectAcquireLock(listen->Queue);\r
1009         status = WdfRequestForwardToIoQueue(Request, listen->Queue);\r
1010         if (NT_SUCCESS(status)) {\r
1011                 InsertTailList(&listen->Entry, &ep->Entry);\r
1012                 WvEpGet(ep);\r
1013         }\r
1014         WdfObjectReleaseLock(listen->Queue);\r
1015 \r
1016 release2:\r
1017         WvEpRelease(ep);\r
1018 release1:\r
1019         WvEpRelease(listen);\r
1020 complete:\r
1021         if (!NT_SUCCESS(status)) {\r
1022                 WdfRequestComplete(Request, status);\r
1023         }\r
1024 }\r
1025 \r
1026 void WvEpLookup(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
1027 {\r
1028         UNUSED_PARAM(pProvider);\r
1029         WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
1030 }\r
1031 \r
1032 void WvEpMulticastJoin(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
1033 {\r
1034         UNUSED_PARAM(pProvider);\r
1035         WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
1036 }\r
1037 \r
1038 void WvEpMulticastLeave(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
1039 {\r
1040         UNUSED_PARAM(pProvider);\r
1041         WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
1042 }\r
1043 \r
1044 //\r
1045 // Note that the framework may have already canceled outstanding requests.\r
1046 //\r
1047 void WvEpCancelListen(WV_ENDPOINT *pListen)\r
1048 {\r
1049         WV_ENDPOINT                     *ep;\r
1050         WDFREQUEST                      request;\r
1051         NTSTATUS                        status;\r
1052 \r
1053         WdfObjectAcquireLock(pListen->Queue);\r
1054         status = WdfIoQueueRetrieveNextRequest(pListen->Queue, &request);\r
1055 \r
1056         while (NT_SUCCESS(status)) {\r
1057                 WdfRequestComplete(request, STATUS_CANCELLED);\r
1058                 status = WdfIoQueueRetrieveNextRequest(pListen->Queue, &request);\r
1059         }\r
1060 \r
1061         while (!IsListEmpty(&pListen->Entry)) {\r
1062                 ep = CONTAINING_RECORD(RemoveHeadList(&pListen->Entry), WV_ENDPOINT, Entry);\r
1063                 ep->State = WvEpIdle;\r
1064                 WvEpPut(ep);\r
1065         }\r
1066 \r
1067         WdfObjectReleaseLock(pListen->Queue);\r
1068 }\r
1069 \r
1070 void WvEpCancel(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
1071 {\r
1072         UINT64                          *id;\r
1073         WV_ENDPOINT                     *ep;\r
1074         NTSTATUS                        status;\r
1075 \r
1076         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
1077         if (!NT_SUCCESS(status)) {\r
1078                 goto out;\r
1079         }\r
1080 \r
1081         ep = WvEpAcquire(pProvider, *id);\r
1082         if (ep == NULL) {\r
1083                 status = STATUS_NOT_FOUND;\r
1084                 goto out;\r
1085         }\r
1086 \r
1087         if (ep->State == WvEpListening) {\r
1088                 WvEpCancelListen(ep);\r
1089         } else {\r
1090                 WvFlushQueue(ep->Queue, STATUS_CANCELLED);\r
1091         }\r
1092         WvEpRelease(ep);\r
1093 \r
1094 out:\r
1095         WdfRequestComplete(Request, status);\r
1096 }\r