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