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