[WSD] Change ib_listen to return an error value rather than set it
[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                         CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("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         /* Check the state of the socket */\r
1575         if( socket_info->socket_state != IBSP_CONNECTED )\r
1576         {\r
1577                 IBSP_ERROR_EXIT(\r
1578                         ("Socket is not in connected socket_state state=%s\n",\r
1579                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
1580                 *lpErrno = WSAENOTCONN;\r
1581                 return SOCKET_ERROR;\r
1582         }\r
1583 \r
1584         if( socket_info->qp_error != 0 )\r
1585         {\r
1586                 IBSP_ERROR_EXIT(\r
1587                         ("QP is in error state %d\n", socket_info->qp_error) );\r
1588                 *lpErrno = socket_info->qp_error;\r
1589                 return SOCKET_ERROR;\r
1590         }\r
1591 \r
1592         /* This function only works for that case. Right now the switch is\r
1593          * only using that. */\r
1594         if( dwBufferCount > QP_ATTRIB_RQ_SGE )\r
1595         {\r
1596                 CL_ASSERT( dwBufferCount <= QP_ATTRIB_RQ_SGE );\r
1597                 IBSP_ERROR_EXIT(\r
1598                         ("dwBufferCount is greater than %d\n", QP_ATTRIB_RQ_SGE) );\r
1599                 *lpErrno = WSAEINVAL;\r
1600                 return SOCKET_ERROR;\r
1601         }\r
1602 \r
1603         cl_spinlock_acquire( &socket_info->recv_lock );\r
1604         if( socket_info->recv_cnt == QP_ATTRIB_RQ_DEPTH )\r
1605         {\r
1606                 /* This should never happen */\r
1607                 cl_spinlock_release( &socket_info->recv_lock );\r
1608                 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );\r
1609                 *lpErrno = WSAENETDOWN;\r
1610                 return SOCKET_ERROR;\r
1611         }\r
1612 \r
1613         wr = &socket_info->recv_wr[socket_info->recv_idx];\r
1614 \r
1615         wr->wr.lpOverlapped = lpOverlapped;\r
1616         wr->wr.socket_info = socket_info;\r
1617 \r
1618         /* Looks good. Post the receive buffer. */\r
1619         wr->recv.p_next = NULL;\r
1620         wr->recv.wr_id = (uint64_t)(void* __ptr64)wr;\r
1621         wr->recv.num_ds = dwBufferCount;\r
1622         wr->recv.ds_array = wr->ds_array;\r
1623 \r
1624         for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )\r
1625         {\r
1626                 /* Get the memory region node */\r
1627                 node = lookup_partial_mr( &socket_info->buf_mem_list, IB_AC_LOCAL_WRITE,\r
1628                         lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );\r
1629                 if( !node )\r
1630                 {\r
1631                         cl_spinlock_release( &socket_info->recv_lock );\r
1632                         /*\r
1633                          * No mr fits. This should never happen. This error is not \r
1634                          * official, but seems to be the closest.\r
1635                          */\r
1636                         IBSP_ERROR_EXIT( ("no MR found\n") );\r
1637                         *lpErrno = WSAEFAULT;\r
1638                         return SOCKET_ERROR;\r
1639                 }\r
1640 \r
1641                 wr->ds_array[ds_idx].vaddr =\r
1642                         (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;\r
1643                 wr->ds_array[ds_idx].length = lpBuffers[ds_idx].len;\r
1644                 wr->ds_array[ds_idx].lkey = node->lkey;\r
1645         }\r
1646 \r
1647         /*\r
1648          * We must set this now, because the operation could complete\r
1649          * before ib_post_Recv returns.\r
1650          */\r
1651         lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;\r
1652 \r
1653         /* Store the flags for reporting back in IBSPGetOverlappedResult */\r
1654         lpOverlapped->Offset = *lpFlags;\r
1655 \r
1656         cl_atomic_inc( &socket_info->recv_cnt );\r
1657 \r
1658 #ifdef _DEBUG_\r
1659         if( lpOverlapped->hEvent == 0 )\r
1660         {\r
1661                 cl_atomic_inc( &g_ibsp.overlap_h0_count );\r
1662         }\r
1663         else\r
1664         {\r
1665                 cl_atomic_inc( &g_ibsp.overlap_h1_count );\r
1666                 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );\r
1667         }\r
1668 \r
1669         cl_atomic_inc( &g_ibsp.recv_count );\r
1670 \r
1671         fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",\r
1672                          __FUNCTION__, __LINE__, GetCurrentProcessId(),\r
1673                          GetCurrentThreadId(), lpOverlapped,\r
1674                          g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,\r
1675                          g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));\r
1676 \r
1677 \r
1678 #endif\r
1679 \r
1680 \r
1681         fzprint(("%s():%d:0x%x:0x%x: posting RECV socket=0x%p overlap=%p wr=0x%p\n",\r
1682                          __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,\r
1683                          lpOverlapped, wr));\r
1684 \r
1685         status = ib_post_recv( socket_info->qp, &wr->recv, NULL );\r
1686 \r
1687         if( status == IB_SUCCESS )\r
1688         {\r
1689                 /* Update the index and wrap as needed */\r
1690 #if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \\r
1691         QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \\r
1692         QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8\r
1693                 socket_info->recv_idx++;\r
1694                 socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1);\r
1695 #else\r
1696                 if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH )\r
1697                         socket_info->recv_idx = 0;\r
1698 #endif\r
1699 \r
1700                 IBSP_TRACE1( IBSP_DBG_IO,\r
1701                         ("Posted RECV: socket=%p, ov=%p, addr=%p, len=%d\n",\r
1702                         s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );\r
1703 \r
1704                 *lpErrno = WSA_IO_PENDING;\r
1705         }\r
1706         else\r
1707         {\r
1708                 IBSP_ERROR(\r
1709                         ("ib_post_recv returned %s\n", ib_get_err_str( status )) );\r
1710 #ifdef _DEBUG_\r
1711                 if( lpOverlapped->hEvent == 0 )\r
1712                 {\r
1713                         cl_atomic_dec( &g_ibsp.overlap_h0_count );\r
1714                 }\r
1715                 else\r
1716                 {\r
1717                         cl_atomic_dec( &g_ibsp.overlap_h1_count );\r
1718                         cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );\r
1719                 }\r
1720 \r
1721                 cl_atomic_dec( &g_ibsp.recv_count );\r
1722 \r
1723                 memset( wr, 0x33, sizeof(struct _recv_wr) );\r
1724 #endif\r
1725 \r
1726                 cl_atomic_dec( &socket_info->recv_cnt );\r
1727                 *lpErrno = ibal_to_wsa_error( status );\r
1728         }\r
1729 \r
1730         cl_spinlock_release( &socket_info->recv_lock );\r
1731 \r
1732         /* We never complete the operation here. */\r
1733         IBSP_EXIT( IBSP_DBG_IO );\r
1734         return SOCKET_ERROR;\r
1735 }\r
1736 \r
1737 \r
1738 /* Function: IBSPSend\r
1739  *\r
1740  *  Description:\r
1741  *    This function sends data on a given socket and also allows for asynchronous\r
1742  *    (overlapped) operation. First translate the socket handle to the lower provider\r
1743  *    handle and then make the send call.\r
1744 */\r
1745 static int WSPAPI\r
1746 IBSPSend(\r
1747         IN                              SOCKET                                          s,\r
1748         IN                              LPWSABUF                                        lpBuffers,\r
1749         IN                              DWORD                                           dwBufferCount,\r
1750                 OUT                     LPDWORD                                         lpNumberOfBytesSent,\r
1751         IN                              DWORD                                           dwFlags,\r
1752         IN                              LPWSAOVERLAPPED                         lpOverlapped,\r
1753         IN                              LPWSAOVERLAPPED_COMPLETION_ROUTINE      lpCompletionRoutine,\r
1754         IN                              LPWSATHREADID                           lpThreadId,\r
1755                 OUT                     LPINT                                           lpErrno )\r
1756 {\r
1757         struct ibsp_socket_info         *socket_info = (struct ibsp_socket_info *)s;\r
1758         ib_api_status_t                         status;\r
1759         struct memory_node                      *node;\r
1760         struct _wr                                      *wr;\r
1761         ib_send_wr_t                            send_wr;\r
1762         ib_local_ds_t                           local_ds[QP_ATTRIB_SQ_SGE];\r
1763         DWORD                                           ds_idx;\r
1764 \r
1765         IBSP_ENTER( IBSP_DBG_IO );\r
1766 \r
1767         UNUSED_PARAM( lpNumberOfBytesSent );\r
1768         UNUSED_PARAM( lpCompletionRoutine );\r
1769         UNUSED_PARAM( lpThreadId );\r
1770 \r
1771         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlap=%p\n", __FUNCTION__,\r
1772                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped));\r
1773 \r
1774         if( s == INVALID_SOCKET )\r
1775         {\r
1776                 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );\r
1777                 *lpErrno = WSAENOTSOCK;\r
1778                 return SOCKET_ERROR;\r
1779         }\r
1780 \r
1781         CL_ASSERT( lpCompletionRoutine == NULL );\r
1782         CL_ASSERT( lpOverlapped != NULL );\r
1783 \r
1784         cl_spinlock_acquire( &socket_info->mutex );\r
1785         /* Check the state of the socket */\r
1786         switch( socket_info->socket_state )\r
1787         {\r
1788         case IBSP_CONNECTED:\r
1789         case IBSP_DISCONNECTED:\r
1790                 break;\r
1791 \r
1792         default:\r
1793                 IBSP_ERROR_EXIT( ("Socket is not in connected socket_state \n") );\r
1794                 *lpErrno = WSAENOTCONN;\r
1795                 return SOCKET_ERROR;\r
1796         }\r
1797         cl_spinlock_release( &socket_info->mutex );\r
1798 \r
1799         if( socket_info->qp_error )\r
1800         {\r
1801                 IBSP_ERROR_EXIT(\r
1802                         ("QP is in error state %d\n", socket_info->qp_error) );\r
1803                 *lpErrno = socket_info->qp_error;\r
1804                 return SOCKET_ERROR;\r
1805         }\r
1806 \r
1807         /* This function only works for that case. */\r
1808         if( dwBufferCount > QP_ATTRIB_SQ_SGE )\r
1809         {\r
1810                 CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE );\r
1811                 IBSP_ERROR_EXIT(\r
1812                         ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) );\r
1813                 *lpErrno = WSAEINVAL;\r
1814                 return SOCKET_ERROR;\r
1815         }\r
1816 \r
1817         /* The send lock is only used to serialize posting. */\r
1818         cl_spinlock_acquire( &socket_info->send_lock );\r
1819         if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH )\r
1820         {\r
1821                 /* This should never happen */\r
1822                 cl_spinlock_release( &socket_info->send_lock );\r
1823                 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );\r
1824                 *lpErrno = WSAENETDOWN;\r
1825                 return SOCKET_ERROR;\r
1826         }\r
1827 \r
1828         wr = &socket_info->send_wr[socket_info->send_idx];\r
1829 \r
1830         wr->lpOverlapped = lpOverlapped;\r
1831         wr->socket_info = socket_info;\r
1832 \r
1833         /* Looks good. Post the send buffer. */\r
1834         send_wr.p_next = NULL;\r
1835         send_wr.wr_id = (uint64_t) (uintptr_t) wr;\r
1836         send_wr.wr_type = WR_SEND;\r
1837         send_wr.send_opt = socket_info->send_opt;\r
1838         socket_info->send_opt = 0;\r
1839 \r
1840         send_wr.num_ds = dwBufferCount;\r
1841         send_wr.ds_array = local_ds;\r
1842 \r
1843         lpOverlapped->InternalHigh = 0;\r
1844         for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )\r
1845         {\r
1846                 local_ds[ds_idx].vaddr = (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;\r
1847                 local_ds[ds_idx].length = lpBuffers[ds_idx].len;\r
1848 \r
1849                 lpOverlapped->InternalHigh += lpBuffers[ds_idx].len;\r
1850         }\r
1851 \r
1852         if( lpOverlapped->InternalHigh <= socket_info->max_inline )\r
1853         {\r
1854                 send_wr.send_opt |= IB_SEND_OPT_INLINE;\r
1855         }\r
1856         else\r
1857         {\r
1858                 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )\r
1859                 {\r
1860                         /* Get the memory region node */\r
1861                         node = lookup_partial_mr( &socket_info->buf_mem_list, 0,        /* READ */\r
1862                                 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );\r
1863                         if( !node )\r
1864                         {\r
1865                                 cl_spinlock_release( &socket_info->send_lock );\r
1866                                 /*\r
1867                                  * No mr fits. This error is not official, but seems to be the\r
1868                                  * closest.\r
1869                                  */\r
1870                                 IBSP_ERROR_EXIT( ("mr lookup failed\n") );\r
1871                                 *lpErrno = WSAEFAULT;\r
1872                                 return SOCKET_ERROR;\r
1873                         }\r
1874 \r
1875                         local_ds[ds_idx].lkey = node->lkey;\r
1876                 }\r
1877         }\r
1878 \r
1879         /*\r
1880          * We must set this now, because the operation could complete\r
1881          * before ib_post_send returns.\r
1882          */\r
1883         lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;\r
1884 \r
1885         /* Store the flags for reporting back in IBSPGetOverlappedResult */\r
1886         lpOverlapped->Offset = dwFlags;\r
1887 \r
1888         cl_atomic_inc( &socket_info->send_cnt );\r
1889 \r
1890 #ifdef _DEBUG_\r
1891         if( lpOverlapped->hEvent == 0)\r
1892         {\r
1893                 cl_atomic_inc( &g_ibsp.overlap_h0_count );\r
1894         }\r
1895         else\r
1896         {\r
1897                 cl_atomic_inc( &g_ibsp.overlap_h1_count );\r
1898                 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );\r
1899         }\r
1900 \r
1901         cl_atomic_inc( &g_ibsp.send_count );\r
1902 \r
1903         fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",\r
1904                          __FUNCTION__, __LINE__, GetCurrentProcessId(),\r
1905                          GetCurrentThreadId(), lpOverlapped,\r
1906                          g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,\r
1907                          g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));\r
1908 \r
1909 \r
1910 #endif\r
1911 \r
1912 \r
1913         fzprint(("%s():%d:0x%x:0x%x: posting SEND %p, mr handle=%p, addr=%p, len=%d\n",\r
1914                          __FUNCTION__,\r
1915                          __LINE__, GetCurrentProcessId(),\r
1916                          GetCurrentThreadId(),\r
1917                          lpOverlapped, node, lpBuffers[0].buf, lpBuffers[0].len));\r
1918 \r
1919 #ifdef _DEBUG_\r
1920         if( lpBuffers[0].len >= 40 )\r
1921         {\r
1922                 debug_dump_buffer( IBSP_DBG_WQ | IBSP_DBG_LEVEL4, "SEND",\r
1923                         lpBuffers[0].buf, 40 );\r
1924         }\r
1925 #endif\r
1926 \r
1927         status = ib_post_send( socket_info->qp, &send_wr, NULL );\r
1928 \r
1929         if( status == IB_SUCCESS )\r
1930         {\r
1931                 /* Update the index and wrap as needed */\r
1932 #if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \\r
1933         QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \\r
1934         QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8\r
1935                 socket_info->send_idx++;\r
1936                 socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1);\r
1937 #else\r
1938                 if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH )\r
1939                         socket_info->send_idx = 0;\r
1940 #endif\r
1941 \r
1942 \r
1943                 IBSP_TRACE1( IBSP_DBG_IO,\r
1944                         ("Posted SEND: socket=%p, ov=%p, addr=%p, len=%d\n",\r
1945                         s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );\r
1946 \r
1947                 *lpErrno = WSA_IO_PENDING;\r
1948         }\r
1949         else\r
1950         {\r
1951                 IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) );\r
1952 \r
1953 #ifdef _DEBUG_\r
1954                 if( lpOverlapped->hEvent == 0 )\r
1955                 {\r
1956                         cl_atomic_dec( &g_ibsp.overlap_h0_count );\r
1957                 }\r
1958                 else\r
1959                 {\r
1960                         cl_atomic_dec( &g_ibsp.overlap_h1_count );\r
1961                         cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );\r
1962                 }\r
1963                 cl_atomic_dec( &g_ibsp.send_count );\r
1964 \r
1965                 memset( wr, 0x37, sizeof(struct _wr) );\r
1966 #endif\r
1967                 cl_atomic_dec( &socket_info->send_cnt );\r
1968 \r
1969                 *lpErrno = ibal_to_wsa_error( status );\r
1970         }\r
1971         cl_spinlock_release( &socket_info->send_lock );\r
1972 \r
1973         /* We never complete the operation here. */\r
1974         IBSP_EXIT( IBSP_DBG_IO );\r
1975         return SOCKET_ERROR;\r
1976 }\r
1977 \r
1978 \r
1979 /* Function: IBSPSetSockOpt\r
1980  * \r
1981  *  Description:\r
1982  *    Set a socket option. For most all options we just have to translate the\r
1983  *    socket option and call the lower provider. The only special case is for\r
1984  *    SO_UPDATE_ACCEPT_CONTEXT in which case a socket handle is passed as the\r
1985  *    argument which we need to translate before calling the lower provider.\r
1986  */\r
1987 static int WSPAPI\r
1988 IBSPSetSockOpt(\r
1989                                         SOCKET                                          s,\r
1990                                         int                                                     level,\r
1991                                         int                                                     optname,\r
1992                                         const char FAR                          *optval,\r
1993                                         int                                                     optlen,\r
1994                                         LPINT                                           lpErrno )\r
1995 {\r
1996         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
1997 \r
1998         IBSP_ENTER( IBSP_DBG_OPT );\r
1999 \r
2000         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,\r
2001                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));\r
2002 \r
2003         if( level != SOL_SOCKET )\r
2004         {\r
2005                 IBSP_ERROR_EXIT( ("invalid level %d", level) );\r
2006                 *lpErrno = WSAENOPROTOOPT;\r
2007                 return SOCKET_ERROR;\r
2008         }\r
2009 \r
2010         if( optval == NULL )\r
2011         {\r
2012                 IBSP_ERROR_EXIT( ("invalid optval=%p", optval) );\r
2013                 *lpErrno = WSAEFAULT;\r
2014                 return SOCKET_ERROR;\r
2015         }\r
2016 \r
2017         switch( optname )\r
2018         {\r
2019         case SO_DEBUG:\r
2020                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );\r
2021                 if( optlen != sizeof(BOOL) )\r
2022                 {\r
2023                         IBSP_ERROR_EXIT(\r
2024                                 ("option len is invalid (0x%x)\n", optlen) );\r
2025                         *lpErrno = WSAEFAULT;\r
2026                         return SOCKET_ERROR;\r
2027                 }\r
2028                 memcpy( &socket_info->socket_options.debug, optval, sizeof(BOOL) );\r
2029                 break;\r
2030 \r
2031         case SO_GROUP_PRIORITY:\r
2032                 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );\r
2033                 if( optlen != sizeof(int) )\r
2034                 {\r
2035                         IBSP_ERROR_EXIT(\r
2036                                 ("option len is invalid (0x%x)\n", optlen) );\r
2037                         *lpErrno = WSAEFAULT;\r
2038                         return SOCKET_ERROR;\r
2039                 }\r
2040                 memcpy( &socket_info->socket_options.group_priority, optval, sizeof(int) );\r
2041                 break;\r
2042 \r
2043         default:\r
2044                 IBSP_ERROR_EXIT( ("invalid option %x\n", optname) );\r
2045                 *lpErrno = WSAENOPROTOOPT;\r
2046                 return SOCKET_ERROR;\r
2047                 break;\r
2048         }\r
2049 \r
2050         IBSP_EXIT( IBSP_DBG_OPT );\r
2051 \r
2052         return 0;\r
2053 }\r
2054 \r
2055 \r
2056 /* Function: IBSPSocket\r
2057  *\r
2058  *  Description:\r
2059  *    This function creates a socket. There are two sockets created. The first\r
2060  *    socket is created by calling the lower providers WSPSocket. This is the\r
2061  *    handle that we use internally within our LSP. We then create a second\r
2062  *    socket with WPUCreateSocketHandle which will be returned to the calling\r
2063  *    application. We will also create a socket context structure which will\r
2064  *    maintain information on each socket. This context is associated with the\r
2065  *    socket handle passed to the application.\r
2066 */\r
2067 static SOCKET WSPAPI\r
2068 IBSPSocket(\r
2069                                         int                                                     af,\r
2070                                         int                                                     type,\r
2071                                         int                                                     protocol,\r
2072                                         LPWSAPROTOCOL_INFOW                     lpProtocolInfo,\r
2073                                         GROUP                                           g,\r
2074                                         DWORD                                           dwFlags,\r
2075                                         LPINT                                           lpErrno )\r
2076 {\r
2077         struct ibsp_socket_info *socket_info = NULL;\r
2078 \r
2079         IBSP_ENTER( IBSP_DBG_SI );\r
2080 \r
2081         UNUSED_PARAM( g );\r
2082 \r
2083         if( af != AF_INET )\r
2084         {\r
2085                 IBSP_ERROR(\r
2086                         ("bad family %d instead of %d\n", af, AF_INET) );\r
2087                 *lpErrno = WSAEAFNOSUPPORT;\r
2088                 goto error;\r
2089         }\r
2090 \r
2091         if( type != SOCK_STREAM )\r
2092         {\r
2093                 IBSP_ERROR(\r
2094                         ("bad type %d instead of %d\n", type, SOCK_STREAM) );\r
2095                 *lpErrno = WSAEPROTOTYPE;\r
2096                 goto error;\r
2097         }\r
2098 \r
2099         if( protocol != IPPROTO_TCP )\r
2100         {\r
2101                 IBSP_ERROR(\r
2102                         ("bad protocol %d instead of %d\n", protocol, IPPROTO_TCP) );\r
2103                 *lpErrno = WSAEPROTONOSUPPORT;\r
2104                 goto error;\r
2105         }\r
2106 \r
2107         if( (dwFlags != WSA_FLAG_OVERLAPPED) )\r
2108         {\r
2109                 IBSP_ERROR(\r
2110                         ("dwFlags is not WSA_FLAG_OVERLAPPED (%x)\n", dwFlags) );\r
2111                 *lpErrno = WSAEINVAL;\r
2112                 goto error;\r
2113         }\r
2114 \r
2115         socket_info = create_socket_info();\r
2116         if( socket_info == NULL )\r
2117         {\r
2118                 IBSP_ERROR( ("create_socket_info return NULL\n") );\r
2119                 *lpErrno = WSAENOBUFS;\r
2120                 goto error;\r
2121         }\r
2122 \r
2123         if( lpProtocolInfo->dwProviderReserved != 0 )\r
2124         {\r
2125                 /* This is a duplicate socket. */\r
2126                 int ret;\r
2127 \r
2128                 ret = setup_duplicate_socket( socket_info, lpProtocolInfo->dwProviderReserved );\r
2129                 if( ret )\r
2130                 {\r
2131                         IBSP_ERROR(\r
2132                                 ("setup_duplicate_socket failed with %d\n",ret) );\r
2133                         *lpErrno = ret;\r
2134                         goto error;\r
2135                 }\r
2136         }\r
2137         else\r
2138         {\r
2139                 socket_info->switch_socket =\r
2140                         g_ibsp.up_call_table.lpWPUCreateSocketHandle( 0,\r
2141                                                                                                                  (DWORD_PTR) socket_info,\r
2142                                                                                                                  lpErrno );\r
2143 \r
2144                 if( socket_info->switch_socket != INVALID_SOCKET )\r
2145                 {\r
2146                         IBSP_TRACE1( IBSP_DBG_SI, ("socket_info=0x%p switch_socket=0x%p \n",\r
2147                                 socket_info, socket_info->switch_socket) );\r
2148 \r
2149                         STAT_INC( wpusocket_num );\r
2150                 }\r
2151         }\r
2152 \r
2153         if( socket_info->switch_socket == INVALID_SOCKET )\r
2154         {\r
2155                 IBSP_ERROR(\r
2156                         ("WPUCreateSocketHandle() failed: %d\n", *lpErrno) );\r
2157                 /* lpErrno has just been set */\r
2158                 goto error;\r
2159         }\r
2160 \r
2161         /* Success */\r
2162         if( lpProtocolInfo->dwProviderReserved != 0 )\r
2163         {\r
2164                 CL_ASSERT( socket_info->socket_state == IBSP_CONNECTED );\r
2165         }\r
2166         else\r
2167         {\r
2168                 socket_info->socket_state = IBSP_CREATE;\r
2169 \r
2170                 /* Set the (non-zero) default socket options for that socket */\r
2171                 socket_info->socket_options.max_msg_size = IB_MAX_MSG_SIZE;\r
2172                 socket_info->socket_options.max_rdma_size = IB_MAX_RDMA_SIZE;\r
2173                 socket_info->socket_options.rdma_threshold_size = IB_RDMA_THRESHOLD_SIZE;\r
2174         }\r
2175 \r
2176         cl_spinlock_acquire( &g_ibsp.socket_info_mutex );\r
2177         cl_qlist_insert_tail( &g_ibsp.socket_info_list, &socket_info->item );\r
2178         cl_spinlock_release( &g_ibsp.socket_info_mutex );\r
2179 \r
2180         *lpErrno = 0;\r
2181 \r
2182         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,\r
2183                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));\r
2184 \r
2185         IBSP_TRACE_EXIT( IBSP_DBG_SI,\r
2186                 ("returning socket handle %p\n", socket_info) );\r
2187 \r
2188         return (SOCKET) socket_info;\r
2189 \r
2190 error:\r
2191         if( socket_info )\r
2192                 free_socket_info( socket_info );\r
2193 \r
2194         CL_ASSERT( *lpErrno != 0 );\r
2195 \r
2196         IBSP_ERROR_EXIT( ("Returning error %d\n", *lpErrno) );\r
2197 \r
2198         return INVALID_SOCKET;\r
2199 }\r
2200 \r
2201 \r
2202 /* Function: IBSPCleanup\r
2203  *\r
2204  *  Description:\r
2205  *    Decrement the entry count. If equal to zero then we can prepare to have us\r
2206  *    unloaded. Close any outstanding sockets and free up allocated memory.\r
2207  */\r
2208 static int WSPAPI\r
2209 IBSPCleanup(\r
2210                                         LPINT                                           lpErrno )\r
2211 {\r
2212         int ret = 0;\r
2213 \r
2214         IBSP_ENTER( IBSP_DBG_INIT );\r
2215 \r
2216         cl_spinlock_acquire( &g_ibsp.mutex );\r
2217 \r
2218         if( !g_ibsp.entry_count )\r
2219         {\r
2220                 cl_spinlock_release( &g_ibsp.mutex );\r
2221 \r
2222                 *lpErrno = WSANOTINITIALISED;\r
2223 \r
2224                 IBSP_ERROR_EXIT( ("returning WSAENOTINITIALISED\n") );\r
2225 \r
2226                 return SOCKET_ERROR;\r
2227         }\r
2228 \r
2229         /* Decrement the entry count */\r
2230         g_ibsp.entry_count--;\r
2231 \r
2232         IBSP_TRACE( IBSP_DBG_INIT, ("WSPCleanup: %d\n", g_ibsp.entry_count) );\r
2233 \r
2234         if( g_ibsp.entry_count == 0 )\r
2235         {\r
2236                 IBSP_TRACE( IBSP_DBG_INIT, ("entry_count is 0 => cleaning up\n") );\r
2237                 ib_release();\r
2238         }\r
2239 \r
2240         cl_spinlock_release( &g_ibsp.mutex );\r
2241 \r
2242         IBSP_EXIT( IBSP_DBG_INIT );\r
2243 \r
2244         return ret;\r
2245 }\r
2246 \r
2247 \r
2248 /*\r
2249  * Function: WSPStartupEx\r
2250  *\r
2251  *  Description:\r
2252  *    This function intializes the service provider. We maintain a ref count to keep track\r
2253  *    of how many times this function has been called.\r
2254  */\r
2255 int WSPAPI\r
2256 WSPStartupEx(\r
2257                                         WORD                                            wVersion,\r
2258                                         LPWSPDATA                                       lpWSPData,\r
2259                                         LPWSAPROTOCOL_INFOW                     lpProtocolInfo,\r
2260                                         LPWSPUPCALLTABLEEX                      UpCallTable,\r
2261                                         LPWSPPROC_TABLE                         lpProcTable )\r
2262 {\r
2263         static WSPPROC_TABLE gProcTable;\r
2264         static WSPDATA gWSPData;\r
2265 \r
2266         IBSP_ENTER( IBSP_DBG_INIT );\r
2267 \r
2268         /* Make sure that the version requested is >= 2.2. The low byte is the \r
2269            major version and the high byte is the minor version. */\r
2270         if( (LOBYTE(wVersion) < 2) || ((LOBYTE(wVersion) == 2) && (HIBYTE(wVersion) < 2)) )\r
2271         {\r
2272                 IBSP_ERROR_EXIT(\r
2273                         ("Invalid winsock version requested %x\n", wVersion) );\r
2274 \r
2275                 return WSAVERNOTSUPPORTED;\r
2276         }\r
2277 \r
2278         IBSP_TRACE( IBSP_DBG_INIT, ("entry_count=%d)\n", g_ibsp.entry_count) );\r
2279 \r
2280         cl_spinlock_acquire( &g_ibsp.mutex );\r
2281 \r
2282         if( g_ibsp.entry_count == 0 )\r
2283         {\r
2284                 int ret;\r
2285 \r
2286                 /* Save the global WSPData */\r
2287                 gWSPData.wVersion = MAKEWORD(2, 2);\r
2288                 gWSPData.wHighVersion = MAKEWORD(2, 2);\r
2289                 wcscpy( gWSPData.szDescription, Description );\r
2290 \r
2291                 /* provide Service provider's entry points in proc table */\r
2292                 memset( &gProcTable, 0, sizeof(gProcTable) );\r
2293                 gProcTable.lpWSPAccept = IBSPAccept;\r
2294                 gProcTable.lpWSPBind = IBSPBind;\r
2295                 gProcTable.lpWSPCleanup = IBSPCleanup;\r
2296                 gProcTable.lpWSPCloseSocket = IBSPCloseSocket;\r
2297                 gProcTable.lpWSPConnect = IBSPConnect;\r
2298                 gProcTable.lpWSPDuplicateSocket = IBSPDuplicateSocket;\r
2299                 gProcTable.lpWSPEnumNetworkEvents = IBSPEnumNetworkEvents;\r
2300                 gProcTable.lpWSPEventSelect = IBSPEventSelect;\r
2301                 gProcTable.lpWSPGetOverlappedResult = IBSPGetOverlappedResult;\r
2302                 gProcTable.lpWSPGetSockOpt = IBSPGetSockOpt;\r
2303                 gProcTable.lpWSPGetQOSByName = IBSPGetQOSByName;\r
2304                 gProcTable.lpWSPIoctl = IBSPIoctl;\r
2305                 gProcTable.lpWSPListen = IBSPListen;\r
2306                 gProcTable.lpWSPRecv = IBSPRecv;\r
2307                 gProcTable.lpWSPSend = IBSPSend;\r
2308                 gProcTable.lpWSPSetSockOpt = IBSPSetSockOpt;\r
2309                 gProcTable.lpWSPSocket = IBSPSocket;\r
2310 \r
2311                 /* Since we only support 2.2, set both wVersion and wHighVersion to 2.2. */\r
2312                 lpWSPData->wVersion = MAKEWORD(2, 2);\r
2313                 lpWSPData->wHighVersion = MAKEWORD(2, 2);\r
2314                 wcscpy( lpWSPData->szDescription, Description );\r
2315 \r
2316 #ifdef LATER\r
2317                 /* TODO: remove? */\r
2318                 cl_qlist_init( &g_ibsp.cq_thread_info_list );\r
2319                 cl_spinlock_init( &g_ibsp.cq_thread_info_mutex );\r
2320 #endif\r
2321 \r
2322                 g_ibsp.protocol_info = *lpProtocolInfo;\r
2323 \r
2324                 /* Initialize Infiniband */\r
2325                 ret = ibsp_initialize();\r
2326                 if( ret )\r
2327                 {\r
2328                         IBSP_ERROR_EXIT(\r
2329                                 ("ibsp_initialize failed (%d)\n", ret) );\r
2330                         return ret;\r
2331                 }\r
2332         }\r
2333         g_ibsp.entry_count++;\r
2334 \r
2335         cl_spinlock_release( &g_ibsp.mutex );\r
2336 \r
2337         /* Set the return parameters */\r
2338         *lpWSPData = gWSPData;\r
2339         *lpProcTable = gProcTable;\r
2340 \r
2341         /* store the upcall function table */\r
2342         g_ibsp.up_call_table = *UpCallTable;\r
2343 \r
2344         IBSP_EXIT( IBSP_DBG_INIT );\r
2345 \r
2346         return 0;\r
2347 }\r