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