winverbs: fixes to support OFED compatibility libraries and ND
[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 unlock;\r
505         }\r
506 \r
507         status = IbCmInterface.CM.create_id(WvEpIbCmHandler, ep, &ep->pIbCmId);\r
508         if (!NT_SUCCESS(status)) {\r
509                 goto unlock;\r
510         }\r
511 \r
512         ep->State = WvEpActiveConnect;\r
513         status = IbCmInterface.CM.send_req(ep->pIbCmId, &req);\r
514         if (NT_SUCCESS(status)) {\r
515                 status = WdfRequestForwardToIoQueue(Request, ep->Queue);\r
516         }\r
517 \r
518         if (!NT_SUCCESS(status)) {\r
519                 ep->State = WvEpDisconnected;\r
520         }\r
521 unlock:\r
522         WdfObjectReleaseLock(ep->Queue);\r
523 release:\r
524         WvEpRelease(ep);\r
525 complete:\r
526         if (!NT_SUCCESS(status)) {\r
527                 WdfRequestComplete(Request, status);\r
528         }\r
529 }\r
530 \r
531 static NTSTATUS WvEpModifyQpRtr(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp,\r
532                                                                 UINT64 ResponderResources, UINT32 Psn,\r
533                                                                 UINT8 *pVerbsData, UINT32 VerbsSize)\r
534 {\r
535         ib_qp_mod_t                     attr;\r
536         ib_api_status_t         ib_status;\r
537         NTSTATUS                        status;\r
538 \r
539         status =IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_INIT, &attr);\r
540         if (!NT_SUCCESS(status)) {\r
541                 return status;\r
542         }\r
543         \r
544         ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
545                                                                                    VerbsSize, pVerbsData);\r
546         if (ib_status != IB_SUCCESS) {\r
547                 return STATUS_UNSUCCESSFUL;\r
548         }\r
549 \r
550         status = IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_RTR, &attr);\r
551         if (!NT_SUCCESS(status)) {\r
552                 return status;\r
553         }\r
554         \r
555         if (pEndpoint->State == WvEpPassiveConnect) {\r
556                 attr.state.rtr.resp_res = (UINT8) ResponderResources;\r
557                 attr.state.rtr.rq_psn = Psn;\r
558         }\r
559 \r
560         ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
561                                                                                    VerbsSize, pVerbsData);\r
562         if (ib_status != IB_SUCCESS) {\r
563                 return STATUS_UNSUCCESSFUL;\r
564         }\r
565 \r
566         return STATUS_SUCCESS;\r
567 }\r
568 \r
569 static NTSTATUS WvEpModifyQpRts(WV_ENDPOINT *pEndpoint, WV_QUEUE_PAIR *pQp,\r
570                                                                 UINT64 InitiatorDepth,\r
571                                                                 UINT8 *pVerbsData, UINT32 VerbsSize)\r
572 {\r
573         ib_qp_mod_t                     attr;\r
574         ib_api_status_t         ib_status;\r
575         NTSTATUS                        status;\r
576 \r
577         status = IbCmInterface.CM.get_qp_attr(pEndpoint->pIbCmId, IB_QPS_RTS, &attr);\r
578         if (!NT_SUCCESS(status)) {\r
579                 return status;\r
580         }\r
581         \r
582         if (pEndpoint->State == WvEpPassiveConnect) {\r
583                 attr.state.rts.init_depth = (UINT8) InitiatorDepth;\r
584         }\r
585 \r
586         ib_status = pQp->pVerbs->ndi_modify_qp(pQp->hVerbsQp, &attr, NULL,\r
587                                                                                    VerbsSize, pVerbsData);\r
588         if (ib_status != IB_SUCCESS) {\r
589                 return STATUS_UNSUCCESSFUL;\r
590         }\r
591 \r
592         return STATUS_SUCCESS;\r
593 }\r
594 \r
595 static NTSTATUS WvEpAcceptActive(WDFREQUEST Request, UINT8 *pVerbsData, size_t VerbsSize,\r
596                                                                  WV_ENDPOINT *pEndpoint, WV_IO_EP_ACCEPT *pAttr)\r
597 {\r
598         WV_QUEUE_PAIR           *qp;\r
599         NTSTATUS                        status;\r
600 \r
601         qp = WvQpAcquire(pEndpoint->pProvider, pAttr->QpId);\r
602         if (qp == NULL) {\r
603                 return STATUS_NOT_FOUND;\r
604         }\r
605 \r
606         status = WvEpModifyQpRtr(pEndpoint, qp, 0, 0, pVerbsData, VerbsSize);\r
607         if (NT_SUCCESS(status)) {\r
608                 status = WvEpModifyQpRts(pEndpoint, qp, 0, pVerbsData, VerbsSize);\r
609         }\r
610 \r
611         WvQpRelease(qp);\r
612 \r
613         WdfObjectAcquireLock(pEndpoint->Queue);\r
614         if (pEndpoint->State != WvEpActiveConnect) {\r
615                 status = STATUS_NOT_SUPPORTED;\r
616                 goto release;\r
617         }\r
618 \r
619         pEndpoint->State = WvEpConnected;\r
620         status = IbCmInterface.CM.send_rtu(pEndpoint->pIbCmId, pAttr->Param.Data,\r
621                                                                            pAttr->Param.DataLength);\r
622         if (!NT_SUCCESS(status)) {\r
623                 pEndpoint->State = WvEpDisconnected;\r
624         }\r
625 \r
626 release:\r
627         WdfObjectReleaseLock(pEndpoint->Queue);\r
628         return status;\r
629 }\r
630 \r
631 static NTSTATUS WvEpAcceptPassive(WDFREQUEST Request, UINT8 *pVerbsData, size_t VerbsSize,\r
632                                                                   WV_ENDPOINT *pEndpoint, WV_IO_EP_ACCEPT *pAttr)\r
633 {\r
634         WV_QUEUE_PAIR           *qp;\r
635         iba_cm_rep                      rep;\r
636         NTSTATUS                        status;\r
637 \r
638         qp = WvQpAcquire(pEndpoint->pProvider, pAttr->QpId);\r
639         if (qp == NULL) {\r
640                 return STATUS_NOT_FOUND;\r
641         }\r
642 \r
643         rep.qpn = qp->Qpn;\r
644         rep.starting_psn = (net32_t) RtlRandomEx(&RandomSeed);\r
645         rep.p_pdata = pAttr->Param.Data;\r
646         rep.pdata_len = pAttr->Param.DataLength;\r
647         rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;\r
648         rep.resp_res = (UINT8) pAttr->Param.ResponderResources;\r
649         rep.init_depth = (UINT8) pAttr->Param.InitiatorDepth;\r
650         rep.flow_ctrl = 1;\r
651         rep.rnr_retry_cnt = pAttr->Param.RnrRetryCount;\r
652         rep.srq = (qp->pSrq != NULL);\r
653 \r
654         status = WvEpModifyQpRtr(pEndpoint, qp, pAttr->Param.ResponderResources,\r
655                                                          rep.starting_psn, pVerbsData, VerbsSize);\r
656         if (NT_SUCCESS(status)) {\r
657                 status = WvEpModifyQpRts(pEndpoint, qp, pAttr->Param.InitiatorDepth,\r
658                                                                  pVerbsData, VerbsSize);\r
659         }\r
660 \r
661         WvQpRelease(qp);\r
662 \r
663         if (!NT_SUCCESS(status)) {\r
664                 goto out;\r
665         }\r
666 \r
667         WdfObjectAcquireLock(pEndpoint->Queue);\r
668         if (pEndpoint->State != WvEpPassiveConnect) {\r
669                 status = STATUS_NOT_SUPPORTED;\r
670                 goto release;\r
671         }\r
672 \r
673         status = IbCmInterface.CM.send_rep(pEndpoint->pIbCmId, &rep);\r
674         if (NT_SUCCESS(status)) {\r
675                 status = WdfRequestForwardToIoQueue(Request, pEndpoint->Queue);\r
676         }\r
677         \r
678         if (!NT_SUCCESS(status)) {\r
679                 pEndpoint->State = WvEpDisconnected;\r
680         }\r
681 \r
682 release:\r
683         WdfObjectReleaseLock(pEndpoint->Queue);\r
684 out:\r
685         return status;\r
686 }\r
687 \r
688 void WvEpAccept(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
689 {\r
690         WV_IO_EP_ACCEPT         *pattr;\r
691         WV_ENDPOINT                     *ep;\r
692         NTSTATUS                        status;\r
693         UINT8                           *out;\r
694         size_t                          outlen;\r
695 \r
696         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_ACCEPT),\r
697                                                                                    &pattr, NULL);\r
698         if (!NT_SUCCESS(status)) {\r
699                 goto complete;\r
700         }\r
701 \r
702         status = WdfRequestRetrieveOutputBuffer(Request, 0, &out, &outlen);\r
703         if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) {\r
704                 goto complete;\r
705         }\r
706 \r
707         if (pattr->Param.DataLength > sizeof(pattr->Param.Data)) {\r
708                 status = STATUS_INVALID_BUFFER_SIZE;\r
709                 goto complete;\r
710         }\r
711 \r
712         ep = WvEpAcquire(pProvider, pattr->Id);\r
713         if (ep == NULL) {\r
714                 status = STATUS_NOT_FOUND;\r
715                 goto complete;\r
716         }\r
717 \r
718         switch (ep->State) {\r
719         case WvEpActiveConnect:\r
720                 status = WvEpAcceptActive(Request, out, outlen, ep, pattr);\r
721                 break;\r
722         case WvEpPassiveConnect:\r
723                 status = WvEpAcceptPassive(Request, out, outlen, ep, pattr);\r
724                 if (NT_SUCCESS(status)) {\r
725                         WvEpRelease(ep);\r
726                         return;\r
727                 }\r
728                 break;\r
729         default:\r
730                 status = STATUS_NOT_SUPPORTED;\r
731                 break;\r
732         }\r
733 \r
734         WvEpRelease(ep);\r
735 complete:\r
736         WdfRequestComplete(Request, status);\r
737 }\r
738 \r
739 void WvEpReject(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
740 {\r
741         WV_IO_ID                        *id;\r
742         WV_ENDPOINT                     *ep;\r
743         NTSTATUS                        status;\r
744         size_t                          len;\r
745 \r
746         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, &len);\r
747         if (!NT_SUCCESS(status)) {\r
748                 goto complete;\r
749         }\r
750 \r
751         ep = WvEpAcquire(pProvider, id->Id);\r
752         if (ep == NULL) {\r
753                 status = STATUS_NOT_FOUND;\r
754                 goto complete;\r
755         }\r
756 \r
757         WdfObjectAcquireLock(ep->Queue);\r
758         if (ep->State != WvEpActiveConnect && ep->State != WvEpPassiveConnect) {\r
759                 status = STATUS_NOT_SUPPORTED;\r
760                 goto release;\r
761         }\r
762 \r
763         ep->State = WvEpDisconnected;\r
764         status = IbCmInterface.CM.send_rej(ep->pIbCmId, IB_REJ_USER_DEFINED,\r
765                                                                            NULL, 0, id + 1, len - sizeof(WV_IO_ID));\r
766 \r
767 release:\r
768         WdfObjectReleaseLock(ep->Queue);\r
769         WvEpRelease(ep);\r
770 complete:\r
771         WdfRequestComplete(Request, status);\r
772 }\r
773 \r
774 void WvEpDisconnect(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
775 {\r
776         UINT64                          *id;\r
777         WV_ENDPOINT                     *ep;\r
778         NTSTATUS                        status;\r
779 \r
780         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
781         if (!NT_SUCCESS(status)) {\r
782                 goto complete;\r
783         }\r
784 \r
785         ep = WvEpAcquire(pProvider, *id);\r
786         if (ep == NULL) {\r
787                 status = STATUS_NOT_FOUND;\r
788                 goto complete;\r
789         }\r
790 \r
791         WdfObjectAcquireLock(ep->Queue);\r
792         switch (ep->State) {\r
793         case WvEpConnected:\r
794                 ep->State = WvEpActiveDisconnect;\r
795                 status = IbCmInterface.CM.send_dreq(ep->pIbCmId, NULL, 0);\r
796                 break;\r
797         case WvEpPassiveDisconnect:\r
798                 ep->State = WvEpDisconnected;\r
799                 IbCmInterface.CM.send_drep(ep->pIbCmId, NULL, 0);\r
800                 status = STATUS_SUCCESS;\r
801                 break;\r
802         default:\r
803                 status = STATUS_NOT_SUPPORTED;\r
804                 break;\r
805         }\r
806 \r
807         WdfObjectReleaseLock(ep->Queue);\r
808         WvEpRelease(ep);\r
809 complete:\r
810         WdfRequestComplete(Request, status);\r
811 }\r
812 \r
813 void WvEpDisconnectNotify(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
814 {\r
815         UINT64                          *id;\r
816         WV_ENDPOINT                     *ep;\r
817         NTSTATUS                        status;\r
818 \r
819         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
820         if (!NT_SUCCESS(status)) {\r
821                 goto complete;\r
822         }\r
823 \r
824         ep = WvEpAcquire(pProvider, *id);\r
825         if (ep == NULL) {\r
826                 status = STATUS_NOT_FOUND;\r
827                 goto complete;\r
828         }\r
829 \r
830         WdfObjectAcquireLock(ep->Queue);\r
831         switch (ep->State) {\r
832         case WvEpConnected:\r
833         case WvEpActiveDisconnect:\r
834                 status = WdfRequestForwardToIoQueue(Request, ep->Queue);\r
835                 if (NT_SUCCESS(status)) {\r
836                         WdfObjectReleaseLock(ep->Queue);\r
837                         WvEpRelease(ep);\r
838                         return;\r
839                 }\r
840                 break;\r
841         case WvEpPassiveDisconnect:\r
842         case WvEpDisconnected:\r
843                 status = STATUS_SUCCESS;\r
844                 break;\r
845         default:\r
846                 status = STATUS_NOT_SUPPORTED;\r
847                 break;\r
848         }\r
849         WdfObjectReleaseLock(ep->Queue);\r
850 \r
851         WvEpRelease(ep);\r
852 complete:\r
853         WdfRequestComplete(Request, status);\r
854 }\r
855 \r
856 static NTSTATUS WvEpIbListenHandler(iba_cm_id *pId, iba_cm_event *pEvent)\r
857 {\r
858         WV_ENDPOINT             *listen, *ep;\r
859         WDFREQUEST              request;\r
860         NTSTATUS                status;\r
861         IB_CMA_HEADER   *hdr;\r
862 \r
863         listen = ((iba_cm_id *) pId->context)->context;\r
864 \r
865         WdfObjectAcquireLock(listen->Queue);\r
866         status = WdfIoQueueRetrieveNextRequest(listen->Queue, &request);\r
867         if (!NT_SUCCESS(status)) {\r
868                 goto release;\r
869         }\r
870 \r
871         ASSERT(!IsListEmpty(&listen->Entry));\r
872         ep = CONTAINING_RECORD(RemoveHeadList(&listen->Entry), WV_ENDPOINT, Entry);\r
873         ep->pIbCmId = pId;\r
874         pId->callback = WvEpIbCmHandler;\r
875         pId->context = ep;\r
876 \r
877         hdr = pEvent->data.req.req.p_pdata;\r
878         if (hdr->IpVersion == 4) {\r
879                 ep->Attributes.LocalAddress.SockAddr.In.SinFamily = WV_AF_INET;\r
880                 ep->Attributes.LocalAddress.SockAddr.In.SinAddr = hdr->DstAddress.Ip4.Address;\r
881                 ep->Attributes.PeerAddress.SockAddr.In.SinFamily = WV_AF_INET;\r
882                 ep->Attributes.PeerAddress.SockAddr.In.SinAddr = hdr->SrcAddress.Ip4.Address;\r
883         } else {\r
884                 ep->Attributes.LocalAddress.SockAddr.In6.Sin6Family = WV_AF_INET6; \r
885                 RtlCopyMemory(ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr,\r
886                                           hdr->DstAddress.Ip6Address, 16);\r
887                 ep->Attributes.PeerAddress.SockAddr.In6.Sin6Family = WV_AF_INET6;\r
888                 RtlCopyMemory(ep->Attributes.PeerAddress.SockAddr.In6.Sin6Addr,\r
889                                           hdr->SrcAddress.Ip6Address, 16);\r
890         }\r
891         ep->Attributes.Device.DeviceGuid = pEvent->data.req.local_ca_guid;\r
892         ep->Attributes.Device.Pkey = pEvent->data.req.req.p_primary_path->pkey;\r
893         ep->Attributes.Device.PortNumber = pEvent->data.req.port_num;\r
894         ep->Attributes.Param.Connect.ResponderResources = pEvent->data.req.req.resp_res;\r
895         ep->Attributes.Param.Connect.InitiatorDepth = pEvent->data.req.req.init_depth;\r
896         ep->Attributes.Param.Connect.RetryCount = pEvent->data.req.req.retry_cnt;\r
897         ep->Attributes.Param.Connect.RnrRetryCount = pEvent->data.req.req.rnr_retry_cnt;\r
898         ep->Attributes.Param.Connect.DataLength = sizeof(ep->Attributes.Param.Connect.Data);\r
899         RtlCopyMemory(ep->Attributes.Param.Connect.Data, hdr + 1,\r
900                                   sizeof(ep->Attributes.Param.Connect.Data));\r
901         ep->Route = *pEvent->data.req.req.p_primary_path;\r
902 \r
903         ep->State = WvEpPassiveConnect;\r
904         WvEpPut(ep);\r
905 \r
906         WdfRequestComplete(request, STATUS_SUCCESS);\r
907 release:\r
908         WdfObjectReleaseLock(listen->Queue);\r
909         return status;\r
910 }\r
911 \r
912 void WvEpListen(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
913 {\r
914         WV_ENDPOINT                     *ep;\r
915         WV_IO_EP_LISTEN         *pattr;\r
916         NTSTATUS                        status;\r
917         void                            *buf;\r
918         UINT8                           offset, len;\r
919         UINT64                          sid;\r
920 \r
921         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_LISTEN),\r
922                                                                                    &pattr, NULL);\r
923         if (!NT_SUCCESS(status)) {\r
924                 goto complete;\r
925         }\r
926 \r
927         ep = WvEpAcquire(pProvider, pattr->Id);\r
928         if (ep == NULL) {\r
929                 status = STATUS_NOT_FOUND;\r
930                 goto complete;\r
931         }\r
932 \r
933         if (WvAnyAddress(&ep->Attributes.LocalAddress)) {\r
934                 buf = NULL;\r
935                 offset = 0;\r
936                 len = 0;\r
937         } else {\r
938                 if (ep->Attributes.LocalAddress.SockAddr.Sa.SaFamily == WV_AF_INET) {\r
939                         buf = &ep->Attributes.LocalAddress.SockAddr.In.SinAddr;\r
940                         len = sizeof ep->Attributes.LocalAddress.SockAddr.In.SinAddr;\r
941                         offset = FIELD_OFFSET(IB_CMA_HEADER, DstAddress.Ip4.Address);\r
942                 } else {\r
943                         buf = ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr;\r
944                         len = sizeof ep->Attributes.LocalAddress.SockAddr.In6.Sin6Addr;\r
945                         offset = FIELD_OFFSET(IB_CMA_HEADER, DstAddress.Ip6Address);\r
946                 }\r
947         }\r
948 \r
949         WdfObjectAcquireLock(ep->Queue);\r
950         if (ep->State != WvEpAddressBound) {\r
951                 status = STATUS_NOT_SUPPORTED;\r
952                 goto release;\r
953         }\r
954 \r
955         status = IbCmInterface.CM.create_id(WvEpIbListenHandler, ep, &ep->pIbCmId);\r
956         if (!NT_SUCCESS(status)) {\r
957                 goto release;\r
958         }\r
959 \r
960         ep->Attributes.Param.Backlog = pattr->Backlog;\r
961         ep->State = WvEpListening;\r
962         sid = WvGetServiceId(ep->EpType, &ep->Attributes.LocalAddress);\r
963         status = IbCmInterface.CM.listen(ep->pIbCmId, sid, buf, len, offset);\r
964 \r
965 release:\r
966         WdfObjectReleaseLock(ep->Queue);\r
967         WvEpRelease(ep);\r
968 complete:\r
969         WdfRequestComplete(Request, status);\r
970 }\r
971 \r
972 void WvEpGetRequest(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
973 {\r
974         WV_ENDPOINT                             *listen, *ep;\r
975         WV_IO_EP_GET_REQUEST    *req;\r
976         NTSTATUS                                status;\r
977 \r
978         status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_EP_GET_REQUEST),\r
979                                                                                    &req, NULL);\r
980         if (!NT_SUCCESS(status)) {\r
981                 goto complete;\r
982         }\r
983 \r
984         listen = WvEpAcquire(pProvider, req->Id);\r
985         if (listen == NULL) {\r
986                 status = STATUS_NOT_FOUND;\r
987                 goto complete;\r
988         }\r
989 \r
990         if (listen->State != WvEpListening) {\r
991                 status = STATUS_NOT_SUPPORTED;\r
992                 goto release1;\r
993         }\r
994 \r
995         ep = WvEpAcquire(pProvider, req->EpId);\r
996         if (ep == NULL) {\r
997                 status = STATUS_NOT_FOUND;\r
998                 goto release1;\r
999         }\r
1000 \r
1001         WdfObjectAcquireLock(ep->Queue);\r
1002         if (ep->State == WvEpIdle) {\r
1003                 ep->State = WvEpQueued;\r
1004         } else {\r
1005                 status = STATUS_CONNECTION_IN_USE;\r
1006         }\r
1007         WdfObjectReleaseLock(ep->Queue);\r
1008 \r
1009         if (!NT_SUCCESS(status)) {\r
1010                 goto release2;\r
1011         }\r
1012 \r
1013         WdfObjectAcquireLock(listen->Queue);\r
1014         status = WdfRequestForwardToIoQueue(Request, listen->Queue);\r
1015         if (NT_SUCCESS(status)) {\r
1016                 InsertTailList(&listen->Entry, &ep->Entry);\r
1017                 WvEpGet(ep);\r
1018         }\r
1019         WdfObjectReleaseLock(listen->Queue);\r
1020 \r
1021 release2:\r
1022         WvEpRelease(ep);\r
1023 release1:\r
1024         WvEpRelease(listen);\r
1025 complete:\r
1026         if (!NT_SUCCESS(status)) {\r
1027                 WdfRequestComplete(Request, status);\r
1028         }\r
1029 }\r
1030 \r
1031 void WvEpLookup(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
1032 {\r
1033         UNUSED_PARAM(pProvider);\r
1034         WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
1035 }\r
1036 \r
1037 void WvEpMulticastJoin(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
1038 {\r
1039         UNUSED_PARAM(pProvider);\r
1040         WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
1041 }\r
1042 \r
1043 void WvEpMulticastLeave(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
1044 {\r
1045         UNUSED_PARAM(pProvider);\r
1046         WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);\r
1047 }\r
1048 \r
1049 //\r
1050 // Note that the framework may have already canceled outstanding requests.\r
1051 //\r
1052 void WvEpCancelListen(WV_ENDPOINT *pListen)\r
1053 {\r
1054         WV_ENDPOINT                     *ep;\r
1055         WDFREQUEST                      request;\r
1056         NTSTATUS                        status;\r
1057 \r
1058         WdfObjectAcquireLock(pListen->Queue);\r
1059         status = WdfIoQueueRetrieveNextRequest(pListen->Queue, &request);\r
1060 \r
1061         while (NT_SUCCESS(status)) {\r
1062                 WdfRequestComplete(request, STATUS_CANCELLED);\r
1063                 status = WdfIoQueueRetrieveNextRequest(pListen->Queue, &request);\r
1064         }\r
1065 \r
1066         while (!IsListEmpty(&pListen->Entry)) {\r
1067                 ep = CONTAINING_RECORD(RemoveHeadList(&pListen->Entry), WV_ENDPOINT, Entry);\r
1068                 ep->State = WvEpIdle;\r
1069                 WvEpPut(ep);\r
1070         }\r
1071 \r
1072         WdfObjectReleaseLock(pListen->Queue);\r
1073 }\r
1074 \r
1075 void WvEpCancel(WV_PROVIDER *pProvider, WDFREQUEST Request)\r
1076 {\r
1077         UINT64                          *id;\r
1078         WV_ENDPOINT                     *ep;\r
1079         NTSTATUS                        status;\r
1080 \r
1081         status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);\r
1082         if (!NT_SUCCESS(status)) {\r
1083                 goto out;\r
1084         }\r
1085 \r
1086         ep = WvEpAcquire(pProvider, *id);\r
1087         if (ep == NULL) {\r
1088                 status = STATUS_NOT_FOUND;\r
1089                 goto out;\r
1090         }\r
1091 \r
1092         if (ep->State == WvEpListening) {\r
1093                 WvEpCancelListen(ep);\r
1094         } else {\r
1095                 WvFlushQueue(ep->Queue, STATUS_CANCELLED);\r
1096         }\r
1097         WvEpRelease(ep);\r
1098 \r
1099 out:\r
1100         WdfRequestComplete(Request, status);\r
1101 }\r