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