1 /*
2 * Copyright (c) 2015-2016 Intel Corporation, Inc.  All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses.  You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * BSD license below:
9 *
10 *     Redistribution and use in source and binary forms, with or
11 *     without modification, are permitted provided that the following
12 *     conditions are met:
13 *
14 *      - Redistributions of source code must retain the above
15 *        copyright notice, this list of conditions and the following
16 *        disclaimer.
17 *
18 *      - Redistributions in binary form must reproduce the above
19 *        copyright notice, this list of conditions and the following
20 *        disclaimer in the documentation and/or other materials
21 *        provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32 
33 #ifdef _WIN32
34 
35 #include <initguid.h>
36 #include <guiddef.h>
37 
38 #include <ws2spi.h>
39 #include <cassert>
40 #include "ndspi.h"
41 
42 #include "netdir.h"
43 #include "netdir_log.h"
44 
45 #ifndef ofi_sizeofaddr
46 #define ofi_sizeofaddr(address)			\
47 	(address)->sa_family == AF_INET ?	\
48 		sizeof(struct sockaddr_in) :	\
49 		sizeof(struct sockaddr_in6)
50 #endif
51 
52 #define FI_ND_PROTO_FLAG (XP1_GUARANTEED_DELIVERY | XP1_GUARANTEED_ORDER | \
53 			  XP1_MESSAGE_ORIENTED | XP1_CONNECT_DATA)
54 
55 static int ofi_nd_startup_done = 0;
56 
57 typedef HRESULT(*can_unload_now_t)(void);
58 typedef HRESULT(*get_class_object_t)(REFCLSID rclsid, REFIID rrid, LPVOID* ppv);
59 
60 struct module_t {
61 	const wchar_t		*path;
62 	HMODULE			module;
63 	can_unload_now_t	can_unload_now;
64 	get_class_object_t	get_class_object;
65 };
66 
67 struct factory_t {
68 	WSAPROTOCOL_INFOW	protocol;
69 	IClassFactory		*class_factory;
70 	IND2Provider		*provider;
71 	struct module_t		*module;
72 	SOCKET_ADDRESS_LIST	*addr_list;
73 };
74 
75 struct adapter_t {
76 	union {
77 		struct sockaddr		addr;
78 		struct sockaddr_in	addr4;
79 		struct sockaddr_in6	addr6;
80 	} address;
81 	ND2_ADAPTER_INFO		info;
82 	IND2Adapter			*adapter;
83 	struct factory_t		*factory;
84 	const char			*name;
85 };
86 
87 static struct ofi_nd_infra_t {
88 	struct modules_t {
89 		struct module_t		*modules;
90 		size_t			count;
91 	} providers;
92 
93 	struct class_factory_t {
94 		struct factory_t	*factory;
95 		size_t			count;
96 	} class_factories;
97 
98 	struct adapters_t {
99 		struct adapter_t	*adapter;
100 		size_t			count;
101 	} adapters;
102 } ofi_nd_infra = {0};
103 
104 /* release all objects, do not free strings or arrays */
ofi_nd_release_infra()105 static inline void ofi_nd_release_infra()
106 {
107 	size_t i;
108 
109 	if (ofi_nd_infra.adapters.count) {
110 		assert(ofi_nd_infra.adapters.adapter);
111 		for (i = 0; i < ofi_nd_infra.adapters.count; i++) {
112 			struct adapter_t *adapter = &ofi_nd_infra.adapters.adapter[i];
113 			if (adapter->adapter) {
114 				adapter->adapter->lpVtbl->Release(adapter->adapter);
115 				adapter->adapter = 0;
116 			}
117 		}
118 	}
119 
120 	if (ofi_nd_infra.class_factories.count) {
121 		assert(ofi_nd_infra.class_factories.factory);
122 		for (i = 0; i < ofi_nd_infra.class_factories.count; i++) {
123 			struct factory_t *factory = &ofi_nd_infra.class_factories.factory[i];
124 			if (factory->provider) {
125 				factory->provider->lpVtbl->Release(factory->provider);
126 				factory->provider = 0;
127 			}
128 			if (factory->class_factory) {
129 				factory->class_factory->lpVtbl->Release(factory->class_factory);
130 				factory->class_factory = 0;
131 			}
132 		}
133 	}
134 }
135 
ofi_nd_free_infra()136 static inline void ofi_nd_free_infra()
137 {
138 	size_t i;
139 
140 	ofi_nd_release_infra();
141 
142 	if (ofi_nd_infra.adapters.count) {
143 		assert(ofi_nd_infra.adapters.adapter);
144 		for (i = 0; i < ofi_nd_infra.adapters.count; i++) {
145 			struct adapter_t *adapter = &ofi_nd_infra.adapters.adapter[i];
146 			if (adapter->name) {
147 				free((void*)adapter->name);
148 				adapter->name = 0;
149 			}
150 		}
151 		free(ofi_nd_infra.adapters.adapter);
152 		ofi_nd_infra.adapters.adapter = 0;
153 		ofi_nd_infra.adapters.count = 0;
154 	}
155 
156 	if (ofi_nd_infra.class_factories.count) {
157 		assert(ofi_nd_infra.class_factories.factory);
158 		for (i = 0; i < ofi_nd_infra.class_factories.count; i++) {
159 			struct factory_t *factory = &ofi_nd_infra.class_factories.factory[i];
160 			assert(factory->module);
161 			if (factory->addr_list) {
162 				free(factory->addr_list);
163 				factory->addr_list = 0;
164 			}
165 		}
166 		free(ofi_nd_infra.class_factories.factory);
167 		ofi_nd_infra.class_factories.factory = 0;
168 		ofi_nd_infra.class_factories.count = 0;
169 	}
170 
171 	if (ofi_nd_infra.providers.count) {
172 		assert(ofi_nd_infra.providers.modules);
173 		for (i = 0; i < ofi_nd_infra.providers.count; i++) {
174 			struct module_t *module = &ofi_nd_infra.providers.modules[i];
175 			assert(module->path);
176 			free((void*)module->path);
177 		}
178 		free(ofi_nd_infra.providers.modules);
179 		ofi_nd_infra.providers.modules = 0;
180 		ofi_nd_infra.providers.count = 0;
181 	}
182 }
183 
ofi_nd_alloc_infra(size_t cnt)184 static inline HRESULT ofi_nd_alloc_infra(size_t cnt)
185 {
186 	memset(&ofi_nd_infra, 0, sizeof(*(&ofi_nd_infra)));
187 
188 	ofi_nd_infra.providers.modules = (struct module_t*)malloc(cnt * sizeof(*ofi_nd_infra.providers.modules));
189 	if (!ofi_nd_infra.providers.modules)
190 		return ND_NO_MEMORY;
191 
192 	ofi_nd_infra.class_factories.factory = (struct factory_t*)malloc(cnt * sizeof(*ofi_nd_infra.class_factories.factory));
193 	if (!ofi_nd_infra.class_factories.factory) {
194 		ofi_nd_free_infra();
195 		return ND_NO_MEMORY;
196 	}
197 
198 	return S_OK;
199 }
200 
ofi_nd_get_provider_path(const WSAPROTOCOL_INFOW * proto)201 static inline wchar_t *ofi_nd_get_provider_path(const WSAPROTOCOL_INFOW *proto)
202 {
203 	assert(proto);
204 
205 	int len, lenex, err, res;
206 	wchar_t *prov, *provex;
207 
208 	res = WSCGetProviderPath((GUID*)&proto->ProviderId, NULL, &len, &err);
209 	if (err != WSAEFAULT || !len)
210 		return NULL;
211 
212 	prov = (wchar_t*)malloc(len * sizeof(*prov));
213 	if (!prov)
214 		return NULL;
215 
216 	res = WSCGetProviderPath((GUID*)&proto->ProviderId, prov, &len, &err);
217 	if (res)
218 		goto fn1;
219 
220 	lenex = ExpandEnvironmentStringsW(prov, NULL, 0);
221 	if (!lenex)
222 		goto fn1;
223 
224 	provex = (wchar_t*)malloc(lenex * sizeof(*provex));
225 	if (!provex)
226 		goto fn1;
227 
228 	lenex = ExpandEnvironmentStringsW(prov, provex, lenex);
229 	if (!lenex)
230 		goto fn2;
231 
232 	free(prov);
233 	return provex;
234 
235 fn2:
236 	free(provex);
237 fn1:
238 	free(prov);
239 	return NULL;
240 }
241 
ofi_nd_is_valid_proto(const WSAPROTOCOL_INFOW * proto)242 static inline int ofi_nd_is_valid_proto(const WSAPROTOCOL_INFOW *proto)
243 {
244 	assert(proto);
245 
246 	if ((proto->dwServiceFlags1 & FI_ND_PROTO_FLAG) != FI_ND_PROTO_FLAG)
247 		return 0;
248 
249 	if (!(proto->iAddressFamily == AF_INET ||
250 	      proto->iAddressFamily == AF_INET6))
251 		return 0;
252 
253 	if (proto->iSocketType != -1)
254 		return 0;
255 
256 	if (proto->iProtocol || proto->iProtocolMaxOffset)
257 		return 0;
258 	return 1;
259 }
260 
ofi_nd_search_module(const wchar_t * path)261 static inline struct module_t *ofi_nd_search_module(const wchar_t* path)
262 {
263 	size_t i;
264 	size_t j;
265 
266 	for (i = 0; i < ofi_nd_infra.providers.count; i++) {
267 		if (path && ofi_nd_file_exists(path) &&
268 		    !ofi_nd_is_directory(path)) {
269 			for (j = 0; j < ofi_nd_infra.providers.count; j++) {
270 				if (ofi_nd_is_same_file(path, ofi_nd_infra.providers.modules[j].path)) {
271 					return &ofi_nd_infra.providers.modules[j];
272 				}
273 			}
274 		}
275 	}
276 	return NULL;
277 }
278 
ofi_nd_create_module(const wchar_t * path)279 static inline struct module_t *ofi_nd_create_module(const wchar_t* path)
280 {
281 	struct module_t *module;
282 	HMODULE hmodule;
283 	can_unload_now_t unload;
284 	get_class_object_t getclass;
285 
286 	assert(ofi_nd_infra.providers.modules);
287 
288 	module = ofi_nd_search_module(path);
289 	if (module)
290 		return module;
291 
292 	/* ok, this is not duplicate. try to
293 	load it and get class factory*/
294 	hmodule = LoadLibraryW(path);
295 	if (!hmodule) {
296 		ND_LOG_WARN(FI_LOG_CORE,
297 			   "ofi_nd_create_module: provider : %S, failed to load: %s\n",
298 			   path, ofi_nd_strerror(GetLastError(), 0));
299 		return NULL;
300 	}
301 
302 	unload = (can_unload_now_t)GetProcAddress(hmodule, "DllCanUnloadNow");
303 	getclass = (get_class_object_t)GetProcAddress(hmodule, "DllGetClassObject");
304 	if (!unload || !getclass) {
305 		ND_LOG_WARN(FI_LOG_CORE,
306 			   "ofi_nd_create_module: provider: %S, failed to import interface\n",
307 			   path);
308 		goto fn_noiface;
309 	}
310 
311 	module = &ofi_nd_infra.providers.modules[ofi_nd_infra.providers.count];
312 	ofi_nd_infra.providers.count++;
313 
314 	module->path = _wcsdup(path);
315 	module->module = hmodule;
316 	module->can_unload_now = unload;
317 	module->get_class_object = getclass;
318 
319 	return module;
320 
321 fn_noiface:
322 	FreeLibrary(hmodule);
323 	return NULL;
324 }
325 
ofi_nd_create_factory(const WSAPROTOCOL_INFOW * proto)326 static inline HRESULT ofi_nd_create_factory(const WSAPROTOCOL_INFOW* proto)
327 {
328 	wchar_t *path;
329 	struct module_t *module;
330 	IClassFactory* factory;
331 	HRESULT hr;
332 	struct factory_t *ftr;
333 
334 	assert(proto);
335 	assert(ofi_nd_is_valid_proto(proto));
336 	assert(ofi_nd_infra.class_factories.factory);
337 
338 	path = ofi_nd_get_provider_path(proto);
339 	if (path)
340 		ND_LOG_INFO(FI_LOG_CORE,
341 			    "ofi_nd_create_factory: provider " FI_ND_GUID_FORMAT " path: %S \n",
342 			    FI_ND_GUID_ARG(proto->ProviderId), path);
343 	else /* can't get provider path. just return */
344 		return S_OK;
345 
346 	module = ofi_nd_create_module(path);
347 	free(path);
348 	if (!module)
349 		return S_OK;
350 
351 	assert(module->get_class_object);
352 	hr = module->get_class_object(&proto->ProviderId, &IID_IClassFactory,
353 				      (void**)&factory);
354 	if (FAILED(hr))
355 		return hr;
356 
357 	ftr = &ofi_nd_infra.class_factories.factory[ofi_nd_infra.class_factories.count];
358 	ofi_nd_infra.class_factories.count++;
359 	ftr->class_factory = factory;
360 	ftr->module = module;
361 	ftr->protocol = *proto;
362 
363 	return S_OK;
364 }
365 
ofi_nd_adapter_cmp(const void * adapter1,const void * adapter2)366 static int ofi_nd_adapter_cmp(const void *adapter1, const void *adapter2)
367 {
368 	return ofi_nd_addr_cmp(&((struct adapter_t*)adapter1)->address,
369 			       &((struct adapter_t*)adapter2)->address);
370 }
371 
ofi_nd_create_adapter(void)372 static HRESULT ofi_nd_create_adapter(void)
373 {
374 	size_t addr_count = 0;
375 	HRESULT hr;
376 
377 	for (size_t i = 0; i < ofi_nd_infra.class_factories.count; i++) {
378 		struct factory_t *factory = &ofi_nd_infra.class_factories.factory[i];
379 		ULONG listsize = 0;
380 
381 		assert(factory->class_factory);
382 
383 		hr = factory->class_factory->lpVtbl->CreateInstance(factory->class_factory,
384 			NULL, &IID_IND2Provider, (void**)&factory->provider);
385 		if (FAILED(hr))
386 			return hr;
387 		hr = factory->provider->lpVtbl->QueryAddressList(factory->provider, NULL, &listsize);
388 		if (hr != ND_BUFFER_OVERFLOW)
389 			return hr;
390 		if (!listsize) {
391 			continue;
392 		}
393 
394 		factory->addr_list = (SOCKET_ADDRESS_LIST*)malloc(listsize);
395 		if (!factory->addr_list)
396 			return ND_NO_MEMORY;
397 
398 		hr = factory->provider->lpVtbl->QueryAddressList(factory->provider,
399 			factory->addr_list, &listsize);
400 		if (FAILED(hr))
401 			return hr;
402 
403 		for (INT j = 0; j < factory->addr_list->iAddressCount; j++) {
404 			if (ofi_nd_is_valid_addr(factory->addr_list->Address[j].lpSockaddr))
405 				addr_count++;
406 		}
407 	}
408 
409 	if (!addr_count)
410 		return E_NOINTERFACE;
411 
412 	ofi_nd_infra.adapters.adapter = (struct adapter_t*)malloc(addr_count * sizeof(*ofi_nd_infra.adapters.adapter));
413 	if (!ofi_nd_infra.adapters.adapter)
414 		return ND_NO_MEMORY;
415 
416 	/* put all available valid addresses into common array */
417 	for (size_t i = 0; i < ofi_nd_infra.class_factories.count; i++) {
418 		struct factory_t *factory = &ofi_nd_infra.class_factories.factory[i];
419 		for (INT j = 0; j < factory->addr_list->iAddressCount; j++) {
420 			if (ofi_nd_is_valid_addr(factory->addr_list->Address[j].lpSockaddr)) {
421 				struct adapter_t *adapter = &ofi_nd_infra.adapters.adapter[ofi_nd_infra.adapters.count];
422 				assert((int)sizeof(adapter->address) >= factory->addr_list->Address[j].iSockaddrLength);
423 				memcpy(&adapter->address,
424 				       factory->addr_list->Address[j].lpSockaddr,
425 				       factory->addr_list->Address[j].iSockaddrLength);
426 				adapter->factory = factory;
427 				ofi_nd_infra.adapters.count++;
428 			}
429 		}
430 	}
431 
432 	if (!ofi_nd_infra.adapters.count)
433 		return E_NOINTERFACE;
434 
435 	/* sort adapters by addresses to set IP4 addresses first. then remove
436 	   duplicates */
437 	qsort(ofi_nd_infra.adapters.adapter, ofi_nd_infra.adapters.count,
438 	      sizeof(struct adapter_t), ofi_nd_adapter_cmp);
439 	ofi_nd_infra.adapters.count = unique(ofi_nd_infra.adapters.adapter,
440 					     ofi_nd_infra.adapters.count,
441 					     sizeof(struct adapter_t), ofi_nd_adapter_cmp);
442 
443 	for (size_t i = 0; i < ofi_nd_infra.adapters.count; i++) {
444 		struct adapter_t *adapter = &ofi_nd_infra.adapters.adapter[i];
445 		struct factory_t *factory = adapter->factory;
446 		wchar_t *saddr;
447 		DWORD addrlen = 0;
448 		UINT64 id;
449 		int res;
450 
451 		assert(factory);
452 		assert(factory->provider);
453 
454 		assert(adapter->address.addr.sa_family == AF_INET ||
455 		       adapter->address.addr.sa_family == AF_INET6);
456 
457 		hr = factory->provider->lpVtbl->ResolveAddress(factory->provider,
458 			&adapter->address.addr,
459 			ofi_sizeofaddr(&adapter->address.addr), &id);
460 
461 		if (FAILED(hr))
462 			return hr;
463 
464 		hr = factory->provider->lpVtbl->OpenAdapter(factory->provider,
465 			&IID_IND2Adapter, id, (void**)&adapter->adapter);
466 		if (FAILED(hr))
467 			return hr;
468 
469 		ULONG linfo = sizeof(adapter->info);
470 		adapter->info.InfoVersion = ND_VERSION_2;
471 		hr = adapter->adapter->lpVtbl->Query(adapter->adapter, &adapter->info, &linfo);
472 		if (FAILED(hr) && hr == ND_BUFFER_OVERFLOW) {
473 			ND2_ADAPTER_INFO *info = (ND2_ADAPTER_INFO*)malloc(linfo);
474 			if (!info)
475 				return ND_NO_MEMORY;
476 			info->InfoVersion = ND_VERSION_2;
477 			hr = adapter->adapter->lpVtbl->Query(adapter->adapter, info, &linfo);
478 			if (FAILED(hr))
479 				return hr;
480 			adapter->info = *info;
481 			free(info);
482 		} else if (FAILED(hr)) {
483 			return hr;
484 		}
485 
486 		/* generate adapter's name */
487 		res = WSAAddressToStringW(&adapter->address.addr,
488 					     ofi_sizeofaddr(&adapter->address.addr),
489 					     NULL, NULL, &addrlen);
490 		if (res == SOCKET_ERROR && WSAGetLastError() == WSAEFAULT && addrlen) {
491 			saddr = (wchar_t*)malloc((addrlen + 1) * sizeof(*saddr));
492 			WSAAddressToStringW(&adapter->address.addr,
493 					    ofi_sizeofaddr(&adapter->address.addr),
494 					    NULL, saddr, &addrlen);
495 		}
496 		else {
497 			saddr = _wcsdup(L"unknown");
498 		}
499 
500 		asprintf((char**)&adapter->name, "netdir-%S-%S-%p",
501 			 ofi_nd_filename(adapter->factory->module->path),
502 			 saddr, adapter);
503 		free(saddr);
504 	}
505 
506 	return S_OK;
507 }
508 
ofi_nd_init(ofi_nd_adapter_cb_t cb)509 static HRESULT ofi_nd_init(ofi_nd_adapter_cb_t cb)
510 {
511 	DWORD proto_len = 0;
512 	HRESULT hr = ND_INTERNAL_ERROR;
513 	int i, protonum, err;
514 	size_t j, prov_count = 0;
515 	WSAPROTOCOL_INFOW *proto = 0;
516 
517 	memset(&ofi_nd_infra, 0, sizeof(ofi_nd_infra));
518 
519 	int ret = WSCEnumProtocols(NULL, NULL, &proto_len, &err);
520 	if (ret != SOCKET_ERROR || err != WSAENOBUFS) {
521 		hr = ND_NO_MEMORY;
522 		goto fn_exit;
523 	}
524 
525 	proto = (WSAPROTOCOL_INFOW*)(malloc(proto_len));
526 	if (!proto) {
527 		hr = ND_NO_MEMORY;
528 		goto fn_exit;
529 	}
530 
531 	protonum = WSCEnumProtocols(NULL, proto, &proto_len, &err);
532 	if (protonum == SOCKET_ERROR) {
533 		hr = ND_INTERNAL_ERROR;
534 		goto fn_protofail;
535 	}
536 
537 	/* calculating number of valid protocols. this number is used
538 	   as maximum of existing providers and class factories */
539 	for (i = 0; i < protonum; i++) {
540 		if (ofi_nd_is_valid_proto(&proto[i]))
541 			prov_count++;
542 	}
543 
544 	if (!prov_count) {
545 		hr = E_NOINTERFACE;
546 		goto fn_protofail;
547 	}
548 
549 	hr = ofi_nd_alloc_infra(prov_count);
550 	if (hr != S_OK)
551 		goto fn_protofail;
552 
553 	for (i = 0; i < protonum; i++) {
554 		if (ofi_nd_is_valid_proto(&proto[i]))
555 			ofi_nd_create_factory(&proto[i]);
556 	}
557 
558 	free(proto);
559 
560 	/* ok, factories are created, now list all available addresses, try to
561 	   create adapters & collect adapter's info */
562 	hr = ofi_nd_create_adapter();
563 	if (FAILED(hr))
564 		return hr;
565 
566 	/* free all interfaces. we don't need it right now */
567 	ofi_nd_release_infra();
568 
569 	/* now call cb function to create info's */
570 	for (j = 0; j < ofi_nd_infra.adapters.count; j++)
571 		cb(&ofi_nd_infra.adapters.adapter[j].info,
572 		   ofi_nd_infra.adapters.adapter[j].name);
573 
574 	return hr;
575 fn_protofail:
576 	free(proto);
577 fn_exit:
578 	return hr;
579 }
580 
581 /* we don't need here exclusive execution because this function
582  * is called from OFI init routine which is single thread */
ofi_nd_startup(ofi_nd_adapter_cb_t cb)583 HRESULT ofi_nd_startup(ofi_nd_adapter_cb_t cb)
584 {
585 	WSADATA data;
586 	HRESULT hr;
587 	int ret;
588 
589 	assert(cb);
590 
591 	if (ofi_nd_startup_done)
592 		return S_OK;
593 
594 	ND_LOG_INFO(FI_LOG_CORE, "ofi_nd_startup: starting initialization\n");
595 
596 	ret = WSAStartup(MAKEWORD(2, 2), &data);
597 	if (ret)
598 		return HRESULT_FROM_WIN32(ret);
599 
600 	ND_LOG_DEBUG(FI_LOG_CORE, "ofi_nd_startup: WSAStartup complete\n");
601 
602 	hr = ofi_nd_init(cb);
603 
604 	ofi_nd_startup_done = 1;
605 
606 	return hr;
607 }
608 
ofi_nd_shutdown(void)609 HRESULT ofi_nd_shutdown(void)
610 {
611 	if (!ofi_nd_startup_done)
612 		return S_OK;
613 
614 	ND_LOG_INFO(FI_LOG_CORE, "ofi_nd_shutdown: shutdown WSA\n");
615 
616 	ofi_nd_free_infra();
617 	ofi_nd_startup_done = 0;
618 
619 	return HRESULT_FROM_WIN32(WSACleanup());
620 }
621 
ofi_nd_lookup_adapter(const char * name,IND2Adapter ** adapter,struct sockaddr ** addr)622 int ofi_nd_lookup_adapter(const char *name, IND2Adapter **adapter, struct sockaddr** addr)
623 {
624 	size_t i;
625 
626 	assert(name);
627 	assert(adapter);
628 
629 	if (!ofi_nd_startup_done)
630 		return -FI_EOPBADSTATE;
631 
632 	for (i = 0; i < ofi_nd_infra.adapters.count; i++) {
633 		struct adapter_t *ada = &ofi_nd_infra.adapters.adapter[i];
634 		if (ada->name && !strcmp(ada->name, name)) {
635 			HRESULT hr;
636 			UINT64 adapter_id;
637 			IClassFactory* factory = NULL;
638 			IND2Provider *provider = NULL;
639 
640 			/* ok, we found good adapter. try to initialize it */
641 			if (ada->adapter) {
642 				*adapter = ada->adapter;
643 				*addr = &ada->address.addr;
644 				ada->adapter->lpVtbl->AddRef(ada->adapter);
645 				return FI_SUCCESS;
646 			}
647 
648 			assert(ada->factory);
649 			assert(ada->factory->module);
650 			assert(ada->factory->module->get_class_object);
651 
652 			hr = ada->factory->module->get_class_object(
653 				&ada->factory->protocol.ProviderId,
654 				&IID_IClassFactory,
655 				(void**)&factory);
656 			if (FAILED(hr))
657 				return H2F(hr);
658 			assert(factory);
659 
660 			hr = factory->lpVtbl->CreateInstance(factory, NULL,
661 							     &IID_IND2Provider,
662 							     (void**)&provider);
663 			factory->lpVtbl->Release(factory);
664 			if (FAILED(hr))
665 				return H2F(hr);
666 			assert(provider);
667 
668 			hr = provider->lpVtbl->ResolveAddress(provider, &ada->address.addr,
669 							      ofi_sizeofaddr(&ada->address.addr),
670 							      &adapter_id);
671 			if (FAILED(hr)) {
672 				provider->lpVtbl->Release(provider);
673 				return H2F(hr);
674 			}
675 
676 			hr = provider->lpVtbl->OpenAdapter(provider, &IID_IND2Adapter, adapter_id,
677 							   (void**)&ada->adapter);
678 			provider->lpVtbl->Release(provider);
679 			if (FAILED(hr))
680 				return H2F(hr);
681 
682 			*adapter = ada->adapter;
683 			*addr = &ada->address.addr;
684 			ada->adapter->lpVtbl->AddRef(ada->adapter);
685 
686 			return FI_SUCCESS;
687 		}
688 	}
689 
690 	return -FI_EINVAL;
691 }
692 
693 #endif /* _WIN32 */
694 
695