[WSD] Make QP destruction asynchronous to speed up socket closure.
[mirror/winof/.git] / ulp / wsd / user / ibspdll.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  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 <tchar.h>\r
33 #include <stdlib.h>\r
34 #include "ibspdll.h"\r
35 \r
36 /* Globals */\r
37 struct ibspdll_globals g_ibsp;\r
38 \r
39 /* Defines */\r
40 static const WCHAR *Description = L"Winsock Service Provider for Infiniband Transport";\r
41 \r
42 /* Unique provider GUID generated with "uuidgen -s". Same as in installsp.c. */\r
43 static const GUID provider_guid = {\r
44         /* c943654d-2c84-4db7-af3e-fdf1c5322458 */\r
45         0xc943654d, 0x2c84, 0x4db7,\r
46         {0xaf, 0x3e, 0xfd, 0xf1, 0xc5, 0x32, 0x24, 0x58}\r
47 };\r
48 \r
49 static DWORD    no_read = 0;\r
50 uint32_t                g_max_inline = 0xFFFFFFFF;\r
51 \r
52 /*\r
53  * Function: DllMain\r
54  * \r
55  *  Description:\r
56  *    Provides initialization when the ibspdll DLL is loaded. \r
57  */\r
58 #pragma auto_inline( off )\r
59 static BOOL\r
60 _DllMain(\r
61         IN                              HINSTANCE                                       hinstDll,\r
62         IN                              DWORD                                           dwReason,\r
63         IN                              LPVOID                                          lpvReserved )\r
64 {\r
65         TCHAR   env_var[16];\r
66         DWORD   i;\r
67 \r
68         IBSP_ENTER( IBSP_DBG_DLL );\r
69 \r
70         UNUSED_PARAM( hinstDll );\r
71         UNUSED_PARAM( lpvReserved );\r
72 \r
73         fzprint(("%s():%d:0x%x:0x%x: hinstDll=%d dwReason=%d lpvReserved=0x%p\n",\r
74                          __FUNCTION__,\r
75                          __LINE__, GetCurrentProcessId(),\r
76                          GetCurrentThreadId(), hinstDll, dwReason, lpvReserved));\r
77 \r
78 //#ifdef _DEBUG_\r
79 #if 0\r
80         {\r
81                 char buf[64];\r
82                 if( GetEnvironmentVariable( "IBSPLOAD", buf, sizeof(buf) ) == 0 )\r
83                 {\r
84                         IBSP_ERROR_EXIT( ("IBSPLOAD not defined:\n") );\r
85 \r
86                         return FALSE;\r
87                 }\r
88         }\r
89 #endif\r
90 \r
91         switch( dwReason )\r
92         {\r
93         case DLL_PROCESS_ATTACH:\r
94                 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_PROCESS_ATTACH\n") );\r
95 \r
96 #ifdef _DEBUG_\r
97                 i = GetEnvironmentVariable( "IBWSD_DBG", env_var, sizeof(env_var) );\r
98                 if( i && i <= 16 )\r
99                 {\r
100                         gdbg_lvl = _tcstoul( env_var, NULL, 16 );\r
101                         IBSP_TRACE( IBSP_DBG_DLL,\r
102                                 ("Given IBWSD_DBG debug level:0x%X\n",\r
103                                 gdbg_lvl) );\r
104                 }\r
105 #endif\r
106 \r
107                 /* See if the user wants to disable RDMA reads. */\r
108                 no_read = GetEnvironmentVariable( "IBWSD_NO_READ", NULL, 0 );\r
109 \r
110                 i = GetEnvironmentVariable( "IBWSD_INLINE", env_var, sizeof(env_var) );\r
111                 if( i && i <= 16 )\r
112                         g_max_inline = _tcstoul( env_var, NULL, 10 );\r
113 \r
114                 if( init_globals() )\r
115                         return FALSE;\r
116                 break;\r
117 \r
118         case DLL_THREAD_ATTACH:\r
119                 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_THREAD_ATTACH\n") );\r
120                 break;\r
121 \r
122         case DLL_THREAD_DETACH:\r
123                 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_THREAD_DETACH\n") );\r
124                 break;\r
125 \r
126         case DLL_PROCESS_DETACH:\r
127                 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_PROCESS_DETACH\n") );\r
128 \r
129 #ifdef _DEBUG_\r
130                 {\r
131                         cl_list_item_t *socket_item = NULL;\r
132 \r
133                         cl_spinlock_acquire( &g_ibsp.socket_info_mutex );\r
134 \r
135                         for( socket_item = cl_qlist_head( &g_ibsp.socket_info_list );\r
136                                 socket_item != cl_qlist_end( &g_ibsp.socket_info_list );\r
137                                 socket_item = cl_qlist_next( socket_item ) )\r
138                         {\r
139                                 struct ibsp_socket_info *socket_info = NULL;\r
140                                 socket_info = PARENT_STRUCT(socket_item, struct ibsp_socket_info, item);\r
141                         }\r
142 \r
143                         cl_spinlock_release( &g_ibsp.socket_info_mutex );\r
144 \r
145                         IBSP_ERROR( ("Statistics:\n") );\r
146                         IBSP_ERROR(\r
147                                          ("  overlap_h0_count = %d\n", g_ibsp.overlap_h0_count) );\r
148                         IBSP_ERROR(\r
149                                          ("  max_comp_count = %d\n", g_ibsp.max_comp_count) );\r
150                         IBSP_ERROR(\r
151                                          ("  overlap_h1_count = %d\n", g_ibsp.overlap_h1_count) );\r
152 \r
153                         IBSP_ERROR( ("  send_count = %d\n", g_ibsp.send_count) );\r
154 \r
155                         IBSP_ERROR(\r
156                                          ("  number of QPs left = %d\n", g_ibsp.qp_num) );\r
157                         IBSP_ERROR(\r
158                                          ("  number of CQs left = %d\n", g_ibsp.cq_num) );\r
159                         IBSP_ERROR(\r
160                                          ("  number of PDs left = %d\n", g_ibsp.pd_num) );\r
161                         IBSP_ERROR(\r
162                                          ("  number of ALs left = %d\n", g_ibsp.al_num) );\r
163                         IBSP_ERROR(\r
164                                          ("  number of MRs left = %d\n", g_ibsp.mr_num) );\r
165                         IBSP_ERROR(\r
166                                          ("  number of listens left = %d\n", g_ibsp.listen_num) );\r
167                         IBSP_ERROR(\r
168                                          ("  number of PNPs left = %d\n", g_ibsp.pnp_num) );\r
169                         IBSP_ERROR(\r
170                                          ("  number of threads left = %d\n", g_ibsp.thread_num) );\r
171                         IBSP_ERROR(\r
172                                          ("  number of WPU sockets left = %d\n", g_ibsp.wpusocket_num) );\r
173 \r
174                         IBSP_ERROR(\r
175                                          ("  CloseSocket_count = %d\n", g_ibsp.CloseSocket_count) );\r
176 \r
177                 }\r
178 #endif\r
179                 release_globals();\r
180                 break;\r
181         }\r
182 \r
183         IBSP_EXIT( IBSP_DBG_DLL );\r
184 \r
185         return TRUE;\r
186 }\r
187 #pragma auto_inline( off )\r
188 \r
189 \r
190 extern BOOL APIENTRY\r
191 _DllMainCRTStartupForGS(\r
192         IN                              HINSTANCE                                       h_module,\r
193         IN                              DWORD                                           ul_reason_for_call, \r
194         IN                              LPVOID                                          lp_reserved );\r
195 \r
196 \r
197 BOOL APIENTRY\r
198 DllMain(\r
199         IN                              HINSTANCE                                       h_module,\r
200         IN                              DWORD                                           ul_reason_for_call, \r
201         IN                              LPVOID                                          lp_reserved )\r
202 {\r
203         switch( ul_reason_for_call )\r
204         {\r
205         case DLL_PROCESS_ATTACH:\r
206                 if( !_DllMainCRTStartupForGS(\r
207                         h_module, ul_reason_for_call, lp_reserved ) )\r
208                 {\r
209                         return FALSE;\r
210                 }\r
211 \r
212                 return _DllMain( h_module, ul_reason_for_call, lp_reserved );\r
213 \r
214         case DLL_PROCESS_DETACH:\r
215                 _DllMain( h_module, ul_reason_for_call, lp_reserved );\r
216 \r
217                 return _DllMainCRTStartupForGS(\r
218                         h_module, ul_reason_for_call, lp_reserved );\r
219         }\r
220         return TRUE;\r
221 }\r
222 \r
223 \r
224 /* Function: IBSPAccept\r
225  *\r
226  *  Description:\r
227  *    Handle the WSAAccept function. The only special consideration here\r
228  *    is the conditional accept callback. You can choose to intercept\r
229  *    this by substituting your own callback (you'll need to keep track\r
230  *    of the user supplied callback so you can trigger that once your\r
231  *    substituted function is triggered).\r
232  */\r
233 static SOCKET WSPAPI\r
234 IBSPAccept(\r
235         IN                              SOCKET                                          s,\r
236                 OUT                     struct sockaddr FAR                     *addr,\r
237         IN      OUT                     LPINT                                           addrlen,\r
238         IN                              LPCONDITIONPROC                         lpfnCondition,\r
239         IN                              DWORD_PTR                                       dwCallbackData,\r
240                 OUT                     LPINT                                           lpErrno )\r
241 {\r
242         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
243         struct ibsp_socket_info *new_socket_info;\r
244         int ret;\r
245         WSABUF caller_id;\r
246         WSABUF callee_id;\r
247         struct listen_incoming *incoming;\r
248         struct ibsp_port *port;\r
249 \r
250         IBSP_ENTER( IBSP_DBG_CONN );\r
251 \r
252         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,\r
253                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
254 \r
255         CL_ASSERT( lpfnCondition );\r
256 \r
257         if( *addrlen < sizeof(struct sockaddr_in) )\r
258         {\r
259                 IBSP_ERROR_EXIT( ("invalid addrlen (%d, %d)\n",\r
260                         *addrlen, sizeof(struct sockaddr_in)) );\r
261                 *lpErrno = WSAEFAULT;\r
262                 return INVALID_SOCKET;\r
263         }\r
264 \r
265         /* Check if there is any pending connection for this socket. If\r
266          * there is one, create a socket, and then query the switch about\r
267          * the pending connection */\r
268 \r
269         cl_spinlock_acquire( &socket_info->mutex );\r
270 \r
271         /* Verify the state of the socket */\r
272         if( socket_info->socket_state != IBSP_LISTEN )\r
273         {\r
274                 cl_spinlock_release( &socket_info->mutex );\r
275                 IBSP_ERROR_EXIT( ("Socket is not in right socket_state (%s)\n",\r
276                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
277                 *lpErrno = WSAEINVAL;\r
278                 return INVALID_SOCKET;\r
279         }\r
280 \r
281         if( cl_qlist_count( &socket_info->listen.list ) == 0 )\r
282         {\r
283                 cl_spinlock_release( &socket_info->mutex );\r
284 \r
285                 IBSP_ERROR_EXIT( ("No pending connection found for this socket\n") );\r
286                 *lpErrno = WSAEWOULDBLOCK;\r
287                 return INVALID_SOCKET;\r
288         }\r
289 \r
290         IBSP_TRACE( IBSP_DBG_CONN,\r
291                 ("IBSPAccept: Found pending connection on this socket\n") );\r
292 \r
293         incoming = PARENT_STRUCT(cl_qlist_head( &socket_info->listen.list ),\r
294                                                          struct listen_incoming, item);\r
295         port = socket_info->port;\r
296 \r
297         /* Find the destination IP address */\r
298         if( port == NULL )\r
299         {\r
300                 /* The socket was bound to INADDR_ANY. We must find the correct port\r
301                  * for the new socket. */\r
302                 port = get_port_from_ip_address( incoming->params.dest.sin_addr );\r
303                 if( port == NULL )\r
304                 {\r
305                         IBSP_ERROR(\r
306                                 ("incoming destination IP address not local (%s)\n",\r
307                                 inet_ntoa( incoming->params.dest.sin_addr )) );\r
308                         goto reject;\r
309                 }\r
310         }\r
311 \r
312         /* Cross-check with the path info to make sure we are conectiong correctly */\r
313         if( port->guid != ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid ) )\r
314         {\r
315                 IBSP_ERROR(\r
316                         ("GUIDs of port for destination IP address and primary path do not match (%016I64x, %016I64x)\n",\r
317                         port->guid,\r
318                         ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid )) );\r
319 \r
320 reject:\r
321                 /* The request is invalid. Remove it from the list and reject it. */\r
322                 cl_qlist_remove_item( &socket_info->listen.list, &incoming->item );\r
323                 cl_spinlock_release( &socket_info->mutex );\r
324 \r
325                 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );\r
326 \r
327                 HeapFree( g_ibsp.heap, 0, incoming );\r
328                 IBSP_ERROR_EXIT( ("bad incoming parameter\n") );\r
329                 *lpErrno = WSAECONNREFUSED;\r
330                 return INVALID_SOCKET;\r
331         }\r
332 \r
333         /*\r
334          * Check against the conditional routine if socket can be created\r
335          * or not \r
336          */\r
337 \r
338         /* Set the caller and callee data buffer */\r
339         caller_id.buf = (char *)&incoming->params.source;\r
340         caller_id.len = sizeof(incoming->params.source);\r
341 \r
342         callee_id.buf = (char *)&incoming->params.dest;\r
343         callee_id.len = sizeof(incoming->params.dest);\r
344 \r
345         IBSP_TRACE( IBSP_DBG_CONN,\r
346                 ("Got incoming conn from %s/%d-%d to %s/%d-%d\n",\r
347                 inet_ntoa( incoming->params.source.sin_addr ),\r
348                 cl_ntoh16( incoming->params.source.sin_port ),\r
349                 incoming->params.source.sin_family,\r
350                 inet_ntoa( incoming->params.dest.sin_addr ),\r
351                 cl_ntoh16( incoming->params.dest.sin_port ),\r
352                 incoming->params.dest.sin_family) );\r
353 \r
354         /* Call the conditional function */\r
355         ret = lpfnCondition( &caller_id, NULL, NULL, NULL,\r
356                 &callee_id, NULL, NULL, dwCallbackData );\r
357 \r
358         switch( ret )\r
359         {\r
360         case CF_REJECT:\r
361                 cl_qlist_remove_item( &socket_info->listen.list, &incoming->item );\r
362                 cl_spinlock_release( &socket_info->mutex );\r
363 \r
364                 IBSP_TRACE1( IBSP_DBG_CONN,\r
365                         ("Conditional routine returned CF_REJECT\n") );\r
366 \r
367                 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_USER_DEFINED );\r
368 \r
369                 HeapFree( g_ibsp.heap, 0, incoming );\r
370                 *lpErrno = WSAECONNREFUSED;\r
371                 IBSP_EXIT( IBSP_DBG_CONN );\r
372                 return INVALID_SOCKET;\r
373 \r
374         case CF_DEFER:\r
375                 cl_spinlock_release( &socket_info->mutex );\r
376 \r
377                 IBSP_TRACE1( IBSP_DBG_CONN,\r
378                         ("Conditional routine returned CF_DEFER\n") );\r
379                 /* TODO: Send MRA */\r
380                 *lpErrno = WSATRY_AGAIN;\r
381                 IBSP_EXIT( IBSP_DBG_CONN );\r
382                 return INVALID_SOCKET;\r
383 \r
384         case CF_ACCEPT:\r
385                 break;\r
386 \r
387         default:\r
388                 /* Should never happen */\r
389                 cl_spinlock_release( &socket_info->mutex );\r
390                 IBSP_ERROR(\r
391                         ("Conditional routine returned undocumented code (%d)\n", ret) );\r
392                 CL_ASSERT( 0 );\r
393                 *lpErrno = WSAECONNREFUSED;\r
394                 IBSP_EXIT( IBSP_DBG_CONN );\r
395                 return INVALID_SOCKET;\r
396         }\r
397 \r
398         /* Create a new socket here  */\r
399         new_socket_info = create_socket_info( lpErrno );\r
400         if( !new_socket_info )\r
401         {\r
402                 cl_spinlock_release( &socket_info->mutex );\r
403 \r
404                 IBSP_ERROR_EXIT( ("create_socket_info failed (%d)\n", *lpErrno) );\r
405                 return INVALID_SOCKET;\r
406         }\r
407 \r
408         /* Time to allocate our IB QP */\r
409         new_socket_info->port = port;\r
410         *lpErrno = ib_create_socket( new_socket_info );\r
411         if( *lpErrno )\r
412         {\r
413                 cl_spinlock_release( &socket_info->mutex );\r
414                 deref_socket_info( new_socket_info );\r
415 \r
416                 IBSP_ERROR_EXIT( ("ib_create socket failed with %d\n", *lpErrno) );\r
417                 return INVALID_SOCKET;\r
418         }\r
419 \r
420         /* Store the IP address and port number in the socket context */\r
421         new_socket_info->local_addr = incoming->params.dest;\r
422 \r
423         cl_qlist_remove_item( &socket_info->listen.list, &incoming->item );\r
424         /* Signal the event again if there are more connection requests. */\r
425         if( cl_qlist_count( &socket_info->listen.list ) )\r
426                 ibsp_post_select_event( socket_info, FD_ACCEPT, 0 );\r
427 \r
428         cl_spinlock_release( &socket_info->mutex );\r
429 \r
430         /* Copy the socket context info from parent socket context */\r
431         new_socket_info->socket_options = socket_info->socket_options;\r
432 \r
433         /* Store the client socket address information */\r
434         memcpy( addr, &incoming->params.source, sizeof(struct sockaddr_in) );\r
435         *addrlen = sizeof(struct sockaddr_in);\r
436 \r
437         IBSP_TRACE( IBSP_DBG_CONN,\r
438                 ("The socket address of connecting entity is\n") );\r
439         DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, &incoming->params.source );\r
440 \r
441         new_socket_info->peer_addr = incoming->params.source;\r
442 \r
443         new_socket_info->h_event = CreateEvent( NULL, FALSE, FALSE, NULL );\r
444 \r
445         cl_spinlock_acquire( &new_socket_info->mutex );\r
446         /* Update the state of the socket context */\r
447         IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_ACCEPT );\r
448 \r
449         ret = ib_accept( new_socket_info, &incoming->cm_req_received );\r
450         if( ret )\r
451         {\r
452                 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CREATE );\r
453                 cl_spinlock_release( &new_socket_info->mutex );\r
454 \r
455                 if( g_ibsp.up_call_table.lpWPUCloseSocketHandle(\r
456                         new_socket_info->switch_socket, &ret ) == SOCKET_ERROR )\r
457                 {\r
458                         IBSP_ERROR( ("WPUCloseSocketHandle failed: %d\n", ret) );\r
459                 }\r
460                 else\r
461                 {\r
462                         STAT_DEC( wpusocket_num );\r
463                 }\r
464                 new_socket_info->switch_socket = INVALID_SOCKET;\r
465 \r
466                 CloseHandle( new_socket_info->h_event );\r
467 \r
468                 ib_destroy_socket( new_socket_info );\r
469 \r
470                 deref_socket_info( new_socket_info );\r
471 \r
472                 /* Be nice and reject that connection. */\r
473                 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );\r
474 \r
475                 HeapFree( g_ibsp.heap, 0, incoming );\r
476                 *lpErrno = ret;\r
477 \r
478                 IBSP_ERROR_EXIT( ("ib_accept failed (%d)\n", ret) );\r
479 \r
480                 return INVALID_SOCKET;\r
481         }\r
482         else\r
483         {\r
484                 cl_spinlock_release( &new_socket_info->mutex );\r
485                 HeapFree( g_ibsp.heap, 0, incoming );\r
486 \r
487                 if( WaitForSingleObject( new_socket_info->h_event, INFINITE ) == WAIT_OBJECT_0 )\r
488                 {\r
489                         CloseHandle( new_socket_info->h_event );\r
490                         new_socket_info->h_event = NULL;\r
491 \r
492                         cl_spinlock_acquire( &new_socket_info->mutex );\r
493 \r
494                         if( new_socket_info->socket_state == IBSP_CONNECTED )\r
495                         {\r
496                                 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );\r
497                                 cl_qlist_insert_tail( &g_ibsp.socket_info_list, &new_socket_info->item );\r
498                                 cl_spinlock_release( &g_ibsp.socket_info_mutex );\r
499 \r
500                                 cl_spinlock_release( &new_socket_info->mutex );\r
501                         }\r
502                         else\r
503                         {\r
504                                 IBSP_ERROR(\r
505                                         ("ib_accept failed - socket state is %s\n",\r
506                                         IBSP_SOCKET_STATE_STR( new_socket_info->socket_state )) );\r
507 \r
508                                 cl_spinlock_release( &new_socket_info->mutex );\r
509 \r
510                                 /* The accept failed (by a REJ for instance). */\r
511 \r
512                                 /* Free the socket descriptor */\r
513                                 if( g_ibsp.up_call_table.lpWPUCloseSocketHandle(\r
514                                         new_socket_info->switch_socket, lpErrno ) == SOCKET_ERROR )\r
515                                 {\r
516                                         IBSP_ERROR(\r
517                                                 ("WPUCloseSocketHandle failed: %d\n", *lpErrno) );\r
518                                 }\r
519                                 else\r
520                                 {\r
521                                         STAT_DEC( wpusocket_num );\r
522                                 }\r
523                                 new_socket_info->switch_socket = INVALID_SOCKET;\r
524 \r
525                                 ib_destroy_socket( new_socket_info );\r
526                                 deref_socket_info( new_socket_info );\r
527 \r
528                                 *lpErrno = WSAEACCES;\r
529 \r
530                                 new_socket_info = (struct ibsp_socket_info *)INVALID_SOCKET;\r
531                         }\r
532 \r
533                         IBSP_TRACE_EXIT( IBSP_DBG_CONN,\r
534                                 ("returns new SocketID (0x%x)\n", new_socket_info) );\r
535 \r
536                         return (SOCKET) new_socket_info;\r
537                 }\r
538                 else\r
539                 {\r
540                         CloseHandle( new_socket_info->h_event );\r
541                         new_socket_info->h_event = NULL;\r
542 \r
543                         IBSP_ERROR_EXIT( ("wait for ib_accept failed\n") );\r
544 \r
545                         *lpErrno = WSAEACCES;\r
546                         return INVALID_SOCKET;\r
547                 }\r
548         }\r
549 \r
550         /* Unreachable */\r
551 }\r
552 \r
553 \r
554 /* Function: IBSPBind\r
555  *  \r
556  *  Description:\r
557  *    Bind the socket to a local address. \r
558  *   \r
559 */\r
560 static int WSPAPI\r
561 IBSPBind(\r
562         IN                              SOCKET                                          s,\r
563         IN              const   struct sockaddr FAR                     *name,\r
564         IN                              int                                                     namelen,\r
565                 OUT                     LPINT                                           lpErrno )\r
566 {\r
567         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
568         struct sockaddr_in *addr = (struct sockaddr_in *)name;\r
569         struct ibsp_port *port;\r
570         int ret;\r
571 \r
572         IBSP_ENTER( IBSP_DBG_CONN );\r
573 \r
574         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,\r
575                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
576 \r
577         IBSP_TRACE( IBSP_DBG_CONN, ("Address to bind to:\n") );\r
578         DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, addr );\r
579 \r
580         fzprint(("binding to IP %s\n", inet_ntoa( addr->sin_addr )));\r
581 \r
582         /* Sanity checks */\r
583         if( namelen != sizeof(struct sockaddr_in) )\r
584         {\r
585                 IBSP_ERROR(\r
586                         ("invalid namelen (%d instead of %d)\n",\r
587                         namelen, sizeof(struct sockaddr_in)) );\r
588                 *lpErrno = WSAEFAULT;\r
589                 goto error;\r
590         }\r
591 \r
592         if( addr->sin_family != AF_INET )\r
593         {\r
594                 IBSP_ERROR( ("bad family for socket\n") );\r
595                 *lpErrno = WSAEFAULT;\r
596                 goto error;\r
597         }\r
598 \r
599         /* Check if the ip address is assigned to one of our IBoIB HCA. */\r
600         if( addr->sin_addr.S_un.S_addr != INADDR_ANY )\r
601         {\r
602                 port = get_port_from_ip_address( addr->sin_addr );\r
603                 if( port == NULL )\r
604                 {\r
605                         IBSP_ERROR(\r
606                                 ("This IP address does not belong to that host (%08x)\n",\r
607                                 addr->sin_addr.S_un.S_addr) );\r
608                         *lpErrno = WSAEADDRNOTAVAIL;\r
609                         goto error;\r
610                 }\r
611         }\r
612         else\r
613         {\r
614                 port = NULL;\r
615         }\r
616 \r
617         /* We are going to take this mutex for some time, \r
618          * but at this stage, it shouldn't impact anything. */\r
619         cl_spinlock_acquire( &socket_info->mutex );\r
620 \r
621         /* Verify the state of the socket */\r
622         if( socket_info->socket_state != IBSP_CREATE )\r
623         {\r
624                 cl_spinlock_release( &socket_info->mutex );\r
625                 IBSP_ERROR(\r
626                         ("Invalid socket state (%s)\n",\r
627                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
628                 *lpErrno = WSAEINVAL;\r
629                 goto error;\r
630         }\r
631 \r
632         if( addr->sin_addr.S_un.S_addr != INADDR_ANY )\r
633         {\r
634                 /* Time to allocate our IB QP */\r
635                 socket_info->port = port;\r
636                 ret = ib_create_socket( socket_info );\r
637                 if( ret )\r
638                 {\r
639                         socket_info->port = NULL;\r
640                         cl_spinlock_release( &socket_info->mutex );\r
641                         IBSP_ERROR( ("ib_create socket failed with %d\n", ret) );\r
642                         *lpErrno = WSAENOBUFS;\r
643                         goto error;\r
644                 }\r
645         }\r
646 \r
647         /* Success */\r
648         socket_info->local_addr = *addr;\r
649 \r
650         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );\r
651 \r
652         cl_spinlock_release( &socket_info->mutex );\r
653 \r
654         IBSP_EXIT( IBSP_DBG_CONN );\r
655         return 0;\r
656 \r
657 error:\r
658         CL_ASSERT( *lpErrno != 0 );\r
659         IBSP_TRACE_EXIT( IBSP_DBG_CONN, ("failed with error %d\n", *lpErrno) );\r
660         return SOCKET_ERROR;\r
661 }\r
662 \r
663 \r
664 /* Function: IBSPCloseSocket\r
665  * \r
666  * Description:\r
667  *   Close the socket handle of the app socket as well as the provider socket.\r
668  *   However, if there are outstanding async IO requests on the app socket\r
669  *   we only close the provider socket. Only when all the IO requests complete\r
670  *   (with error) will we then close the app socket.\r
671  */\r
672 static int WSPAPI\r
673 IBSPCloseSocket(\r
674                                         SOCKET                                          s,\r
675                                         LPINT                                           lpErrno )\r
676 {\r
677         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
678 \r
679         IBSP_ENTER( IBSP_DBG_CONN );\r
680 \r
681         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,\r
682                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
683 \r
684         if( s == INVALID_SOCKET )\r
685         {\r
686                 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );\r
687                 *lpErrno = WSAENOTSOCK;\r
688                 return SOCKET_ERROR;\r
689         }\r
690 #ifdef _DEBUG_\r
691         cl_atomic_inc( &g_ibsp.CloseSocket_count );\r
692 #endif\r
693 \r
694         cl_spinlock_acquire( &g_ibsp.socket_info_mutex );\r
695         cl_qlist_remove_item( &g_ibsp.socket_info_list, &socket_info->item );\r
696         cl_spinlock_release( &g_ibsp.socket_info_mutex );\r
697 \r
698         shutdown_and_destroy_socket_info( socket_info );\r
699 \r
700         IBSP_EXIT( IBSP_DBG_CONN );\r
701 \r
702         *lpErrno = 0;\r
703         return 0;\r
704 }\r
705 \r
706 \r
707 /* Function: IBSPConnect\r
708  *\r
709  *  Description:\r
710  *    Performs a connect call. The only thing we need to do is translate\r
711  *    the socket handle.\r
712  */\r
713 static int WSPAPI\r
714 IBSPConnect(\r
715                                         SOCKET                                          s,\r
716                                         const struct sockaddr FAR       *name,\r
717                                         int                                                     namelen,\r
718                                         LPWSABUF                                        lpCallerData,\r
719                                         LPWSABUF                                        lpCalleeData,\r
720                                         LPQOS                                           lpSQOS,\r
721                                         LPQOS                                           lpGQOS,\r
722                                         LPINT                                           lpErrno )\r
723 {\r
724         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
725         struct sockaddr_in *addr = (struct sockaddr_in *)name;\r
726         int ret;\r
727         ib_net64_t dest_port_guid;\r
728         ib_path_rec_t path_rec;\r
729 \r
730         IBSP_ENTER( IBSP_DBG_CONN );\r
731 \r
732         UNUSED_PARAM( lpCalleeData );\r
733         UNUSED_PARAM( lpSQOS );\r
734         UNUSED_PARAM( lpGQOS );\r
735 \r
736         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,\r
737                          __LINE__, GetCurrentProcessId(),\r
738                          GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));\r
739 \r
740         IBSP_TRACE( IBSP_DBG_CONN,\r
741                 ("lpCallerData=%p, lpCalleeData=%p\n", lpCallerData, lpCalleeData) );\r
742 \r
743         /* Sanity checks */\r
744         if( lpCallerData )\r
745         {\r
746                 /* We don't support that. The current switch does not use it. */\r
747                 IBSP_ERROR_EXIT( ("lpCallerData.len=%d\n", lpCallerData->len) );\r
748                 *lpErrno = WSAEINVAL;\r
749                 return SOCKET_ERROR;\r
750         }\r
751 \r
752         if( namelen < sizeof(struct sockaddr_in) )\r
753         {\r
754                 IBSP_ERROR_EXIT(\r
755                         ("invalid remote address (%d)\n", socket_info->socket_state) );\r
756                 *lpErrno = WSAEFAULT;\r
757                 return SOCKET_ERROR;\r
758         }\r
759 \r
760         /* Check if the name (actually address) of peer entity is correct */\r
761         if( addr->sin_family != AF_INET ||\r
762                 addr->sin_port == 0 || addr->sin_addr.s_addr == INADDR_ANY )\r
763         {\r
764                 IBSP_ERROR_EXIT(\r
765                         ("peer entity address is invalid (%d, %d, %x)\n",\r
766                         addr->sin_family, addr->sin_port, addr->sin_addr.s_addr) );\r
767                 *lpErrno = WSAEADDRNOTAVAIL;\r
768                 return SOCKET_ERROR;\r
769         }\r
770 \r
771         if( socket_info->local_addr.sin_addr.S_un.S_addr == addr->sin_addr.S_un.S_addr )\r
772         {\r
773                 /* Loopback - let the regular stack take care of that. */\r
774                 IBSP_ERROR_EXIT( ("Loopback!\n") );\r
775                 *lpErrno = WSAEADDRNOTAVAIL;\r
776                 return SOCKET_ERROR;\r
777         }\r
778 \r
779         /* Get the GUID for that IP address. */\r
780         ret = query_guid_address( socket_info->port, addr->sin_addr.s_addr, &dest_port_guid );\r
781         if( ret )\r
782         {\r
783                 IBSP_ERROR_EXIT(\r
784                         ("query_guid_address failed for IP %08x\n",\r
785                         addr->sin_addr.s_addr) );\r
786                 *lpErrno = WSAEADDRNOTAVAIL;\r
787                 return SOCKET_ERROR;\r
788         }\r
789 \r
790         IBSP_TRACE( IBSP_DBG_CONN, ("got GUID %I64x for IP %s\n",\r
791                 CL_NTOH64( dest_port_guid ), inet_ntoa( addr->sin_addr )) );\r
792 \r
793         if( dest_port_guid == socket_info->port->guid )\r
794         {\r
795                 IBSP_ERROR_EXIT( ("Loopback!\n") );\r
796                 *lpErrno = WSAEADDRNOTAVAIL;\r
797                 return SOCKET_ERROR;\r
798         }\r
799 \r
800         /* Get the path record */\r
801         ret = query_pr( socket_info->port, dest_port_guid, &path_rec );\r
802         if( ret )\r
803         {\r
804                 IBSP_ERROR_EXIT(\r
805                         ("query_pr failed for IP %08x\n", addr->sin_addr.s_addr) );\r
806                 *lpErrno = WSAEADDRNOTAVAIL;\r
807                 return SOCKET_ERROR;\r
808         }\r
809 \r
810         cl_spinlock_acquire( &socket_info->mutex );\r
811 \r
812         /* Verify the state of the socket */\r
813         switch( socket_info->socket_state )\r
814         {\r
815         case IBSP_BIND:\r
816                 /* Good. That's the only valid state we want. */\r
817                 break;\r
818 \r
819         case IBSP_CONNECTED:\r
820                 IBSP_ERROR( ("Socket is already connected\n") );\r
821                 *lpErrno = WSAEISCONN;\r
822                 goto done;\r
823 \r
824         case IBSP_LISTEN:\r
825                 IBSP_ERROR( ("Socket is a listening socket\n") );\r
826                 *lpErrno = WSAEINVAL;\r
827                 goto done;\r
828 \r
829         default:\r
830                 IBSP_ERROR( ("Socket is not in the bound state (%s)\n",\r
831                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
832                 *lpErrno = WSAEINVAL;\r
833                 goto done;\r
834         }\r
835 \r
836         /* Store the peer entity's address in socket context */\r
837         socket_info->peer_addr = *addr;\r
838 \r
839         /* Update the socket state */\r
840         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECT );\r
841 \r
842         /* Connect */\r
843         *lpErrno = ib_connect( socket_info, &path_rec );\r
844         if( *lpErrno != WSAEWOULDBLOCK )\r
845         {\r
846                 /* We must be sure none destroyed our socket */\r
847                 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );\r
848                 memset( &socket_info->peer_addr, 0, sizeof(struct sockaddr_in) );\r
849 \r
850                 IBSP_ERROR( ("ib_connect failed (%d)\n", *lpErrno) );\r
851         }\r
852 \r
853 done:\r
854         cl_spinlock_release( &socket_info->mutex );\r
855         IBSP_EXIT( IBSP_DBG_CONN );\r
856         return SOCKET_ERROR;\r
857 }\r
858 \r
859 \r
860 /* Function: IBSPDuplicateSocket\r
861 \r
862  Description:\r
863     This function provides a WSAPROTOCOL_INFOW structure which can be passed\r
864     to another process to open a handle to the same socket. First we need\r
865     to translate the user socket into the provider socket and call the underlying\r
866     WSPDuplicateSocket. Note that the lpProtocolInfo structure passed into us\r
867     is an out parameter only!\r
868 */\r
869 static int WSPAPI\r
870 IBSPDuplicateSocket(\r
871                                         SOCKET                                          s,\r
872                                         DWORD                                           dwProcessId,\r
873                                         LPWSAPROTOCOL_INFOW                     lpProtocolInfo,\r
874                                         LPINT                                           lpErrno )\r
875 {\r
876         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
877         int ret;\r
878 \r
879         IBSP_ENTER( IBSP_DBG_CONN );\r
880 \r
881         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,\r
882                          __LINE__, GetCurrentProcessId(),\r
883                          GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));\r
884 \r
885         cl_spinlock_acquire( &socket_info->mutex );\r
886         if( socket_info->socket_state != IBSP_CONNECTED )\r
887         {\r
888                 cl_spinlock_release( &socket_info->mutex );\r
889                 IBSP_TRACE_EXIT( IBSP_DBG_CONN,\r
890                         ("Socket state not IBSP_CONNECTED, state=%s.\n",\r
891                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
892                 *lpErrno = WSAENOTCONN;\r
893                 return SOCKET_ERROR;\r
894         }\r
895 \r
896         ret = prepare_duplicate_socket( socket_info, dwProcessId );\r
897         cl_spinlock_release( &socket_info->mutex );\r
898         if( ret )\r
899         {\r
900                 IBSP_TRACE_EXIT( IBSP_DBG_CONN,\r
901                         ("prepare_duplicate_socket failed with %d\n", ret) );\r
902                 *lpErrno = ret;\r
903                 return SOCKET_ERROR;\r
904         }\r
905         else\r
906         {\r
907                 IBSP_EXIT( IBSP_DBG_CONN );\r
908                 lpProtocolInfo->dwProviderReserved = socket_info->duplicate.identifier;\r
909                 *lpErrno = 0;\r
910                 return 0;\r
911         }\r
912 }\r
913 \r
914 \r
915 /* Function: IBSPEnumNetworkEvents\r
916  * \r
917  *  Description:\r
918  *    Enumerate the network events for a socket. We only need to\r
919  *    translate the socket handle.\r
920 */\r
921 static int WSPAPI\r
922 IBSPEnumNetworkEvents(\r
923                                         SOCKET                                          s,\r
924                                         WSAEVENT                                        hEventObject,\r
925                                         LPWSANETWORKEVENTS                      lpNetworkEvents,\r
926                                         LPINT                                           lpErrno )\r
927 {\r
928         struct ibsp_socket_info         *socket_info = (struct ibsp_socket_info *)s;\r
929 \r
930         IBSP_ENTER( IBSP_DBG_NEV );\r
931 \r
932         ResetEvent( hEventObject );\r
933 \r
934         lpNetworkEvents->lNetworkEvents =\r
935                 InterlockedExchange( &socket_info->network_events, 0 );\r
936 \r
937         if( lpNetworkEvents->lNetworkEvents & FD_ACCEPT )\r
938         {\r
939                 IBSP_TRACE1( IBSP_DBG_NEV,\r
940                         ("socket %p notify FD_ACCEPT at time %I64d\n",\r
941                         socket_info, cl_get_time_stamp()) );\r
942                 lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] = 0;\r
943         }\r
944 \r
945         if( lpNetworkEvents->lNetworkEvents & FD_CONNECT )\r
946         {\r
947                 IBSP_TRACE1( IBSP_DBG_NEV,\r
948                         ("socket %p notify FD_CONNECT %d at time %I64d\n",\r
949                         socket_info, socket_info->errno_connect, cl_get_time_stamp()) );\r
950                 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = socket_info->errno_connect;\r
951         }\r
952 \r
953         *lpErrno = 0;\r
954         IBSP_EXIT( IBSP_DBG_NEV );\r
955         return 0;\r
956 }\r
957 \r
958 \r
959 /* Function: IBSPEventSelect\r
960  *\r
961  *  Description:\r
962  *    Register the specified events on the socket with the given event handle.\r
963  *    All we need to do is translate the socket handle.\r
964  */\r
965 static int WSPAPI\r
966 IBSPEventSelect(\r
967                                         SOCKET                                          s,\r
968                                         WSAEVENT                                        hEventObject,\r
969                                         long                                            lNetworkEvents,\r
970                                         LPINT                                           lpErrno )\r
971 {\r
972         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
973         long                                    events;\r
974 \r
975         IBSP_ENTER( IBSP_DBG_NEV );\r
976 \r
977         IBSP_TRACE4( IBSP_DBG_NEV,\r
978                 ("Socket %p requesting notifiction of %d on event %p.\n",\r
979                 s, lNetworkEvents, hEventObject) );\r
980 \r
981         if( (lNetworkEvents & ~(FD_ACCEPT | FD_CONNECT)) != 0 )\r
982         {\r
983                 IBSP_TRACE_EXIT(IBSP_DBG_NEV,\r
984                         ("Unknown lNetworkEvents flag given (%x)\n", lNetworkEvents) );\r
985                 *lpErrno = WSAEINVAL;\r
986                 return SOCKET_ERROR;\r
987         }\r
988 \r
989         CL_ASSERT( lpErrno );\r
990 \r
991         socket_info->event_mask = lNetworkEvents;\r
992         InterlockedExchangePointer( &socket_info->event_select, hEventObject );\r
993 \r
994         events = InterlockedCompareExchange( &socket_info->network_events, 0, 0 );\r
995         /* Check for existing events and signal as appropriate. */\r
996         if( (socket_info->event_mask & events) && hEventObject )\r
997         {\r
998                 IBSP_TRACE2( IBSP_DBG_NEV,\r
999                         ("Signaling eventHandle %p .\n", socket_info->event_select) );\r
1000                 SetEvent( hEventObject );\r
1001         }\r
1002 \r
1003         IBSP_EXIT( IBSP_DBG_NEV );\r
1004         return 0;\r
1005 }\r
1006 \r
1007 \r
1008 /* Function: IBSPGetOverlappedResult\r
1009  *\r
1010  *  Description:\r
1011  *    This function reports whether the specified overlapped call has\r
1012  *    completed. If it has, return the requested information. If not,\r
1013  *    and fWait is true, wait until completion. Otherwise return an\r
1014  *    error immediately.\r
1015  */\r
1016 static BOOL WSPAPI\r
1017 IBSPGetOverlappedResult(\r
1018         IN                              SOCKET                                          s,\r
1019         IN                              LPWSAOVERLAPPED                         lpOverlapped,\r
1020                 OUT                     LPDWORD                                         lpcbTransfer,\r
1021         IN                              BOOL                                            fWait,\r
1022                 OUT                     LPDWORD                                         lpdwFlags,\r
1023                 OUT                     LPINT                                           lpErrno )\r
1024 {\r
1025         struct ibsp_socket_info *p_socket_info;\r
1026         BOOL                                    rc;\r
1027 \r
1028         IBSP_ENTER( IBSP_DBG_IO );\r
1029 \r
1030         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p Internal=%d InternalHigh=%d OffsetHigh=%d hEvent=%d\n", __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped, lpOverlapped->Internal, lpOverlapped->InternalHigh, lpOverlapped->OffsetHigh, lpOverlapped->hEvent));\r
1031 \r
1032         CL_ASSERT( fWait == FALSE );\r
1033         if( fWait == TRUE )\r
1034         {\r
1035                 IBSP_ERROR_EXIT( ("fWait not supported\n") );\r
1036                 *lpErrno = WSAENETDOWN;\r
1037                 return FALSE;\r
1038         }\r
1039 \r
1040         if( s == INVALID_SOCKET )\r
1041         {\r
1042                 /* Seen in real life with overlap/client test.\r
1043                  * The switch closes a socket then calls this. Why? */\r
1044                 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );\r
1045                 *lpErrno = WSAENOTSOCK;\r
1046                 return SOCKET_ERROR;\r
1047         }\r
1048 \r
1049         if( lpOverlapped->Internal == WSS_OPERATION_IN_PROGRESS )\r
1050         {\r
1051                 p_socket_info = (struct ibsp_socket_info*)s;\r
1052                 /* Poll just in case it's done. */\r
1053                 ib_cq_comp( p_socket_info->cq_tinfo );\r
1054         }\r
1055 \r
1056         if( lpOverlapped->Internal != WSS_OPERATION_IN_PROGRESS )\r
1057         {\r
1058                 /* Operation has completed, perhaps with error */\r
1059                 *lpdwFlags = lpOverlapped->Offset;\r
1060                 *lpErrno = lpOverlapped->OffsetHigh;\r
1061 \r
1062 #ifdef _DEBUG_\r
1063                 if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 )\r
1064                 {\r
1065                         cl_atomic_dec( &g_ibsp.overlap_h1_count );\r
1066 \r
1067                         fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",\r
1068                                          __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),\r
1069                                          lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,\r
1070                                          g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));\r
1071                 }\r
1072 \r
1073                 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p completed overlap=0x%x overlap_h0_count=%d overlap_h1_count=%d\n", __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count));\r
1074 #endif\r
1075                 IBSP_TRACE1( IBSP_DBG_IO,\r
1076                         ("socket=%p completed ov=%p\n", s, lpOverlapped) );\r
1077         }\r
1078         else\r
1079         {\r
1080                 /* Operation is still in progress */\r
1081                 *lpErrno = WSA_IO_INCOMPLETE;\r
1082                 IBSP_TRACE1( IBSP_DBG_IO,\r
1083                         ("socket=%p ov=%p hEvent=%p, operation in progress\n",\r
1084                         s, lpOverlapped, lpOverlapped->hEvent));\r
1085         }\r
1086 \r
1087         *lpcbTransfer = (DWORD)lpOverlapped->InternalHigh;\r
1088 \r
1089         if( *lpErrno == 0 )\r
1090                 rc = TRUE;\r
1091         else\r
1092                 rc = FALSE;\r
1093 \r
1094         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p lpErrno=%d rc=%d\n",\r
1095                          __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,\r
1096                          lpOverlapped, *lpErrno, rc));\r
1097 \r
1098         IBSP_EXIT( IBSP_DBG_IO );\r
1099         return rc;\r
1100 }\r
1101 \r
1102 \r
1103 /* Function: IBSPGetSockOpt\r
1104  *\r
1105  *  Description:\r
1106  *    Get the specified socket option. All we need to do is translate the\r
1107  *    socket handle.\r
1108  */\r
1109 static int WSPAPI\r
1110 IBSPGetSockOpt(\r
1111                                         SOCKET                                          s,\r
1112                                         int                                                     level,\r
1113                                         int                                                     optname,\r
1114                                         char FAR                                        *optval,\r
1115                                         LPINT                                           optlen,\r
1116                                         LPINT                                           lpErrno )\r
1117 {\r
1118         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
1119 \r
1120         IBSP_ENTER( IBSP_DBG_OPT );\r
1121 \r
1122         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,\r
1123                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
1124 \r
1125         if( level != SOL_SOCKET )\r
1126         {\r
1127                 IBSP_ERROR_EXIT( ("invalid level %d", level) );\r
1128                 *lpErrno = WSAENOPROTOOPT;\r
1129                 return SOCKET_ERROR;\r
1130         }\r
1131 \r
1132         if( optval == NULL || optlen == NULL )\r
1133         {\r
1134                 IBSP_ERROR_EXIT(\r
1135                                           ("invalid optval=%p or optlen=%p", optval, optlen) );\r
1136                 *lpErrno = WSAEFAULT;\r
1137                 return SOCKET_ERROR;\r
1138         }\r
1139 \r
1140         switch( optname )\r
1141         {\r
1142         case SO_DEBUG:\r
1143                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );\r
1144                 if( *optlen < sizeof(BOOL) )\r
1145                 {\r
1146                         IBSP_ERROR_EXIT(\r
1147                                 ("option len is invalid (0x%x)\n", *optlen) );\r
1148                         *optlen = sizeof(BOOL);\r
1149                         *lpErrno = WSAEFAULT;\r
1150                         return SOCKET_ERROR;\r
1151                 }\r
1152 \r
1153                 memcpy( optval, &socket_info->socket_options.debug, sizeof(BOOL) );\r
1154                 *optlen = sizeof(BOOL);\r
1155                 break;\r
1156 \r
1157         case SO_GROUP_ID:\r
1158                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_ID\n") );\r
1159                 if( *optlen < sizeof(GROUP) )\r
1160                 {\r
1161                         IBSP_ERROR_EXIT(\r
1162                                 ("option len is invalid (0x%x)\n", *optlen) );\r
1163                         *optlen = sizeof(GROUP);\r
1164                         *lpErrno = WSAEFAULT;\r
1165                         return SOCKET_ERROR;\r
1166                 }\r
1167 \r
1168                 memcpy( optval, &socket_info->socket_options.group_id, sizeof(GROUP) );\r
1169                 *optlen = sizeof(GROUP);\r
1170                 break;\r
1171 \r
1172         case SO_GROUP_PRIORITY:\r
1173                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );\r
1174 \r
1175                 if( *optlen < sizeof(int) )\r
1176                 {\r
1177                         IBSP_ERROR_EXIT(\r
1178                                 ("option len is invalid (0x%x)\n", *optlen) );\r
1179                         *optlen = sizeof(int);\r
1180                         *lpErrno = WSAEFAULT;\r
1181                         return SOCKET_ERROR;\r
1182                 }\r
1183 \r
1184                 memcpy( optval, &socket_info->socket_options.group_priority, sizeof(int) );\r
1185                 *optlen = sizeof(int);\r
1186                 break;\r
1187 \r
1188         case SO_MAX_MSG_SIZE:\r
1189                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_MAX_MSG_SIZE\n") );\r
1190 \r
1191                 if( *optlen < sizeof(unsigned int) )\r
1192                 {\r
1193                         IBSP_ERROR_EXIT(\r
1194                                 ("option len is invalid (0x%x)\n", *optlen) );\r
1195                         *optlen = sizeof(unsigned int);\r
1196                         *lpErrno = WSAEFAULT;\r
1197                         return SOCKET_ERROR;\r
1198                 }\r
1199 \r
1200                 memcpy( optval, &socket_info->socket_options.max_msg_size, sizeof(unsigned int) );\r
1201                 *optlen = sizeof(unsigned int);\r
1202                 break;\r
1203 \r
1204         case SO_MAX_RDMA_SIZE:\r
1205                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_MAX_RDMA_SIZE\n") );\r
1206 \r
1207                 if( *optlen < sizeof(unsigned int) )\r
1208                 {\r
1209                         IBSP_ERROR_EXIT(\r
1210                                 ("option len is invalid (0x%x)\n", *optlen) );\r
1211                         *optlen = sizeof(unsigned int);\r
1212                         *lpErrno = WSAEFAULT;\r
1213                         return SOCKET_ERROR;\r
1214                 }\r
1215 \r
1216                 memcpy( optval, &socket_info->socket_options.max_rdma_size, sizeof(unsigned int) );\r
1217                 *optlen = sizeof(unsigned int);\r
1218                 break;\r
1219 \r
1220         case SO_RDMA_THRESHOLD_SIZE:\r
1221                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_RDMA_THRESHOLD_SIZE\n") );\r
1222 \r
1223                 if( *optlen < sizeof(unsigned int) )\r
1224                 {\r
1225                         IBSP_ERROR_EXIT(\r
1226                                 ("option len is invalid (0x%x)\n", *optlen) );\r
1227                         *optlen = sizeof(unsigned int);\r
1228                         *lpErrno = WSAEFAULT;\r
1229                         return SOCKET_ERROR;\r
1230                 }\r
1231 \r
1232                 memcpy( optval, &socket_info->socket_options.rdma_threshold_size,\r
1233                         sizeof(unsigned int) );\r
1234                 *optlen = sizeof(unsigned int);\r
1235                 break;\r
1236 \r
1237         default:\r
1238                 *lpErrno = WSAENOPROTOOPT;\r
1239 \r
1240                 IBSP_ERROR_EXIT( ("unknown option 0x%x\n", optname) );\r
1241 \r
1242                 return SOCKET_ERROR;\r
1243                 break;\r
1244         }\r
1245 \r
1246         IBSP_EXIT( IBSP_DBG_OPT );\r
1247         return 0;\r
1248 }\r
1249 \r
1250 \r
1251 /* Function: IBSPGetQOSByName\r
1252  *\r
1253  *  Description:\r
1254  *    Get a QOS template by name. All we need to do is translate the socket\r
1255  *    handle.\r
1256  */\r
1257 static BOOL WSPAPI\r
1258 IBSPGetQOSByName(\r
1259                                         SOCKET                                          s,\r
1260                                         LPWSABUF                                        lpQOSName,\r
1261                                         LPQOS                                           lpQOS,\r
1262                                         LPINT                                           lpErrno )\r
1263 {\r
1264         IBSP_ENTER( IBSP_DBG_OPT );\r
1265 \r
1266         UNUSED_PARAM( s );\r
1267         UNUSED_PARAM( lpQOSName );\r
1268         UNUSED_PARAM( lpQOS );\r
1269 \r
1270         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,\r
1271                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
1272 \r
1273         *lpErrno = WSAEOPNOTSUPP;\r
1274 \r
1275         IBSP_ERROR_EXIT( ("not supported\n") );\r
1276 \r
1277         return FALSE;\r
1278 }\r
1279 \r
1280 \r
1281 /* Function: IBSPIoctl\r
1282  *\r
1283  * Description:\r
1284  *   Invoke an ioctl. In most cases, we just need to translate the socket\r
1285  *   handle. However, if the dwIoControlCode is SIO_GET_EXTENSION_FUNCTION_POINTER,\r
1286  *   we'll need to intercept this and return our own function pointers.\r
1287  */\r
1288 static int WSPAPI\r
1289 IBSPIoctl(\r
1290         IN                              SOCKET                                          s,\r
1291         IN                              DWORD                                           dwIoControlCode,\r
1292         IN                              LPVOID                                          lpvInBuffer,\r
1293         IN                              DWORD                                           cbInBuffer,\r
1294                 OUT                     LPVOID                                          lpvOutBuffer,\r
1295         IN                              DWORD                                           cbOutBuffer,\r
1296                 OUT                     LPDWORD                                         lpcbBytesReturned,\r
1297         IN                              LPWSAOVERLAPPED                         lpOverlapped,\r
1298         IN                              LPWSAOVERLAPPED_COMPLETION_ROUTINE      lpCompletionRoutine,\r
1299         IN                              LPWSATHREADID                           lpThreadId,\r
1300                 OUT                     LPINT                                           lpErrno )\r
1301 {\r
1302         struct ibsp_socket_info *socket_info;\r
1303         GUID SANRegisterMemory = WSAID_REGISTERMEMORY;\r
1304         GUID SANDeregisterMemory = WSAID_DEREGISTERMEMORY;\r
1305         GUID SANRegisterRDMAMemory = WSAID_REGISTERRDMAMEMORY;\r
1306         GUID SANDeregisterRDMAMemory = WSAID_DEREGISTERRDMAMEMORY;\r
1307         GUID SANRDMAWrite = WSAID_RDMAWRITE;\r
1308         GUID SANRDMARead = WSAID_RDMAREAD;\r
1309         GUID SANMemoryRegistrationCacheCallback = WSAID_MEMORYREGISTRATIONCACHECALLBACK;\r
1310 \r
1311         IBSP_ENTER( IBSP_DBG_OPT );\r
1312 \r
1313         UNUSED_PARAM( cbInBuffer );\r
1314         UNUSED_PARAM( lpOverlapped );\r
1315         UNUSED_PARAM( lpCompletionRoutine );\r
1316         UNUSED_PARAM( lpThreadId );\r
1317 \r
1318         if( dwIoControlCode == SIO_GET_EXTENSION_FUNCTION_POINTER )\r
1319         {\r
1320                 /* This a special case. The socket handle passed is not valid. */\r
1321                 IBSP_TRACE1( IBSP_DBG_OPT, ("Get extension function pointer\n") );\r
1322 \r
1323                 if( memcmp( lpvInBuffer, &SANRegisterMemory, sizeof(GUID) ) == 0 )\r
1324                 {\r
1325                         /* Return a pointer to our intermediate extension function */\r
1326                         *((LPFN_WSPREGISTERMEMORY *) lpvOutBuffer) = IBSPRegisterMemory;\r
1327                 }\r
1328                 else if( memcmp( lpvInBuffer, &SANDeregisterMemory, sizeof(GUID) ) == 0 )\r
1329                 {\r
1330                         /* Return a pointer to our intermediate extension function */\r
1331                         *((LPFN_WSPDEREGISTERMEMORY *) lpvOutBuffer) = IBSPDeregisterMemory;\r
1332                 }\r
1333                 else if( memcmp( lpvInBuffer, &SANRegisterRDMAMemory, sizeof(GUID) ) == 0 )\r
1334                 {\r
1335                         /* Return a pointer to our intermediate extension function */\r
1336                         *((LPFN_WSPREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPRegisterRdmaMemory;\r
1337                 }\r
1338                 else if( memcmp( lpvInBuffer, &SANDeregisterRDMAMemory, sizeof(GUID) ) == 0 )\r
1339                 {\r
1340                         /* Return a pointer to our intermediate extension function */\r
1341                         *((LPFN_WSPDEREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPDeregisterRdmaMemory;\r
1342                 }\r
1343                 else if( memcmp( lpvInBuffer, &SANRDMAWrite, sizeof(GUID) ) == 0 )\r
1344                 {\r
1345                         /* Return a pointer to our intermediate extension function */\r
1346                         *((LPFN_WSPRDMAWRITE *) lpvOutBuffer ) = IBSPRdmaWrite;\r
1347                 }\r
1348                 else if( memcmp( lpvInBuffer, &SANRDMARead, sizeof(GUID) ) == 0 )\r
1349                 {\r
1350                         if( no_read )\r
1351                         {\r
1352                                 IBSP_TRACE( IBSP_DBG_WARN | IBSP_DBG_OPT,\r
1353                                         ("RDMA_READ disabled.\n") );\r
1354                                 *lpErrno = WSAEOPNOTSUPP;\r
1355                                 return SOCKET_ERROR;\r
1356                         }\r
1357                         else\r
1358                         {\r
1359                                 /* Return a pointer to our intermediate extension function */\r
1360                                 *((LPFN_WSPRDMAREAD *) lpvOutBuffer ) = IBSPRdmaRead;\r
1361                         }\r
1362                 }\r
1363                 else if( memcmp( lpvInBuffer, &SANMemoryRegistrationCacheCallback,\r
1364                                                   sizeof(GUID) ) == 0 )\r
1365                 {\r
1366                         /* Return a pointer to our intermediate extension function */\r
1367                         *((LPFN_WSPMEMORYREGISTRATIONCACHECALLBACK *) lpvOutBuffer ) =\r
1368                                 IBSPMemoryRegistrationCacheCallback;\r
1369                 }\r
1370                 else\r
1371                 {\r
1372                         IBSP_ERROR_EXIT( ("invalid extension GUID\n") );\r
1373                         *lpErrno = WSAEINVAL;\r
1374                         return SOCKET_ERROR;\r
1375                 }\r
1376                 IBSP_EXIT( IBSP_DBG_OPT );\r
1377                 return 0;\r
1378         }\r
1379 \r
1380         socket_info = (struct ibsp_socket_info *)s;\r
1381 \r
1382         /* Verify the state of the socket */\r
1383         /* Not sure which state socket should be in to receive this call */\r
1384         DebugPrintIBSPIoctlParams( IBSP_DBG_OPT, gdbg_lvl,\r
1385                                                           dwIoControlCode,\r
1386                                                           lpvInBuffer,\r
1387                                                           cbInBuffer,\r
1388                                                           lpvOutBuffer,\r
1389                                                           cbOutBuffer, lpOverlapped, lpCompletionRoutine, lpThreadId );\r
1390 \r
1391         switch( dwIoControlCode )\r
1392         {\r
1393         case SIO_GET_QOS:\r
1394         case SIO_GET_GROUP_QOS:\r
1395         case SIO_SET_QOS:\r
1396         case SIO_SET_GROUP_QOS:\r
1397                 /* We don't support that. dwServiceFlags1 in installSP \r
1398                  * wasn't set. */\r
1399                 IBSP_ERROR_EXIT(\r
1400                         ("unsupported dwIoControlCode %d\n", dwIoControlCode) );\r
1401                 *lpErrno = WSAENOPROTOOPT;\r
1402                 return SOCKET_ERROR;\r
1403                 break;\r
1404 \r
1405         case SIO_ADDRESS_LIST_QUERY:\r
1406                 {\r
1407                         int ret;\r
1408 \r
1409                         *lpcbBytesReturned = cbOutBuffer;\r
1410                         ret = build_ip_list( (LPSOCKET_ADDRESS_LIST)lpvOutBuffer,\r
1411                                                                 lpcbBytesReturned, lpErrno );\r
1412 \r
1413                         IBSP_EXIT( IBSP_DBG_OPT );\r
1414                         return ret;\r
1415                 }\r
1416                 break;\r
1417 \r
1418         default:\r
1419                 IBSP_ERROR_EXIT(\r
1420                         ("invalid dwIoControlCode %d\n", dwIoControlCode) );\r
1421 \r
1422                 *lpErrno = WSAENOPROTOOPT;\r
1423                 return SOCKET_ERROR;\r
1424                 break;\r
1425         }\r
1426 \r
1427         /* unreachable */\r
1428 }\r
1429 \r
1430 \r
1431 /* Function: IBSPListen\r
1432  * \r
1433  * Description:\r
1434  *   This function establishes a socket to listen for incoming connections. It sets\r
1435  *   the backlog value on a listening socket.\r
1436  */\r
1437 static int WSPAPI\r
1438 IBSPListen(\r
1439                                         SOCKET                                          s,\r
1440                                         int                                                     backlog,\r
1441                                         LPINT                                           lpErrno )\r
1442 {\r
1443         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
1444         int ret;\r
1445 \r
1446         IBSP_ENTER( IBSP_DBG_CONN );\r
1447 \r
1448         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,\r
1449                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
1450 \r
1451         cl_spinlock_acquire( &socket_info->mutex );\r
1452 \r
1453         IBSP_TRACE( IBSP_DBG_CONN, ("socket_state is %s\n",\r
1454                 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
1455 \r
1456         /* Verify the state of the socket */\r
1457         switch( socket_info->socket_state )\r
1458         {\r
1459         case IBSP_BIND:\r
1460 \r
1461                 /* Store the backlog value in the context */\r
1462                 socket_info->listen.backlog = backlog;\r
1463                 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_LISTEN );\r
1464 \r
1465                 socket_info->listen.listen_req_param.dwProcessId = 0;\r
1466                 socket_info->listen.listen_req_param.identifier = 0;\r
1467 \r
1468                 ret = ib_listen( socket_info );\r
1469                 if( ret )\r
1470                 {\r
1471                         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );\r
1472                         IBSP_ERROR_EXIT( ("ib_listen failed with %d\n", ret) );\r
1473                 }\r
1474                 break;\r
1475 \r
1476         case IBSP_LISTEN:\r
1477                 /* Change the backlog */\r
1478                 ib_listen_backlog( socket_info, backlog );\r
1479                 ret = 0;\r
1480                 break;\r
1481 \r
1482         default:\r
1483                 IBSP_ERROR(\r
1484                         ("Invalid socket_state (%s)\n",\r
1485                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
1486                 ret = WSAEINVAL;\r
1487                 break;\r
1488         }\r
1489 \r
1490         cl_spinlock_release( &socket_info->mutex );\r
1491 \r
1492         *lpErrno = ret;\r
1493 \r
1494         IBSP_EXIT( IBSP_DBG_CONN );\r
1495         if( ret )\r
1496                 return SOCKET_ERROR;\r
1497         else\r
1498                 return 0;\r
1499 }\r
1500 \r
1501 \r
1502 /* Function: IBSPRecv\r
1503  * \r
1504  * Description:\r
1505  *   This function receives data on a given socket and also allows for asynchronous\r
1506  *   (overlapped) operation. First translate the socket handle to the lower provider\r
1507  *   handle and then make the receive call. If called with overlap, post the operation\r
1508  *   to our IOCP or completion routine.\r
1509 */\r
1510 static int WSPAPI\r
1511 IBSPRecv(\r
1512                                         SOCKET                                          s,\r
1513                                         LPWSABUF                                        lpBuffers,\r
1514                                         DWORD                                           dwBufferCount,\r
1515                                         LPDWORD                                         lpNumberOfBytesRecvd,\r
1516                                         LPDWORD                                         lpFlags,\r
1517                                         LPWSAOVERLAPPED                         lpOverlapped,\r
1518                                         LPWSAOVERLAPPED_COMPLETION_ROUTINE      lpCompletionRoutine,\r
1519                                         LPWSATHREADID                           lpThreadId,\r
1520                                         LPINT                                           lpErrno )\r
1521 {\r
1522         struct ibsp_socket_info         *socket_info = (struct ibsp_socket_info *)s;\r
1523         ib_api_status_t                         status;\r
1524         struct memory_node                      *node;\r
1525         struct _recv_wr                         *wr;\r
1526         DWORD                                           ds_idx;\r
1527 \r
1528         IBSP_ENTER( IBSP_DBG_IO );\r
1529 \r
1530         UNUSED_PARAM( lpNumberOfBytesRecvd );\r
1531         UNUSED_PARAM( lpCompletionRoutine );\r
1532         UNUSED_PARAM( lpThreadId );\r
1533 \r
1534         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,\r
1535                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
1536 \r
1537         CL_ASSERT( lpCompletionRoutine == NULL );\r
1538         CL_ASSERT( lpOverlapped != NULL );\r
1539 \r
1540         if( s == INVALID_SOCKET )\r
1541         {\r
1542                 /* Seen in real life with overlap/client test. \r
1543                  * The switch closes a socket then calls this. Why? */\r
1544                 IBSP_TRACE_EXIT( IBSP_DBG_WARN | IBSP_DBG_IO,\r
1545                         ("invalid socket handle %x\n", s) );\r
1546                 *lpErrno = WSAENOTSOCK;\r
1547                 return SOCKET_ERROR;\r
1548         }\r
1549 \r
1550         cl_spinlock_acquire( &socket_info->mutex );\r
1551         switch( socket_info->socket_state )\r
1552         {\r
1553         case IBSP_CONNECTED:\r
1554         case IBSP_DISCONNECTED:\r
1555                 break;\r
1556 \r
1557         default:\r
1558                 cl_spinlock_release( &socket_info->mutex );\r
1559                 IBSP_ERROR_EXIT(\r
1560                         ("Socket is not in connected socket_state state=%s\n",\r
1561                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
1562                 *lpErrno = WSAENOTCONN;\r
1563                 return SOCKET_ERROR;\r
1564         }\r
1565         cl_spinlock_release( &socket_info->mutex );\r
1566 \r
1567         if( socket_info->qp_error != 0 )\r
1568         {\r
1569                 IBSP_ERROR_EXIT(\r
1570                         ("QP is in error state %d\n", socket_info->qp_error) );\r
1571                 *lpErrno = socket_info->qp_error;\r
1572                 return SOCKET_ERROR;\r
1573         }\r
1574 \r
1575         /* This function only works for that case. Right now the switch is\r
1576          * only using that. */\r
1577         if( dwBufferCount > QP_ATTRIB_RQ_SGE )\r
1578         {\r
1579                 CL_ASSERT( dwBufferCount <= QP_ATTRIB_RQ_SGE );\r
1580                 IBSP_ERROR_EXIT(\r
1581                         ("dwBufferCount is greater than %d\n", QP_ATTRIB_RQ_SGE) );\r
1582                 *lpErrno = WSAEINVAL;\r
1583                 return SOCKET_ERROR;\r
1584         }\r
1585 \r
1586         cl_spinlock_acquire( &socket_info->recv_lock );\r
1587         if( socket_info->recv_cnt == QP_ATTRIB_RQ_DEPTH )\r
1588         {\r
1589                 /* This should never happen */\r
1590                 cl_spinlock_release( &socket_info->recv_lock );\r
1591                 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );\r
1592                 *lpErrno = WSAENETDOWN;\r
1593                 return SOCKET_ERROR;\r
1594         }\r
1595 \r
1596         wr = &socket_info->recv_wr[socket_info->recv_idx];\r
1597 \r
1598         wr->wr.lpOverlapped = lpOverlapped;\r
1599         wr->wr.socket_info = socket_info;\r
1600 \r
1601         /* Looks good. Post the receive buffer. */\r
1602         wr->recv.p_next = NULL;\r
1603         wr->recv.wr_id = (uint64_t)(void* __ptr64)wr;\r
1604         wr->recv.num_ds = dwBufferCount;\r
1605         wr->recv.ds_array = wr->ds_array;\r
1606 \r
1607         for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )\r
1608         {\r
1609                 /* Get the memory region node */\r
1610                 node = lookup_partial_mr( &socket_info->buf_mem_list, IB_AC_LOCAL_WRITE,\r
1611                         lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );\r
1612                 if( !node )\r
1613                 {\r
1614                         cl_spinlock_release( &socket_info->recv_lock );\r
1615                         /*\r
1616                          * No mr fits. This should never happen. This error is not \r
1617                          * official, but seems to be the closest.\r
1618                          */\r
1619                         IBSP_ERROR_EXIT( ("no MR found\n") );\r
1620                         *lpErrno = WSAEFAULT;\r
1621                         return SOCKET_ERROR;\r
1622                 }\r
1623 \r
1624                 wr->ds_array[ds_idx].vaddr =\r
1625                         (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;\r
1626                 wr->ds_array[ds_idx].length = lpBuffers[ds_idx].len;\r
1627                 wr->ds_array[ds_idx].lkey = node->lkey;\r
1628         }\r
1629 \r
1630         /*\r
1631          * We must set this now, because the operation could complete\r
1632          * before ib_post_Recv returns.\r
1633          */\r
1634         lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;\r
1635 \r
1636         /* Store the flags for reporting back in IBSPGetOverlappedResult */\r
1637         lpOverlapped->Offset = *lpFlags;\r
1638 \r
1639         cl_atomic_inc( &socket_info->recv_cnt );\r
1640 \r
1641 #ifdef _DEBUG_\r
1642         if( lpOverlapped->hEvent == 0 )\r
1643         {\r
1644                 cl_atomic_inc( &g_ibsp.overlap_h0_count );\r
1645         }\r
1646         else\r
1647         {\r
1648                 cl_atomic_inc( &g_ibsp.overlap_h1_count );\r
1649                 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );\r
1650         }\r
1651 \r
1652         cl_atomic_inc( &g_ibsp.recv_count );\r
1653 \r
1654         fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",\r
1655                          __FUNCTION__, __LINE__, GetCurrentProcessId(),\r
1656                          GetCurrentThreadId(), lpOverlapped,\r
1657                          g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,\r
1658                          g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));\r
1659 \r
1660 \r
1661 #endif\r
1662 \r
1663 \r
1664         fzprint(("%s():%d:0x%x:0x%x: posting RECV socket=0x%p overlap=%p wr=0x%p\n",\r
1665                          __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,\r
1666                          lpOverlapped, wr));\r
1667 \r
1668         status = ib_post_recv( socket_info->qp, &wr->recv, NULL );\r
1669 \r
1670         if( status == IB_SUCCESS )\r
1671         {\r
1672                 /* Update the index and wrap as needed */\r
1673 #if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \\r
1674         QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \\r
1675         QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8\r
1676                 socket_info->recv_idx++;\r
1677                 socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1);\r
1678 #else\r
1679                 if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH )\r
1680                         socket_info->recv_idx = 0;\r
1681 #endif\r
1682 \r
1683                 IBSP_TRACE1( IBSP_DBG_IO,\r
1684                         ("Posted RECV: socket=%p, ov=%p, addr=%p, len=%d\n",\r
1685                         s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );\r
1686 \r
1687                 *lpErrno = WSA_IO_PENDING;\r
1688         }\r
1689         else\r
1690         {\r
1691                 IBSP_ERROR(\r
1692                         ("ib_post_recv returned %s\n", ib_get_err_str( status )) );\r
1693 #ifdef _DEBUG_\r
1694                 if( lpOverlapped->hEvent == 0 )\r
1695                 {\r
1696                         cl_atomic_dec( &g_ibsp.overlap_h0_count );\r
1697                 }\r
1698                 else\r
1699                 {\r
1700                         cl_atomic_dec( &g_ibsp.overlap_h1_count );\r
1701                         cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );\r
1702                 }\r
1703 \r
1704                 cl_atomic_dec( &g_ibsp.recv_count );\r
1705 \r
1706                 memset( wr, 0x33, sizeof(struct _recv_wr) );\r
1707 #endif\r
1708 \r
1709                 cl_atomic_dec( &socket_info->recv_cnt );\r
1710                 *lpErrno = ibal_to_wsa_error( status );\r
1711         }\r
1712 \r
1713         cl_spinlock_release( &socket_info->recv_lock );\r
1714 \r
1715         /* We never complete the operation here. */\r
1716         IBSP_EXIT( IBSP_DBG_IO );\r
1717         return SOCKET_ERROR;\r
1718 }\r
1719 \r
1720 \r
1721 /* Function: IBSPSend\r
1722  *\r
1723  *  Description:\r
1724  *    This function sends data on a given socket and also allows for asynchronous\r
1725  *    (overlapped) operation. First translate the socket handle to the lower provider\r
1726  *    handle and then make the send call.\r
1727 */\r
1728 static int WSPAPI\r
1729 IBSPSend(\r
1730         IN                              SOCKET                                          s,\r
1731         IN                              LPWSABUF                                        lpBuffers,\r
1732         IN                              DWORD                                           dwBufferCount,\r
1733                 OUT                     LPDWORD                                         lpNumberOfBytesSent,\r
1734         IN                              DWORD                                           dwFlags,\r
1735         IN                              LPWSAOVERLAPPED                         lpOverlapped,\r
1736         IN                              LPWSAOVERLAPPED_COMPLETION_ROUTINE      lpCompletionRoutine,\r
1737         IN                              LPWSATHREADID                           lpThreadId,\r
1738                 OUT                     LPINT                                           lpErrno )\r
1739 {\r
1740         struct ibsp_socket_info         *socket_info = (struct ibsp_socket_info *)s;\r
1741         ib_api_status_t                         status;\r
1742         struct memory_node                      *node;\r
1743         struct _wr                                      *wr;\r
1744         ib_send_wr_t                            send_wr;\r
1745         ib_local_ds_t                           local_ds[QP_ATTRIB_SQ_SGE];\r
1746         DWORD                                           ds_idx;\r
1747 \r
1748         IBSP_ENTER( IBSP_DBG_IO );\r
1749 \r
1750         UNUSED_PARAM( lpNumberOfBytesSent );\r
1751         UNUSED_PARAM( lpCompletionRoutine );\r
1752         UNUSED_PARAM( lpThreadId );\r
1753 \r
1754         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlap=%p\n", __FUNCTION__,\r
1755                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped));\r
1756 \r
1757         if( s == INVALID_SOCKET )\r
1758         {\r
1759                 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );\r
1760                 *lpErrno = WSAENOTSOCK;\r
1761                 return SOCKET_ERROR;\r
1762         }\r
1763 \r
1764         CL_ASSERT( lpCompletionRoutine == NULL );\r
1765         CL_ASSERT( lpOverlapped != NULL );\r
1766 \r
1767         cl_spinlock_acquire( &socket_info->mutex );\r
1768         switch( socket_info->socket_state )\r
1769         {\r
1770         case IBSP_CONNECTED:\r
1771         case IBSP_DISCONNECTED:\r
1772                 break;\r
1773 \r
1774         default:\r
1775                 cl_spinlock_release( &socket_info->mutex );\r
1776                 IBSP_ERROR_EXIT(\r
1777                         ("Socket is not in connected socket_state state=%s\n",\r
1778                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
1779                 *lpErrno = WSAENOTCONN;\r
1780                 return SOCKET_ERROR;\r
1781         }\r
1782         cl_spinlock_release( &socket_info->mutex );\r
1783 \r
1784         if( socket_info->qp_error )\r
1785         {\r
1786                 IBSP_ERROR_EXIT(\r
1787                         ("QP is in error state %d\n", socket_info->qp_error) );\r
1788                 *lpErrno = socket_info->qp_error;\r
1789                 return SOCKET_ERROR;\r
1790         }\r
1791 \r
1792         /* This function only works for that case. */\r
1793         if( dwBufferCount > QP_ATTRIB_SQ_SGE )\r
1794         {\r
1795                 CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE );\r
1796                 IBSP_ERROR_EXIT(\r
1797                         ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) );\r
1798                 *lpErrno = WSAEINVAL;\r
1799                 return SOCKET_ERROR;\r
1800         }\r
1801 \r
1802         /* The send lock is only used to serialize posting. */\r
1803         cl_spinlock_acquire( &socket_info->send_lock );\r
1804         if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH )\r
1805         {\r
1806                 /* This should never happen */\r
1807                 cl_spinlock_release( &socket_info->send_lock );\r
1808                 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );\r
1809                 *lpErrno = WSAENETDOWN;\r
1810                 return SOCKET_ERROR;\r
1811         }\r
1812 \r
1813         wr = &socket_info->send_wr[socket_info->send_idx];\r
1814 \r
1815         wr->lpOverlapped = lpOverlapped;\r
1816         wr->socket_info = socket_info;\r
1817 \r
1818         /* Looks good. Post the send buffer. */\r
1819         send_wr.p_next = NULL;\r
1820         send_wr.wr_id = (uint64_t) (uintptr_t) wr;\r
1821         send_wr.wr_type = WR_SEND;\r
1822         send_wr.send_opt = socket_info->send_opt;\r
1823         socket_info->send_opt = 0;\r
1824 \r
1825         send_wr.num_ds = dwBufferCount;\r
1826         send_wr.ds_array = local_ds;\r
1827 \r
1828         lpOverlapped->InternalHigh = 0;\r
1829         for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )\r
1830         {\r
1831                 local_ds[ds_idx].vaddr = (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;\r
1832                 local_ds[ds_idx].length = lpBuffers[ds_idx].len;\r
1833 \r
1834                 lpOverlapped->InternalHigh += lpBuffers[ds_idx].len;\r
1835         }\r
1836 \r
1837         if( lpOverlapped->InternalHigh <= socket_info->max_inline )\r
1838         {\r
1839                 send_wr.send_opt |= IB_SEND_OPT_INLINE;\r
1840         }\r
1841         else\r
1842         {\r
1843                 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )\r
1844                 {\r
1845                         /* Get the memory region node */\r
1846                         node = lookup_partial_mr( &socket_info->buf_mem_list, 0,        /* READ */\r
1847                                 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );\r
1848                         if( !node )\r
1849                         {\r
1850                                 cl_spinlock_release( &socket_info->send_lock );\r
1851                                 /*\r
1852                                  * No mr fits. This error is not official, but seems to be the\r
1853                                  * closest.\r
1854                                  */\r
1855                                 IBSP_ERROR_EXIT( ("mr lookup failed\n") );\r
1856                                 *lpErrno = WSAEFAULT;\r
1857                                 return SOCKET_ERROR;\r
1858                         }\r
1859 \r
1860                         local_ds[ds_idx].lkey = node->lkey;\r
1861                 }\r
1862         }\r
1863 \r
1864         /*\r
1865          * We must set this now, because the operation could complete\r
1866          * before ib_post_send returns.\r
1867          */\r
1868         lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;\r
1869 \r
1870         /* Store the flags for reporting back in IBSPGetOverlappedResult */\r
1871         lpOverlapped->Offset = dwFlags;\r
1872 \r
1873         cl_atomic_inc( &socket_info->send_cnt );\r
1874 \r
1875 #ifdef _DEBUG_\r
1876         if( lpOverlapped->hEvent == 0)\r
1877         {\r
1878                 cl_atomic_inc( &g_ibsp.overlap_h0_count );\r
1879         }\r
1880         else\r
1881         {\r
1882                 cl_atomic_inc( &g_ibsp.overlap_h1_count );\r
1883                 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );\r
1884         }\r
1885 \r
1886         cl_atomic_inc( &g_ibsp.send_count );\r
1887 \r
1888         fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",\r
1889                          __FUNCTION__, __LINE__, GetCurrentProcessId(),\r
1890                          GetCurrentThreadId(), lpOverlapped,\r
1891                          g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,\r
1892                          g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));\r
1893 \r
1894 \r
1895 #endif\r
1896 \r
1897 \r
1898         fzprint(("%s():%d:0x%x:0x%x: posting SEND %p, mr handle=%p, addr=%p, len=%d\n",\r
1899                          __FUNCTION__,\r
1900                          __LINE__, GetCurrentProcessId(),\r
1901                          GetCurrentThreadId(),\r
1902                          lpOverlapped, node, lpBuffers[0].buf, lpBuffers[0].len));\r
1903 \r
1904 #ifdef _DEBUG_\r
1905         if( lpBuffers[0].len >= 40 )\r
1906         {\r
1907                 debug_dump_buffer( IBSP_DBG_WQ | IBSP_DBG_LEVEL4, "SEND",\r
1908                         lpBuffers[0].buf, 40 );\r
1909         }\r
1910 #endif\r
1911 \r
1912         status = ib_post_send( socket_info->qp, &send_wr, NULL );\r
1913 \r
1914         if( status == IB_SUCCESS )\r
1915         {\r
1916                 /* Update the index and wrap as needed */\r
1917 #if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \\r
1918         QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \\r
1919         QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8\r
1920                 socket_info->send_idx++;\r
1921                 socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1);\r
1922 #else\r
1923                 if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH )\r
1924                         socket_info->send_idx = 0;\r
1925 #endif\r
1926 \r
1927 \r
1928                 IBSP_TRACE1( IBSP_DBG_IO,\r
1929                         ("Posted SEND: socket=%p, ov=%p, addr=%p, len=%d\n",\r
1930                         s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );\r
1931 \r
1932                 *lpErrno = WSA_IO_PENDING;\r
1933         }\r
1934         else\r
1935         {\r
1936                 IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) );\r
1937 \r
1938 #ifdef _DEBUG_\r
1939                 if( lpOverlapped->hEvent == 0 )\r
1940                 {\r
1941                         cl_atomic_dec( &g_ibsp.overlap_h0_count );\r
1942                 }\r
1943                 else\r
1944                 {\r
1945                         cl_atomic_dec( &g_ibsp.overlap_h1_count );\r
1946                         cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );\r
1947                 }\r
1948                 cl_atomic_dec( &g_ibsp.send_count );\r
1949 \r
1950                 memset( wr, 0x37, sizeof(struct _wr) );\r
1951 #endif\r
1952                 cl_atomic_dec( &socket_info->send_cnt );\r
1953 \r
1954                 *lpErrno = ibal_to_wsa_error( status );\r
1955         }\r
1956         cl_spinlock_release( &socket_info->send_lock );\r
1957 \r
1958         /* We never complete the operation here. */\r
1959         IBSP_EXIT( IBSP_DBG_IO );\r
1960         return SOCKET_ERROR;\r
1961 }\r
1962 \r
1963 \r
1964 /* Function: IBSPSetSockOpt\r
1965  * \r
1966  *  Description:\r
1967  *    Set a socket option. For most all options we just have to translate the\r
1968  *    socket option and call the lower provider. The only special case is for\r
1969  *    SO_UPDATE_ACCEPT_CONTEXT in which case a socket handle is passed as the\r
1970  *    argument which we need to translate before calling the lower provider.\r
1971  */\r
1972 static int WSPAPI\r
1973 IBSPSetSockOpt(\r
1974                                         SOCKET                                          s,\r
1975                                         int                                                     level,\r
1976                                         int                                                     optname,\r
1977                                         const char FAR                          *optval,\r
1978                                         int                                                     optlen,\r
1979                                         LPINT                                           lpErrno )\r
1980 {\r
1981         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
1982 \r
1983         IBSP_ENTER( IBSP_DBG_OPT );\r
1984 \r
1985         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,\r
1986                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
1987 \r
1988         if( level != SOL_SOCKET )\r
1989         {\r
1990                 IBSP_ERROR_EXIT( ("invalid level %d", level) );\r
1991                 *lpErrno = WSAENOPROTOOPT;\r
1992                 return SOCKET_ERROR;\r
1993         }\r
1994 \r
1995         if( optval == NULL )\r
1996         {\r
1997                 IBSP_ERROR_EXIT( ("invalid optval=%p", optval) );\r
1998                 *lpErrno = WSAEFAULT;\r
1999                 return SOCKET_ERROR;\r
2000         }\r
2001 \r
2002         switch( optname )\r
2003         {\r
2004         case SO_DEBUG:\r
2005                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );\r
2006                 if( optlen != sizeof(BOOL) )\r
2007                 {\r
2008                         IBSP_ERROR_EXIT(\r
2009                                 ("option len is invalid (0x%x)\n", optlen) );\r
2010                         *lpErrno = WSAEFAULT;\r
2011                         return SOCKET_ERROR;\r
2012                 }\r
2013                 memcpy( &socket_info->socket_options.debug, optval, sizeof(BOOL) );\r
2014                 break;\r
2015 \r
2016         case SO_GROUP_PRIORITY:\r
2017                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );\r
2018                 if( optlen != sizeof(int) )\r
2019                 {\r
2020                         IBSP_ERROR_EXIT(\r
2021                                 ("option len is invalid (0x%x)\n", optlen) );\r
2022                         *lpErrno = WSAEFAULT;\r
2023                         return SOCKET_ERROR;\r
2024                 }\r
2025                 memcpy( &socket_info->socket_options.group_priority, optval, sizeof(int) );\r
2026                 break;\r
2027 \r
2028         default:\r
2029                 IBSP_ERROR_EXIT( ("invalid option %x\n", optname) );\r
2030                 *lpErrno = WSAENOPROTOOPT;\r
2031                 return SOCKET_ERROR;\r
2032                 break;\r
2033         }\r
2034 \r
2035         IBSP_EXIT( IBSP_DBG_OPT );\r
2036 \r
2037         return 0;\r
2038 }\r
2039 \r
2040 \r
2041 /* Function: IBSPSocket\r
2042  *\r
2043  *  Description:\r
2044  *    This function creates a socket. There are two sockets created. The first\r
2045  *    socket is created by calling the lower providers WSPSocket. This is the\r
2046  *    handle that we use internally within our LSP. We then create a second\r
2047  *    socket with WPUCreateSocketHandle which will be returned to the calling\r
2048  *    application. We will also create a socket context structure which will\r
2049  *    maintain information on each socket. This context is associated with the\r
2050  *    socket handle passed to the application.\r
2051 */\r
2052 static SOCKET WSPAPI\r
2053 IBSPSocket(\r
2054                                         int                                                     af,\r
2055                                         int                                                     type,\r
2056                                         int                                                     protocol,\r
2057                                         LPWSAPROTOCOL_INFOW                     lpProtocolInfo,\r
2058                                         GROUP                                           g,\r
2059                                         DWORD                                           dwFlags,\r
2060                                         LPINT                                           lpErrno )\r
2061 {\r
2062         struct ibsp_socket_info *socket_info = NULL;\r
2063 \r
2064         IBSP_ENTER( IBSP_DBG_SI );\r
2065 \r
2066         UNUSED_PARAM( g );\r
2067 \r
2068         if( af != AF_INET )\r
2069         {\r
2070                 IBSP_ERROR_EXIT(\r
2071                         ("bad family %d instead of %d\n", af, AF_INET) );\r
2072                 *lpErrno = WSAEAFNOSUPPORT;\r
2073                 return INVALID_SOCKET;\r
2074         }\r
2075 \r
2076         if( type != SOCK_STREAM )\r
2077         {\r
2078                 IBSP_ERROR_EXIT(\r
2079                         ("bad type %d instead of %d\n", type, SOCK_STREAM) );\r
2080                 *lpErrno = WSAEPROTOTYPE;\r
2081                 return INVALID_SOCKET;\r
2082         }\r
2083 \r
2084         if( protocol != IPPROTO_TCP )\r
2085         {\r
2086                 IBSP_ERROR_EXIT(\r
2087                         ("bad protocol %d instead of %d\n", protocol, IPPROTO_TCP) );\r
2088                 *lpErrno = WSAEPROTONOSUPPORT;\r
2089                 return INVALID_SOCKET;\r
2090         }\r
2091 \r
2092         if( (dwFlags != WSA_FLAG_OVERLAPPED) )\r
2093         {\r
2094                 IBSP_ERROR_EXIT(\r
2095                         ("dwFlags is not WSA_FLAG_OVERLAPPED (%x)\n", dwFlags) );\r
2096                 *lpErrno = WSAEINVAL;\r
2097                 return INVALID_SOCKET;\r
2098         }\r
2099 \r
2100         socket_info = create_socket_info( lpErrno );\r
2101         if( socket_info == NULL )\r
2102         {\r
2103                 IBSP_ERROR_EXIT( ("create_socket_info return NULL\n") );\r
2104                 return INVALID_SOCKET;\r
2105         }\r
2106 \r
2107         if( lpProtocolInfo->dwProviderReserved != 0 )\r
2108         {\r
2109                 /* This is a duplicate socket. */\r
2110                 *lpErrno = setup_duplicate_socket(\r
2111                         socket_info, lpProtocolInfo->dwProviderReserved );\r
2112                 if( *lpErrno )\r
2113                 {\r
2114                         int error;\r
2115 \r
2116                         if( g_ibsp.up_call_table.lpWPUCloseSocketHandle(\r
2117                                 socket_info->switch_socket, &error ) == SOCKET_ERROR )\r
2118                         {\r
2119                                 IBSP_ERROR( ("WPUCloseSocketHandle failed: %d\n", error) );\r
2120                         }\r
2121                         else\r
2122                         {\r
2123                                 STAT_DEC( wpusocket_num );\r
2124                         }\r
2125 \r
2126                         socket_info->switch_socket = INVALID_SOCKET;\r
2127 \r
2128                         deref_socket_info( socket_info );\r
2129                         IBSP_ERROR(\r
2130                                 ("setup_duplicate_socket failed with %d\n", *lpErrno) );\r
2131                         return INVALID_SOCKET;\r
2132                 }\r
2133         }\r
2134         else\r
2135         {\r
2136                 socket_info->socket_state = IBSP_CREATE;\r
2137 \r
2138                 /* Set the (non-zero) default socket options for that socket */\r
2139                 socket_info->socket_options.max_msg_size = IB_MAX_MSG_SIZE;\r
2140                 socket_info->socket_options.max_rdma_size = IB_MAX_RDMA_SIZE;\r
2141                 socket_info->socket_options.rdma_threshold_size = IB_RDMA_THRESHOLD_SIZE;\r
2142         }\r
2143 \r
2144         cl_spinlock_acquire( &g_ibsp.socket_info_mutex );\r
2145         cl_qlist_insert_tail( &g_ibsp.socket_info_list, &socket_info->item );\r
2146         cl_spinlock_release( &g_ibsp.socket_info_mutex );\r
2147 \r
2148         *lpErrno = 0;\r
2149 \r
2150         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,\r
2151                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));\r
2152 \r
2153         IBSP_TRACE_EXIT( IBSP_DBG_SI,\r
2154                 ("returning socket handle %p\n", socket_info) );\r
2155 \r
2156         return (SOCKET) socket_info;\r
2157 }\r
2158 \r
2159 \r
2160 /* Function: IBSPCleanup\r
2161  *\r
2162  *  Description:\r
2163  *    Decrement the entry count. If equal to zero then we can prepare to have us\r
2164  *    unloaded. Close any outstanding sockets and free up allocated memory.\r
2165  */\r
2166 static int WSPAPI\r
2167 IBSPCleanup(\r
2168                                         LPINT                                           lpErrno )\r
2169 {\r
2170         int ret = 0;\r
2171 \r
2172         IBSP_ENTER( IBSP_DBG_INIT );\r
2173 \r
2174         cl_spinlock_acquire( &g_ibsp.mutex );\r
2175 \r
2176         if( !g_ibsp.entry_count )\r
2177         {\r
2178                 cl_spinlock_release( &g_ibsp.mutex );\r
2179 \r
2180                 *lpErrno = WSANOTINITIALISED;\r
2181 \r
2182                 IBSP_ERROR_EXIT( ("returning WSAENOTINITIALISED\n") );\r
2183 \r
2184                 return SOCKET_ERROR;\r
2185         }\r
2186 \r
2187         /* Decrement the entry count */\r
2188         g_ibsp.entry_count--;\r
2189 \r
2190         IBSP_TRACE( IBSP_DBG_INIT, ("WSPCleanup: %d\n", g_ibsp.entry_count) );\r
2191 \r
2192         if( g_ibsp.entry_count == 0 )\r
2193         {\r
2194                 IBSP_TRACE( IBSP_DBG_INIT, ("entry_count is 0 => cleaning up\n") );\r
2195                 ib_release();\r
2196         }\r
2197 \r
2198         cl_spinlock_release( &g_ibsp.mutex );\r
2199 \r
2200         IBSP_EXIT( IBSP_DBG_INIT );\r
2201 \r
2202         return ret;\r
2203 }\r
2204 \r
2205 \r
2206 /*\r
2207  * Function: WSPStartupEx\r
2208  *\r
2209  *  Description:\r
2210  *    This function intializes the service provider. We maintain a ref count to keep track\r
2211  *    of how many times this function has been called.\r
2212  */\r
2213 int WSPAPI\r
2214 WSPStartupEx(\r
2215                                         WORD                                            wVersion,\r
2216                                         LPWSPDATA                                       lpWSPData,\r
2217                                         LPWSAPROTOCOL_INFOW                     lpProtocolInfo,\r
2218                                         LPWSPUPCALLTABLEEX                      UpCallTable,\r
2219                                         LPWSPPROC_TABLE                         lpProcTable )\r
2220 {\r
2221         static WSPPROC_TABLE gProcTable;\r
2222         static WSPDATA gWSPData;\r
2223 \r
2224         IBSP_ENTER( IBSP_DBG_INIT );\r
2225 \r
2226         /* Make sure that the version requested is >= 2.2. The low byte is the \r
2227            major version and the high byte is the minor version. */\r
2228         if( (LOBYTE(wVersion) < 2) || ((LOBYTE(wVersion) == 2) && (HIBYTE(wVersion) < 2)) )\r
2229         {\r
2230                 IBSP_ERROR_EXIT(\r
2231                         ("Invalid winsock version requested %x\n", wVersion) );\r
2232 \r
2233                 return WSAVERNOTSUPPORTED;\r
2234         }\r
2235 \r
2236         IBSP_TRACE( IBSP_DBG_INIT, ("entry_count=%d)\n", g_ibsp.entry_count) );\r
2237 \r
2238         cl_spinlock_acquire( &g_ibsp.mutex );\r
2239 \r
2240         if( g_ibsp.entry_count == 0 )\r
2241         {\r
2242                 int ret;\r
2243 \r
2244                 /* Save the global WSPData */\r
2245                 gWSPData.wVersion = MAKEWORD(2, 2);\r
2246                 gWSPData.wHighVersion = MAKEWORD(2, 2);\r
2247                 wcscpy( gWSPData.szDescription, Description );\r
2248 \r
2249                 /* provide Service provider's entry points in proc table */\r
2250                 memset( &gProcTable, 0, sizeof(gProcTable) );\r
2251                 gProcTable.lpWSPAccept = IBSPAccept;\r
2252                 gProcTable.lpWSPBind = IBSPBind;\r
2253                 gProcTable.lpWSPCleanup = IBSPCleanup;\r
2254                 gProcTable.lpWSPCloseSocket = IBSPCloseSocket;\r
2255                 gProcTable.lpWSPConnect = IBSPConnect;\r
2256                 gProcTable.lpWSPDuplicateSocket = IBSPDuplicateSocket;\r
2257                 gProcTable.lpWSPEnumNetworkEvents = IBSPEnumNetworkEvents;\r
2258                 gProcTable.lpWSPEventSelect = IBSPEventSelect;\r
2259                 gProcTable.lpWSPGetOverlappedResult = IBSPGetOverlappedResult;\r
2260                 gProcTable.lpWSPGetSockOpt = IBSPGetSockOpt;\r
2261                 gProcTable.lpWSPGetQOSByName = IBSPGetQOSByName;\r
2262                 gProcTable.lpWSPIoctl = IBSPIoctl;\r
2263                 gProcTable.lpWSPListen = IBSPListen;\r
2264                 gProcTable.lpWSPRecv = IBSPRecv;\r
2265                 gProcTable.lpWSPSend = IBSPSend;\r
2266                 gProcTable.lpWSPSetSockOpt = IBSPSetSockOpt;\r
2267                 gProcTable.lpWSPSocket = IBSPSocket;\r
2268 \r
2269                 /* Since we only support 2.2, set both wVersion and wHighVersion to 2.2. */\r
2270                 lpWSPData->wVersion = MAKEWORD(2, 2);\r
2271                 lpWSPData->wHighVersion = MAKEWORD(2, 2);\r
2272                 wcscpy( lpWSPData->szDescription, Description );\r
2273 \r
2274 #ifdef LATER\r
2275                 /* TODO: remove? */\r
2276                 cl_qlist_init( &g_ibsp.cq_thread_info_list );\r
2277                 cl_spinlock_init( &g_ibsp.cq_thread_info_mutex );\r
2278 #endif\r
2279 \r
2280                 g_ibsp.protocol_info = *lpProtocolInfo;\r
2281 \r
2282                 /* Initialize Infiniband */\r
2283                 ret = ibsp_initialize();\r
2284                 if( ret )\r
2285                 {\r
2286                         IBSP_ERROR_EXIT(\r
2287                                 ("ibsp_initialize failed (%d)\n", ret) );\r
2288                         return ret;\r
2289                 }\r
2290         }\r
2291         g_ibsp.entry_count++;\r
2292 \r
2293         cl_spinlock_release( &g_ibsp.mutex );\r
2294 \r
2295         /* Set the return parameters */\r
2296         *lpWSPData = gWSPData;\r
2297         *lpProcTable = gProcTable;\r
2298 \r
2299         /* store the upcall function table */\r
2300         g_ibsp.up_call_table = *UpCallTable;\r
2301 \r
2302         IBSP_EXIT( IBSP_DBG_INIT );\r
2303 \r
2304         return 0;\r
2305 }\r