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