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