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