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