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