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