Remove stale HPC Pack 2008 Beta 1 objects
[mirror/winof/.git] / ulp / nd / user / NdConnector.cpp
1 /*\r
2  * Copyright (c) 2008 Microsoft 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 AND\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  * $Id:$\r
30  */\r
31 \r
32 #include "NdCq.h"\r
33 #include "NdAdapter.h"\r
34 #include "NdMw.h"\r
35 #include "NdEndpoint.h"\r
36 #include "NdProv.h"\r
37 #include "NdMr.h"\r
38 #include "NdListen.h"\r
39 #include "NdConnector.h"\r
40 \r
41 #include "al_dev.h"\r
42 #pragma warning( push, 3 )\r
43 #include "winternl.h"\r
44 #pragma warning( pop )\r
45 #include "iba/ibat.h"\r
46 \r
47 #include <assert.h>\r
48 #include <limits.h>\r
49 #include <strsafe.h>\r
50 \r
51 #if defined(EVENT_TRACING)\r
52 #ifdef offsetof\r
53 #undef offsetof\r
54 #endif\r
55 #include "NdConnector.tmh"\r
56 #endif\r
57 \r
58 \r
59 namespace NetworkDirect\r
60 {\r
61 \r
62 CConnector::CConnector(void) :\r
63     m_nRef( 1 ),\r
64     m_pParent( NULL ),\r
65     m_pEndpoint( NULL ),\r
66     m_Protocol( 0 ),\r
67     m_LocalPort( 0 ),\r
68     m_cid( 0 ),\r
69     m_fActive( false )\r
70 {\r
71 }\r
72 \r
73 CConnector::~CConnector(void)\r
74 {\r
75     FreeCid();\r
76 \r
77     if( m_pEndpoint )\r
78         m_pEndpoint->Release();\r
79 \r
80     if( m_pParent )\r
81         m_pParent->Release();\r
82 }\r
83 \r
84 void CConnector::FreeCid(void)\r
85 {\r
86     if( m_cid != 0 )\r
87     {\r
88         DWORD bytes_ret;\r
89         DeviceIoControl(\r
90             m_pParent->m_hSync,\r
91             UAL_DESTROY_CEP,\r
92             &m_cid,\r
93             sizeof(m_cid),\r
94             NULL,\r
95             0,\r
96             &bytes_ret,\r
97             NULL );\r
98 \r
99         m_cid = 0;\r
100     }\r
101 }\r
102 \r
103 HRESULT CConnector::Create(\r
104     __in CAdapter* pParent,\r
105     __deref_out INDConnector** ppConnector\r
106     )\r
107 {\r
108     CConnector* pConnector = new CConnector();\r
109     if( pConnector == NULL )\r
110         return ND_NO_MEMORY;\r
111 \r
112     pConnector->m_pParent = pParent;\r
113     pParent->AddRef();\r
114 \r
115     *ppConnector = pConnector;\r
116     return S_OK;\r
117 }\r
118 \r
119 HRESULT CConnector::QueryInterface(\r
120     REFIID riid,\r
121     LPVOID FAR* ppvObj\r
122     )\r
123 {\r
124     if( IsEqualIID( riid, IID_IUnknown ) )\r
125     {\r
126         *ppvObj = this;\r
127         return S_OK;\r
128     }\r
129 \r
130     if( IsEqualIID( riid, IID_INDConnector ) )\r
131     {\r
132         *ppvObj = this;\r
133         return S_OK;\r
134     }\r
135 \r
136     return E_NOINTERFACE;\r
137 }\r
138 \r
139 ULONG CConnector::AddRef(void)\r
140 {\r
141     return InterlockedIncrement( &m_nRef );\r
142 }\r
143 \r
144 ULONG CConnector::Release(void)\r
145 {\r
146     ULONG ref = InterlockedDecrement( &m_nRef );\r
147     if( ref == 0 )\r
148         delete this;\r
149 \r
150     return ref;\r
151 }\r
152 \r
153 // *** INDOverlapped methods ***\r
154 HRESULT CConnector::CancelOverlappedRequests(void)\r
155 {\r
156     ND_ENTER( ND_DBG_NDI );\r
157 \r
158     DWORD bytes_ret;\r
159     BOOL ret = DeviceIoControl(\r
160         m_pParent->m_hSync,\r
161         UAL_NDI_CANCEL_CM_IRPS,\r
162         &m_cid,\r
163         sizeof(m_cid),\r
164         NULL,\r
165         0,\r
166         &bytes_ret,\r
167         NULL );\r
168 \r
169     if( ret )\r
170         return S_OK;\r
171     else\r
172         return ND_UNSUCCESSFUL;\r
173 }\r
174 \r
175 HRESULT CConnector::GetOverlappedResult(\r
176     __inout OVERLAPPED *pOverlapped,\r
177     __out SIZE_T *pNumberOfBytesTransferred,\r
178     __in BOOL bWait\r
179     )\r
180 {\r
181     ND_ENTER( ND_DBG_NDI );\r
182 \r
183     *pNumberOfBytesTransferred = 0;\r
184     ::GetOverlappedResult(\r
185         m_pParent->GetFileHandle(),\r
186         pOverlapped,\r
187         (DWORD*)pNumberOfBytesTransferred,\r
188         bWait );\r
189     return (HRESULT)pOverlapped->Internal;\r
190 }\r
191 \r
192 HRESULT CConnector::CreateEndpoint(\r
193     __in INDCompletionQueue* pInboundCq,\r
194     __in INDCompletionQueue* pOutboundCq,\r
195     __in SIZE_T nInboundEntries,\r
196     __in SIZE_T nOutboundEntries,\r
197     __in SIZE_T nInboundSge,\r
198     __in SIZE_T nOutboundSge,\r
199     __in SIZE_T InboundReadLimit,\r
200     __in SIZE_T OutboundReadLimit,\r
201     __out_opt SIZE_T* pMaxInlineData,\r
202     __deref_out INDEndpoint** ppEndpoint\r
203     )\r
204 {\r
205     ND_ENTER( ND_DBG_NDI );\r
206 \r
207     //\r
208     // Check that the verb provider supports user-mode operations.\r
209     // If not, a different class should be created.\r
210     //\r
211     if( m_pParent->m_Ifc.user_verbs.pre_create_qp == NULL ||\r
212         m_pParent->m_Ifc.user_verbs.post_create_qp == NULL ||\r
213         m_pParent->m_Ifc.user_verbs.nd_modify_qp == NULL ||\r
214         m_pParent->m_Ifc.user_verbs.nd_get_qp_state == NULL ||\r
215         m_pParent->m_Ifc.user_verbs.pre_destroy_qp == NULL ||\r
216         m_pParent->m_Ifc.user_verbs.post_destroy_qp == NULL ||\r
217         m_pParent->m_Ifc.user_verbs.post_send == NULL ||\r
218         m_pParent->m_Ifc.user_verbs.post_recv == NULL /*||\r
219         m_pParent->m_Ifc.user_verbs.bind_mw == NULL*/ )\r
220     {\r
221         return ND_NOT_SUPPORTED;\r
222     }\r
223 \r
224     if( m_pEndpoint != NULL )\r
225         return ND_NOT_SUPPORTED;\r
226 \r
227     HRESULT hr = CEndpoint::Create(\r
228         m_pParent,\r
229         static_cast<CCq*>(pInboundCq),\r
230         static_cast<CCq*>(pOutboundCq),\r
231         nInboundEntries,\r
232         nOutboundEntries,\r
233         nInboundSge,\r
234         nOutboundSge,\r
235         InboundReadLimit,\r
236         OutboundReadLimit,\r
237         pMaxInlineData,\r
238         (INDEndpoint**)&m_pEndpoint\r
239         );\r
240 \r
241     if( SUCCEEDED( hr ) )\r
242     {\r
243         m_pEndpoint->AddRef();\r
244         *ppEndpoint = m_pEndpoint;\r
245     }\r
246 \r
247     return hr;\r
248 }\r
249 \r
250 //\r
251 // Connects an endpoint to the specified destinaton address.\r
252 //\r
253 // Only basic checks on input data are performed in user-mode,\r
254 // and request is handed to the kernel, where:\r
255 //  1. the destination address is resolved to a destination GID\r
256 //  2. the destination GID is used to get a path record\r
257 //  3. the path record is used to issue a CM REQ\r
258 //  4. a CM REP is received (or REJ or timeout).\r
259 //  5. the request is completed.\r
260 //\r
261 HRESULT CConnector::Connect(\r
262     __inout INDEndpoint* pEndpoint,\r
263     __in_bcount(AddressLength) const struct sockaddr* pAddress,\r
264     __in SIZE_T AddressLength,\r
265     __in INT Protocol,\r
266     __in_opt USHORT LocalPort,\r
267     __in_bcount_opt(PrivateDataLength) const void* pPrivateData,\r
268     __in SIZE_T PrivateDataLength,\r
269     __inout OVERLAPPED* pOverlapped\r
270     )\r
271 {\r
272     ND_ENTER( ND_DBG_NDI );\r
273 \r
274     if( AddressLength < sizeof(struct sockaddr) )\r
275         return ND_INVALID_ADDRESS;\r
276 \r
277     if( Protocol > UCHAR_MAX || Protocol < 0 )\r
278         return ND_INVALID_PARAMETER_4;\r
279 \r
280     m_Protocol = (UINT8)Protocol;\r
281 \r
282     //\r
283     // CM REQ supports 92 bytes of private data.  We expect to use IP\r
284     // addressing annex, which eats up 36 bytes, leaving us with 56.\r
285     //\r
286     if( PrivateDataLength > 56 )\r
287         return ND_BUFFER_OVERFLOW;\r
288 \r
289     //\r
290     // Only support connecting the endpoint we created.\r
291     //\r
292     if( pEndpoint != m_pEndpoint )\r
293         return ND_INVALID_PARAMETER_1;\r
294 \r
295     //\r
296     // Format the private data to match the RDMA CM annex spec as we\r
297     // check the address validity.\r
298     //\r
299     ual_ndi_req_cm_ioctl_in_t ioctl;\r
300     ioctl.pdata.maj_min_ver = 0;\r
301     if( LocalPort == 0 )\r
302     {\r
303         m_LocalPort = (USHORT)_byteswap_ulong( m_pEndpoint->m_Qpn );\r
304     }\r
305     else\r
306     {\r
307         m_LocalPort = LocalPort;\r
308     }\r
309     ioctl.pdata.src_port = _byteswap_ushort( m_LocalPort );\r
310 \r
311     // Resolve the GIDs.\r
312    HRESULT hr = IBAT::Resolve(\r
313         &m_pParent->m_Addr.unspec,\r
314         pAddress,\r
315         (IBAT_PATH_BLOB*)&ioctl.path\r
316         );\r
317     if( FAILED( hr ) )\r
318     {\r
319         if( hr == E_PENDING )\r
320         {\r
321             //\r
322             // Complete the request with a timeout status.\r
323             //\r
324             pOverlapped->Internal = ND_PENDING;\r
325             hr = NtDeviceIoControlFile(\r
326                 m_pParent->GetFileHandle(),\r
327                 pOverlapped->hEvent,\r
328                 NULL,\r
329                 (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
330                 (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
331                 UAL_NDI_NOOP,\r
332                 &hr,\r
333                 sizeof(hr),\r
334                 NULL,\r
335                 0 );\r
336         }\r
337         return hr;\r
338     }\r
339 \r
340     switch( ((struct sockaddr_in*)pAddress)->sin_family )\r
341     {\r
342     case AF_INET:\r
343         if( AddressLength != sizeof(struct sockaddr_in) )\r
344             return ND_INVALID_ADDRESS;\r
345 \r
346         if( m_pParent->m_Addr.v4.sin_family != AF_INET )\r
347             return ND_INVALID_ADDRESS;\r
348 \r
349         //\r
350         // Copy the destination address so we can satisfy a\r
351         // GetPeerAddress request.\r
352         //\r
353         m_PeerAddr.v4 = *(struct sockaddr_in*)pAddress;\r
354 \r
355         ioctl.dst_port = m_PeerAddr.v4.sin_port;\r
356         ioctl.pdata.ipv = 0x40;\r
357 \r
358         // Local address.\r
359         RtlZeroMemory( &ioctl.pdata.src_ip_addr, ATS_IPV4_OFFSET );\r
360         CopyMemory(\r
361             &ioctl.pdata.src_ip_addr[ATS_IPV4_OFFSET>>2],\r
362             (uint8_t*)&m_pParent->m_Addr.v4.sin_addr,\r
363             sizeof( m_pParent->m_Addr.v4.sin_addr )\r
364             );\r
365 \r
366         // Destination address.\r
367         RtlZeroMemory( &ioctl.pdata.dst_ip_addr, ATS_IPV4_OFFSET );\r
368         CopyMemory(\r
369             &ioctl.pdata.dst_ip_addr[ATS_IPV4_OFFSET>>2],\r
370             (uint8_t*)&m_PeerAddr.v4.sin_addr,\r
371             sizeof( m_PeerAddr.v4.sin_addr )\r
372             );\r
373         ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
374             ("local address: IP %#x, port %#hx, dest address: IP %#x, port %#hx\n", \r
375             cl_hton32(m_pParent->m_Addr.v4.sin_addr.S_un.S_addr), cl_hton16(m_pParent->m_Addr.v4.sin_port),\r
376             cl_hton32(m_PeerAddr.v4.sin_addr.S_un.S_addr), cl_hton16(m_PeerAddr.v4.sin_port) ) );\r
377         break;\r
378 \r
379     case AF_INET6:\r
380         if( AddressLength != sizeof(struct sockaddr_in6) )\r
381             return ND_INVALID_ADDRESS;\r
382 \r
383         //\r
384         // Copy the destination address so we can satisfy a\r
385         // GetPeerAddress request.\r
386         //\r
387         m_PeerAddr.v6 = *(struct sockaddr_in6*)pAddress;\r
388 \r
389         ioctl.dst_port = m_PeerAddr.v6.sin6_port;\r
390         ioctl.pdata.ipv = 0x60;\r
391 \r
392         // Local address.\r
393         CopyMemory(\r
394             ioctl.pdata.src_ip_addr,\r
395             m_pParent->m_Addr.v6.sin6_addr.u.Byte,\r
396             sizeof(ioctl.pdata.src_ip_addr)\r
397             );\r
398 \r
399         // Destination address.\r
400         CopyMemory( ioctl.pdata.dst_ip_addr,\r
401             m_PeerAddr.v6.sin6_addr.u.Byte,\r
402             sizeof(ioctl.pdata.dst_ip_addr)\r
403             );\r
404         break;\r
405 \r
406     default:\r
407         return ND_INVALID_ADDRESS;\r
408     }\r
409 \r
410     // Copy the user's private data.\r
411     CopyMemory( ioctl.pdata.pdata, pPrivateData, PrivateDataLength );\r
412 \r
413     //\r
414     // It's only valid to call Connect with a new or reused endpoint:\r
415     // the QP must be in the INIT state.\r
416     //\r
417     switch( m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp ) )\r
418     {\r
419     case IB_QPS_INIT:\r
420         break;\r
421 \r
422     case IB_QPS_RTS:\r
423         return ND_CONNECTION_ACTIVE;\r
424 \r
425     default:\r
426         return ND_UNSUCCESSFUL;\r
427     }\r
428 \r
429     //\r
430     // Create the CEP.  We do this so that we have a valid CID in user-mode\r
431     // in case the user calls CancelOverlappedRequests or releases the object.\r
432     //\r
433     UINT64 context = 0;\r
434     ual_create_cep_ioctl_t create;\r
435     DWORD bytes_ret;\r
436     BOOL fSuccess = DeviceIoControl(\r
437         m_pParent->m_hSync,\r
438         UAL_CREATE_CEP,\r
439         &context,\r
440         sizeof(context),\r
441         &create,\r
442         sizeof(create),\r
443         &bytes_ret,\r
444         NULL\r
445         );\r
446     if( !fSuccess ||\r
447         bytes_ret != sizeof(create) ||\r
448         create.status != IB_SUCCESS )\r
449     {\r
450         return ND_INSUFFICIENT_RESOURCES;\r
451     }\r
452 \r
453     m_cid = create.cid;\r
454 \r
455     //\r
456     // Fill in the rest of the input buffer and send the request down\r
457     // to the kernel and let everything else be done there.\r
458     //\r
459     ioctl.h_qp = m_pEndpoint->m_hQp;\r
460     ioctl.guid = m_pParent->m_PortGuid;\r
461     ioctl.cid = m_cid;\r
462     ioctl.prot = m_Protocol;\r
463     ioctl.pdata_size = sizeof(ioctl.pdata);\r
464     ioctl.init_depth = m_pEndpoint->m_Ord;\r
465     ioctl.resp_res = m_pEndpoint->m_Ird;\r
466 \r
467     ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
468         ("Connect QP %#I64x, QPn %#x, Guid %#I64x \n",\r
469         m_pEndpoint->m_hQp,\r
470         m_pEndpoint->m_Qpn,\r
471         m_pParent->m_PortGuid ) );\r
472 \r
473     m_fActive = true;\r
474 \r
475     pOverlapped->Internal = ND_PENDING;\r
476     hr = NtDeviceIoControlFile(\r
477         m_pParent->GetFileHandle(),\r
478         pOverlapped->hEvent,\r
479         NULL,\r
480         (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
481         (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
482         UAL_NDI_REQ_CM,\r
483         &ioctl,\r
484         sizeof(ioctl),\r
485         NULL,\r
486         0 );\r
487 \r
488     if( FAILED( hr ) )\r
489     {\r
490         FreeCid();\r
491         m_pEndpoint->Release();\r
492         m_pEndpoint = NULL;\r
493     }\r
494 \r
495     return hr;\r
496 }\r
497 \r
498 HRESULT CConnector::CompleteConnect(\r
499     __inout OVERLAPPED* pOverlapped\r
500     )\r
501 {\r
502     ND_ENTER( ND_DBG_NDI );\r
503 \r
504     if( !m_fActive )\r
505         return ND_CONNECTION_INVALID;\r
506 \r
507     if( m_pEndpoint == NULL )\r
508         return ND_CONNECTION_INVALID;\r
509 \r
510     //\r
511     // Get the UVP's buffer for modify operations.\r
512     //\r
513     void* pOutbuf;\r
514     DWORD szOutbuf;\r
515 \r
516     m_pParent->m_Ifc.user_verbs.nd_modify_qp(\r
517         (const ib_qp_handle_t)m_pEndpoint->m_uQp,\r
518         &pOutbuf,\r
519         &szOutbuf\r
520         );\r
521 \r
522     ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
523         ("CompleteConnect QP %#I64x, QPn %#x\n", m_pEndpoint->m_hQp, m_pEndpoint->m_Qpn ) );\r
524 \r
525     pOverlapped->Internal = ND_PENDING;\r
526     return NtDeviceIoControlFile(\r
527         m_pParent->GetFileHandle(),\r
528         pOverlapped->hEvent,\r
529         NULL,\r
530         (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
531         (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
532         UAL_NDI_RTU_CM,\r
533         &m_cid,\r
534         sizeof(m_cid),\r
535         pOutbuf,\r
536         szOutbuf );\r
537 }\r
538 \r
539 HRESULT CConnector::Accept(\r
540     __in INDEndpoint* pEndpoint,\r
541     __in_bcount_opt(PrivateDataLength) const void* pPrivateData,\r
542     __in SIZE_T PrivateDataLength,\r
543     __inout OVERLAPPED* pOverlapped\r
544     )\r
545 {\r
546     ND_ENTER( ND_DBG_NDI );\r
547 \r
548     if( PrivateDataLength > IB_REJ_PDATA_SIZE )\r
549         return ND_BUFFER_OVERFLOW;\r
550 \r
551     //\r
552     // Only support connecting the endpoint we created.\r
553     //\r
554     if( pEndpoint != m_pEndpoint )\r
555         return ND_INVALID_PARAMETER_1;\r
556 \r
557     //\r
558     // Get the UVP's buffer for modify operations.\r
559     //\r
560     void* pOutbuf;\r
561     DWORD szOutbuf;\r
562 \r
563     m_pParent->m_Ifc.user_verbs.nd_modify_qp(\r
564         static_cast<CEndpoint*>(pEndpoint)->m_uQp,\r
565         &pOutbuf,\r
566         &szOutbuf\r
567         );\r
568 \r
569     ual_ndi_rep_cm_ioctl_in_t ioctl;\r
570     ioctl.h_qp = m_pEndpoint->m_hQp;\r
571     ioctl.cid = m_cid;\r
572     ioctl.init_depth = m_pEndpoint->m_Ord;\r
573     ioctl.resp_res = m_pEndpoint->m_Ird;\r
574     ioctl.pdata_size = (uint8_t)PrivateDataLength;\r
575     CopyMemory( &ioctl.pdata, pPrivateData, PrivateDataLength );\r
576 \r
577     ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
578         ("Accept QP %#I64x, cid %d \n", ioctl.h_qp, ioctl.cid ) );\r
579 \r
580     pOverlapped->Internal = ND_PENDING;\r
581     HRESULT hr = NtDeviceIoControlFile(\r
582         m_pParent->GetFileHandle(),\r
583         pOverlapped->hEvent,\r
584         NULL,\r
585         (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
586         (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
587         UAL_NDI_REP_CM,\r
588         &ioctl,\r
589         sizeof(ioctl),\r
590         pOutbuf,\r
591         szOutbuf );\r
592 \r
593     if( FAILED( hr ) )\r
594     {\r
595         m_pEndpoint->Release();\r
596         m_pEndpoint = NULL;\r
597     }\r
598     return hr;\r
599 }\r
600 \r
601 HRESULT CConnector::Reject(\r
602     __in_bcount_opt(PrivateDataLength) const void* pPrivateData,\r
603     __in SIZE_T PrivateDataLength\r
604     )\r
605 {\r
606     ND_ENTER( ND_DBG_NDI );\r
607 \r
608     if( PrivateDataLength > IB_REJ_PDATA_SIZE )\r
609         return ND_BUFFER_OVERFLOW;\r
610 \r
611     ual_ndi_rej_cm_ioctl_in_t ioctl;\r
612     ioctl.cid = m_cid;\r
613     ioctl.pdata_size = (uint8_t)PrivateDataLength;\r
614     if( pPrivateData != NULL )\r
615     {\r
616         CopyMemory( &ioctl.pdata, pPrivateData, PrivateDataLength );\r
617     }\r
618 \r
619     ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI, \r
620         ("Connection rejected with pdata_size %d, cid %d\n", \r
621         (int)PrivateDataLength, ioctl.cid ));\r
622 \r
623     IO_STATUS_BLOCK IoStatus;\r
624     return NtDeviceIoControlFile(\r
625         m_pParent->m_hSync,\r
626         NULL,\r
627         NULL,\r
628         NULL,\r
629         &IoStatus,\r
630         UAL_NDI_REJ_CM,\r
631         &ioctl,\r
632         sizeof(ioctl),\r
633         NULL,\r
634         0 );\r
635 }\r
636 \r
637 HRESULT CConnector::GetConnectionData(\r
638     __out_opt SIZE_T* pInboundReadLimit,\r
639     __out_opt SIZE_T* pOutboundReadLimit,\r
640     __out_bcount_part_opt(*pPrivateDataLength, *pPrivateDataLength) void* pPrivateData,\r
641     __inout SIZE_T* pPrivateDataLength\r
642     )\r
643 {\r
644     ND_ENTER( ND_DBG_NDI );\r
645 \r
646     IO_STATUS_BLOCK IoStatus;\r
647     ual_cep_get_pdata_ioctl_t IoctlBuf;\r
648 \r
649     IoctlBuf.in.cid = m_cid;\r
650     HRESULT hr = NtDeviceIoControlFile(\r
651         m_pParent->m_hSync,\r
652         NULL,\r
653         NULL,\r
654         NULL,\r
655         &IoStatus,\r
656         UAL_CEP_GET_PDATA,\r
657         &IoctlBuf,\r
658         sizeof(IoctlBuf.in),\r
659         &IoctlBuf,\r
660         sizeof(IoctlBuf.out) );\r
661 \r
662     // UAL_CEP_GET_PDATA never returns pending.\r
663     if( FAILED( hr ) )\r
664         return hr;\r
665 \r
666     // On the passive side, check that we got the REQ private data.\r
667     if( !m_fActive )\r
668     {\r
669         hr = GetPdataForPassive(\r
670             IoctlBuf.out.pdata,\r
671             IoctlBuf.out.pdata_len,\r
672             pPrivateData,\r
673             pPrivateDataLength\r
674             );\r
675     }\r
676     else\r
677     {\r
678         hr = GetPdataForActive(\r
679             IoctlBuf.out.pdata,\r
680             IoctlBuf.out.pdata_len,\r
681             pPrivateData,\r
682             pPrivateDataLength\r
683             );\r
684     }\r
685 \r
686     if( FAILED( hr ) && hr != ND_BUFFER_OVERFLOW )\r
687         return hr;\r
688 \r
689     if( pInboundReadLimit )\r
690     {\r
691         *pInboundReadLimit = IoctlBuf.out.resp_res;\r
692     }\r
693 \r
694     if( pOutboundReadLimit )\r
695     {\r
696         *pOutboundReadLimit = IoctlBuf.out.init_depth;\r
697     }\r
698 \r
699     return hr;\r
700 }\r
701 \r
702 HRESULT CConnector::GetLocalAddress(\r
703     __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress,\r
704     __inout SIZE_T* pAddressLength\r
705     )\r
706 {\r
707     ND_ENTER( ND_DBG_NDI );\r
708 \r
709     if( m_pEndpoint == NULL )\r
710         return ND_CONNECTION_INVALID;\r
711 \r
712     ib_qp_state_t state =\r
713         m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp );\r
714     if( state != IB_QPS_RTS )\r
715         return ND_CONNECTION_INVALID;\r
716 \r
717     HRESULT hr = m_pParent->GetLocalAddress( pAddress, pAddressLength );\r
718     if( FAILED(hr) )\r
719         return hr;\r
720 \r
721     // V4 and V6 addresses have the port number in the same place.\r
722     ((struct sockaddr_in*)pAddress)->sin_port = m_LocalPort;\r
723 #if DBG || defined(EVENT_TRACING)\r
724     struct sockaddr_in*pAddrV4 = (struct sockaddr_in*)pAddress;\r
725 #endif        \r
726     ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
727         ("Local address: IP %#x, port %#hx\n", \r
728         cl_hton32(pAddrV4->sin_addr.S_un.S_addr), cl_hton16(pAddrV4->sin_port) ) );\r
729 \r
730     return S_OK;\r
731 }\r
732 \r
733 HRESULT CConnector::GetAddressFromPdata(\r
734     __out_bcount_part(*pAddressLength, *pAddressLength) struct sockaddr* pAddress,\r
735     __inout SIZE_T* pAddressLength\r
736     )\r
737 {\r
738     ND_ENTER( ND_DBG_NDI );\r
739 \r
740     IO_STATUS_BLOCK IoStatus;\r
741     ual_cep_get_pdata_ioctl_t IoctlBuf;\r
742 \r
743     IoctlBuf.in.cid = m_cid;\r
744 \r
745     HRESULT hr = NtDeviceIoControlFile(\r
746         m_pParent->m_hSync,\r
747         NULL,\r
748         NULL,\r
749         NULL,\r
750         &IoStatus,\r
751         UAL_CEP_GET_PDATA,\r
752         &IoctlBuf,\r
753         sizeof(IoctlBuf.in),\r
754         &IoctlBuf,\r
755         sizeof(IoctlBuf.out) );\r
756 \r
757     // UAL_CEP_GET_PDATA never returns pending.\r
758     if( FAILED( hr ) )\r
759     {\r
760         CL_ASSERT( hr != ND_PENDING );\r
761         return hr;\r
762     }\r
763 \r
764     if( IoctlBuf.out.pdata_len != IB_REQ_PDATA_SIZE )\r
765         return ND_CONNECTION_ABORTED;\r
766 \r
767     ib_cm_rdma_req_t* pIpData = (ib_cm_rdma_req_t*)&IoctlBuf.out.pdata;\r
768     CL_ASSERT( pIpData->maj_min_ver == 0 );\r
769 \r
770     SIZE_T len;\r
771     switch( pIpData->ipv )\r
772     {\r
773     case 0x40:\r
774         len = 4;\r
775         break;\r
776     case 0x60:\r
777         len = 16;\r
778         break;\r
779     default:\r
780         CL_ASSERT( pIpData->ipv == 0x40 || pIpData->ipv == 0x60 );\r
781         len = 0;\r
782         break;\r
783     }\r
784 \r
785     if( len > *pAddressLength )\r
786     {\r
787         *pAddressLength = len;\r
788         return ND_BUFFER_OVERFLOW;\r
789     }\r
790 \r
791     ((struct sockaddr_in*)pAddress)->sin_port =\r
792         _byteswap_ushort( pIpData->src_port );\r
793 \r
794     switch( pIpData->ipv )\r
795     {\r
796     case 0x40:\r
797         ((struct sockaddr_in*)pAddress)->sin_family = AF_INET;\r
798         ((struct sockaddr_in*)pAddress)->sin_addr.s_addr = pIpData->src_ip_addr[3];\r
799         ZeroMemory( ((struct sockaddr_in*)pAddress)->sin_zero,\r
800             sizeof( ((struct sockaddr_in*)pAddress)->sin_zero ) );\r
801         break;\r
802 \r
803     case 0x60:\r
804         ((struct sockaddr_in6*)pAddress)->sin6_family = AF_INET6;\r
805         ((struct sockaddr_in6*)pAddress)->sin6_flowinfo = 0;\r
806         RtlCopyMemory( (char*)((struct sockaddr_in6*)pAddress)->sin6_addr.s6_bytes,\r
807             (char *const)pIpData->src_ip_addr, sizeof(pIpData->src_ip_addr) );\r
808         ((struct sockaddr_in6*)pAddress)->sin6_scope_id = 0;\r
809         break;\r
810     }\r
811 \r
812     *pAddressLength = len;\r
813     return hr;\r
814 }\r
815 \r
816 HRESULT CConnector::GetPeerAddress(\r
817     __out_bcount_part_opt(*pAddressLength, *pAddressLength) struct sockaddr* pAddress,\r
818     __inout SIZE_T* pAddressLength\r
819     )\r
820 {\r
821     ND_ENTER( ND_DBG_NDI );\r
822 \r
823     if( !m_fActive )\r
824         return GetAddressFromPdata( pAddress, pAddressLength );\r
825 \r
826     if( m_pEndpoint == NULL )\r
827         return ND_CONNECTION_INVALID;\r
828 \r
829     ib_qp_state_t state =\r
830         m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp );\r
831     if( state != IB_QPS_RTS )\r
832         return ND_CONNECTION_INVALID;\r
833 \r
834     switch( m_PeerAddr.v4.sin_family )\r
835     {\r
836     case AF_INET:\r
837         if( *pAddressLength < sizeof(struct sockaddr_in) )\r
838         {\r
839             *pAddressLength = sizeof(struct sockaddr_in);\r
840             return ND_BUFFER_OVERFLOW;\r
841         }\r
842         *(struct sockaddr_in*)pAddress = m_PeerAddr.v4;\r
843         ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
844             ("Peer address: IP %#x, port %#hx\n", \r
845             cl_hton32(m_PeerAddr.v4.sin_addr.S_un.S_addr), cl_hton16(m_PeerAddr.v4.sin_port) ) );\r
846         break;\r
847 \r
848     case AF_INET6:\r
849         if( *pAddressLength < sizeof(struct sockaddr_in6) )\r
850         {\r
851             *pAddressLength = sizeof(struct sockaddr_in6);\r
852             return ND_BUFFER_OVERFLOW;\r
853         }\r
854         *(struct sockaddr_in6*)pAddress = m_PeerAddr.v6;\r
855         break;\r
856 \r
857     default:\r
858         return ND_CONNECTION_INVALID;\r
859     }\r
860 \r
861     return S_OK;\r
862 }\r
863 \r
864 HRESULT CConnector::NotifyDisconnect(\r
865     __inout OVERLAPPED* pOverlapped\r
866     )\r
867 {\r
868     ND_ENTER( ND_DBG_NDI );\r
869 \r
870     pOverlapped->Internal = ND_PENDING;\r
871     return NtDeviceIoControlFile(\r
872         m_pParent->GetFileHandle(),\r
873         pOverlapped->hEvent,\r
874         NULL,\r
875         (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
876         (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
877         UAL_NDI_NOTIFY_DREQ,\r
878         &m_cid,\r
879         sizeof(m_cid),\r
880         NULL,\r
881         0 );\r
882 }\r
883 \r
884 HRESULT CConnector::Disconnect(\r
885     __inout OVERLAPPED* pOverlapped\r
886     )\r
887 {\r
888     ND_ENTER( ND_DBG_NDI );\r
889 \r
890     if( m_pEndpoint == NULL )\r
891         return ND_CONNECTION_INVALID;\r
892 \r
893     ib_qp_state_t state =\r
894         m_pParent->m_Ifc.user_verbs.nd_get_qp_state( m_pEndpoint->m_uQp );\r
895     if( state != IB_QPS_RTS )\r
896         return ND_CONNECTION_INVALID;\r
897 \r
898     //\r
899     // Get the UVP's buffer for modify operations.\r
900     //\r
901     void* pOutbuf;\r
902     DWORD szOutbuf;\r
903 \r
904     m_pParent->m_Ifc.user_verbs.nd_modify_qp(\r
905         m_pEndpoint->m_uQp,\r
906         &pOutbuf,\r
907         &szOutbuf\r
908         );\r
909 \r
910     ND_PRINT( TRACE_LEVEL_INFORMATION, ND_DBG_NDI,\r
911         ("Disconnect QP %#I64x, QPn %#x\n", m_pEndpoint->m_hQp, m_pEndpoint->m_Qpn ) );\r
912 \r
913     pOverlapped->Internal = ND_PENDING;\r
914     HRESULT hr = NtDeviceIoControlFile(\r
915         m_pParent->GetFileHandle(),\r
916         pOverlapped->hEvent,\r
917         NULL,\r
918         (ULONG_PTR)pOverlapped->hEvent & 1 ? NULL : pOverlapped,\r
919         (IO_STATUS_BLOCK*)&pOverlapped->Internal,\r
920         UAL_NDI_DREQ_CM,\r
921         &m_cid,\r
922         sizeof(m_cid),\r
923         pOutbuf,\r
924         szOutbuf );\r
925 \r
926     if( SUCCEEDED( hr ) )\r
927     {\r
928         m_pEndpoint->Release();\r
929         m_pEndpoint = NULL;\r
930     }\r
931 \r
932     return hr;\r
933 }\r
934 \r
935 } // namespace\r