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