1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/ddi.h>
28 #include <sys/sunddi.h>
29 #include <sys/stropts.h>
30 #include <sys/stream.h>
31 #include <sys/strsun.h>
32 #include <sys/strsubr.h>
33 #include <sys/socket.h>
34 #include <sys/stat.h>
35 #include <net/if_arp.h>
36 #include <net/if_types.h>
37 #include <sys/file.h>
38 #include <sys/sockio.h>
39 #include <sys/pathname.h>
40 #include <inet/arp.h>
41 #include <sys/modctl.h>
42 
43 #include <sys/ib/mgt/ibcm/ibcm_arp.h>
44 
45 #include <sys/kstr.h>
46 #include <sys/tiuser.h>
47 #include <sys/t_kuser.h>
48 
49 extern char cmlog[];
50 
51 extern int ibcm_arp_pr_lookup(ibcm_arp_streams_t *ib_s, ibt_ip_addr_t *dst_addr,
52     ibt_ip_addr_t *src_addr, ibcm_arp_pr_comp_func_t func);
53 extern void ibcm_arp_pr_arp_ack(mblk_t *mp);
54 extern void ibcm_arp_prwqn_delete(ibcm_arp_prwqn_t *wqnp);
55 
56 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", datab))
57 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibt_ip_addr_s))
58 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_ip_t))
59 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_ibd_insts_t))
60 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_prwqn_t))
61 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", iocblk))
62 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", msgb))
63 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", queue))
64 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", sockaddr_in))
65 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", sockaddr_in6))
66 
67 int ibcm_printip = 0;
68 
69 /*
70  * Function:
71  *	ibcm_ip_print
72  * Input:
73  *	label		Arbitrary qualifying string
74  *	ipa		Pointer to IP Address to print
75  */
76 void
77 ibcm_ip_print(char *label, ibt_ip_addr_t *ipaddr)
78 {
79 	char    buf[INET6_ADDRSTRLEN];
80 
81 	if (ipaddr->family == AF_INET) {
82 		IBTF_DPRINTF_L2(cmlog, "%s: %s", label,
83 		    inet_ntop(AF_INET, &ipaddr->un.ip4addr, buf, sizeof (buf)));
84 	} else if (ipaddr->family == AF_INET6) {
85 		IBTF_DPRINTF_L2(cmlog, "%s: %s", label, inet_ntop(AF_INET6,
86 		    &ipaddr->un.ip6addr, buf, sizeof (buf)));
87 	} else {
88 		IBTF_DPRINTF_L2(cmlog, "%s: IP ADDR NOT SPECIFIED ", label);
89 	}
90 }
91 
92 /*
93  * ibcm_arp_get_ibaddr_cb
94  */
95 static int
96 ibcm_arp_get_ibaddr_cb(void *arg, int status)
97 {
98 	ibcm_arp_prwqn_t	*wqnp = (ibcm_arp_prwqn_t *)arg;
99 	ibcm_arp_streams_t	*ib_s = (ibcm_arp_streams_t *)wqnp->arg;
100 
101 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr_cb(ib_s: %p wqnp: %p)",
102 	    ib_s, wqnp);
103 
104 	mutex_enter(&ib_s->lock);
105 	ib_s->status = status;
106 	ib_s->done = B_TRUE;
107 
108 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr_cb: SGID %llX:%llX "
109 	    "DGID: %llX:%llX", wqnp->sgid.gid_prefix, wqnp->sgid.gid_guid,
110 	    wqnp->dgid.gid_prefix, wqnp->dgid.gid_guid);
111 
112 	/* lock is held by the caller. */
113 	cv_signal(&ib_s->cv);
114 	mutex_exit(&ib_s->lock);
115 	return (0);
116 }
117 
118 /*
119  * Lower read service procedure (messages coming back from arp/ip).
120  * Process messages based on queue type.
121  */
122 static int
123 ibcm_arp_lrsrv(queue_t *q)
124 {
125 	mblk_t *mp;
126 	ibcm_arp_streams_t *ib_s = q->q_ptr;
127 
128 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lrsrv(%p, ibd_s: 0x%p)", q, ib_s);
129 
130 	if (WR(q) == ib_s->arpqueue) {
131 		while (mp = getq(q)) {
132 			ibcm_arp_pr_arp_ack(mp);
133 		}
134 	}
135 
136 	return (0);
137 }
138 
139 /*
140  * Lower write service procedure.
141  * Used when lower streams are flow controlled.
142  */
143 static int
144 ibcm_arp_lwsrv(queue_t *q)
145 {
146 	mblk_t *mp;
147 
148 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lwsrv(%p)", q);
149 
150 	while (mp = getq(q)) {
151 		if (canputnext(q)) {
152 			putnext(q, mp);
153 		} else {
154 			(void) putbq(q, mp);
155 			qenable(q);
156 			break;
157 		}
158 	}
159 
160 	return (0);
161 }
162 
163 /*
164  * Lower read put procedure. Arp/ip messages come here.
165  */
166 static int
167 ibcm_arp_lrput(queue_t *q, mblk_t *mp)
168 {
169 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lrput(0x%p, db_type: %d)",
170 	    q, DB_TYPE(mp));
171 
172 	switch (DB_TYPE(mp)) {
173 		case M_FLUSH:
174 			/*
175 			 * Turn around
176 			 */
177 			if (*mp->b_rptr & FLUSHW) {
178 				*mp->b_rptr &= ~FLUSHR;
179 				qreply(q, mp);
180 				return (0);
181 			}
182 			freemsg(mp);
183 			break;
184 		case M_IOCACK:
185 		case M_IOCNAK:
186 		case M_DATA:
187 			/*
188 			 * This could be in interrupt context.
189 			 * Some of the ibt calls cannot be called in
190 			 * interrupt context, so
191 			 * put it in the queue and the message will be
192 			 * processed by service proccedure
193 			 */
194 			(void) putq(q, mp);
195 			qenable(q);
196 			break;
197 		default:
198 			IBTF_DPRINTF_L2(cmlog, "ibcm_arp_lrput: "
199 			    "got unknown msg <0x%x>\n", mp->b_datap->db_type);
200 			ASSERT(0);
201 			break;
202 	}
203 
204 	return (0);
205 }
206 
207 /*
208  * Streams write queue module info
209  */
210 static struct module_info ibcm_arp_winfo = {
211 	0,		/* module ID number */
212 	"ibcm",		/* module name */
213 	0,		/* min packet size */
214 	INFPSZ,
215 	49152,		/* STREAM queue high water mark -- 49152 */
216 	12		/* STREAM queue low water mark -- 12 */
217 };
218 
219 /*
220  * Streams lower write queue, for ibcm/ip requests.
221  */
222 static struct qinit ibcm_arp_lwinit = {
223 	NULL,		/* qi_putp */
224 	ibcm_arp_lwsrv,	/* qi_srvp */
225 	NULL,		/* qi_qopen */
226 	NULL,		/* qi_qclose */
227 	NULL,		/* qi_qadmin */
228 	&ibcm_arp_winfo,	/* module info */
229 	NULL,		/* module statistics struct */
230 	NULL,
231 	NULL,
232 	STRUIOT_NONE	/* stream uio type is standard uiomove() */
233 };
234 
235 /*
236  * Streams lower read queue: read reply messages from ibcm/ip.
237  */
238 static struct qinit ibcm_arp_lrinit = {
239 	ibcm_arp_lrput,	/* qi_putp */
240 	ibcm_arp_lrsrv,	/* qi_srvp */
241 	NULL,		/* qi_qopen */
242 	NULL,		/* qi_qclose */
243 	NULL,		/* qi_qadmin */
244 	&ibcm_arp_winfo,	/* module info */
245 	NULL,		/* module statistics struct */
246 	NULL,
247 	NULL,
248 	STRUIOT_NONE /* stream uio type is standard uiomove() */
249 };
250 
251 
252 static int
253 ibcm_arp_link_driver(ibcm_arp_streams_t *ib_s, char *path, queue_t **q,
254     vnode_t **dev_vp)
255 {
256 	struct stdata *dev_stp;
257 	vnode_t *vp;
258 	int error;
259 	queue_t *rq;
260 
261 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_link_driver: Enter: %s", path);
262 
263 	/* open the driver from inside the kernel */
264 	error = vn_open(path, UIO_SYSSPACE, FREAD|FWRITE, 0, &vp,
265 	    0, NULL);
266 	if (error) {
267 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_link_driver: "
268 		    "vn_open('%s') failed\n", path);
269 		return (error);
270 	}
271 	*dev_vp = vp;
272 
273 	dev_stp = vp->v_stream;
274 	*q = dev_stp->sd_wrq;
275 
276 	VN_HOLD(vp);
277 
278 	rq = RD(dev_stp->sd_wrq);
279 	RD(rq)->q_ptr = WR(rq)->q_ptr = ib_s;
280 	setq(rq, &ibcm_arp_lrinit, &ibcm_arp_lwinit, NULL, QMTSAFE,
281 	    SQ_CI|SQ_CO, B_FALSE);
282 
283 	return (0);
284 }
285 
286 extern struct qinit strdata;
287 extern struct qinit stwdata;
288 
289 /*
290  * Unlink ip, ibcm, icmp6 drivers
291  */
292 /* ARGSUSED */
293 static int
294 ibcm_arp_unlink_driver(queue_t **q, vnode_t **dev_vp)
295 {
296 	vnode_t *vp = *dev_vp;
297 	struct stdata *dev_stp = vp->v_stream;
298 	queue_t *wrq, *rq;
299 	int	rc;
300 
301 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_unlink_driver: Enter: 0x%p", q);
302 
303 	wrq = dev_stp->sd_wrq;
304 	rq = RD(wrq);
305 
306 	disable_svc(rq);
307 	wait_svc(rq);
308 	flushq(rq, FLUSHALL);
309 	flushq(WR(rq), FLUSHALL);
310 
311 	rq->q_ptr = wrq->q_ptr = dev_stp;
312 
313 	setq(rq, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_TRUE);
314 
315 	if ((rc = VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL)) != 0) {
316 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_unlink_driver: VOP_CLOSE "
317 		    "failed %d\n", rc);
318 	}
319 	VN_RELE(vp);
320 
321 	return (0);
322 }
323 
324 static int
325 ibcm_arp_unlink_drivers(ibcm_arp_streams_t *ib_s)
326 {
327 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_unlink_drivers(%p)", ib_s);
328 
329 	if (ib_s->arpqueue) {
330 		(void) ibcm_arp_unlink_driver(&ib_s->arpqueue, &ib_s->arp_vp);
331 	}
332 
333 	return (0);
334 }
335 
336 /*
337  * Link ip, ibtl drivers below ibtl
338  */
339 static int
340 ibcm_arp_link_drivers(ibcm_arp_streams_t *ib_s)
341 {
342 	int	rc;
343 
344 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_link_drivers(%p)", ib_s);
345 
346 	if ((rc = ibcm_arp_link_driver(ib_s, "/dev/arp", &ib_s->arpqueue,
347 	    &ib_s->arp_vp)) != 0) {
348 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_link_drivers: "
349 		    "ibcm_arp_link_driver failed: %d\n", rc);
350 		return (rc);
351 	}
352 
353 	return (0);
354 }
355 
356 ibt_status_t
357 ibcm_arp_get_ibaddr(ibt_ip_addr_t srcaddr, ibt_ip_addr_t destaddr,
358     ib_gid_t *sgid, ib_gid_t *dgid)
359 {
360 	ibcm_arp_streams_t	*ib_s;
361 	ibcm_arp_prwqn_t	*wqnp;
362 	int			ret = 0;
363 
364 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr(%p, %p, %p, %p)",
365 	    srcaddr, destaddr, sgid, dgid);
366 
367 	ib_s = (ibcm_arp_streams_t *)kmem_zalloc(sizeof (ibcm_arp_streams_t),
368 	    KM_SLEEP);
369 
370 	mutex_init(&ib_s->lock, NULL, MUTEX_DEFAULT, NULL);
371 	cv_init(&ib_s->cv, NULL, CV_DRIVER, NULL);
372 
373 	ret = ibcm_arp_link_drivers(ib_s);
374 	if (ret != 0) {
375 		IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: "
376 		    "ibcm_arp_link_drivers failed %d", ret);
377 		goto arp_ibaddr_error;
378 	}
379 
380 	mutex_enter(&ib_s->lock);
381 	ib_s->done = B_FALSE;
382 	mutex_exit(&ib_s->lock);
383 
384 	ret = ibcm_arp_pr_lookup(ib_s, &destaddr, &srcaddr,
385 	    ibcm_arp_get_ibaddr_cb);
386 
387 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: ibcm_arp_pr_lookup "
388 	    "returned: %d", ret);
389 	if (ret == 0) {
390 		mutex_enter(&ib_s->lock);
391 		while (ib_s->done != B_TRUE)
392 			cv_wait(&ib_s->cv, &ib_s->lock);
393 		mutex_exit(&ib_s->lock);
394 	}
395 
396 	(void) ibcm_arp_unlink_drivers(ib_s);
397 	mutex_enter(&ib_s->lock);
398 	wqnp = ib_s->wqnp;
399 	if (ib_s->status == 0) {
400 		if (sgid)
401 			*sgid = ib_s->wqnp->sgid;
402 		if (dgid)
403 			*dgid = ib_s->wqnp->dgid;
404 
405 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr: SGID: %llX:%llX"
406 		    " DGID: %llX:%llX",
407 		    ib_s->wqnp->sgid.gid_prefix, ib_s->wqnp->sgid.gid_guid,
408 		    ib_s->wqnp->dgid.gid_prefix, ib_s->wqnp->dgid.gid_guid);
409 
410 		ibcm_arp_prwqn_delete(wqnp);
411 	} else if (ret == 0) {
412 		/*
413 		 * We come here only when lookup has returned empty (failed)
414 		 * via callback routine - ibcm_arp_get_ibaddr_cb
415 		 * i.e. ib_s->status is non-zero, while ret is zero.
416 		 */
417 		if (wqnp)
418 			kmem_free(wqnp, sizeof (ibcm_arp_prwqn_t));
419 	}
420 	ret = ib_s->status;
421 	mutex_exit(&ib_s->lock);
422 
423 arp_ibaddr_error:
424 
425 	mutex_destroy(&ib_s->lock);
426 	cv_destroy(&ib_s->cv);
427 	kmem_free(ib_s, sizeof (ibcm_arp_streams_t));
428 
429 	if (ret)
430 		return (IBT_FAILURE);
431 	else
432 		return (IBT_SUCCESS);
433 }
434 
435 
436 /*
437  * Routine to get list of "local" IP-ADDR to GID/P_KEY mapping information.
438  * Optionally, if "gid" and/or "p_key" info are specified, then retrieve the
439  * IP-ADDR info for that attribute only.
440  */
441 
442 static ibcm_arp_ip_t *
443 ibcm_arp_ibd_gid2mac(ib_gid_t *gid, ib_pkey_t pkey, ibcm_arp_ibd_insts_t *ibdp)
444 {
445 	ibcm_arp_ip_t		*ipp;
446 	int			i;
447 
448 	for (i = 0, ipp = ibdp->ibcm_arp_ip; i < ibdp->ibcm_arp_ibd_cnt;
449 	    i++, ipp++) {
450 		if ((ipp->ip_port_gid.gid_prefix == gid->gid_prefix) &&
451 		    (ipp->ip_port_gid.gid_guid == gid->gid_guid)) {
452 			if (pkey) {
453 				if (ipp->ip_pkey == pkey)
454 					return (ipp);
455 				else
456 					continue;
457 			}
458 			return (ipp);
459 		}
460 	}
461 	return (NULL);
462 }
463 
464 static ibt_status_t
465 ibcm_arp_ibd_mac2gid(ibcm_arp_ibd_insts_t *ibdp, ibt_ip_addr_t *srcip,
466     ib_gid_t *sgid)
467 {
468 	ibcm_arp_ip_t		*ipp;
469 	int			i;
470 	boolean_t		found = B_FALSE;
471 
472 	for (i = 0, ipp = ibdp->ibcm_arp_ip; i < ibdp->ibcm_arp_ibd_cnt;
473 	    i++, ipp++) {
474 
475 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_ibd_mac2gid: GID %llX:%llX",
476 		    ipp->ip_port_gid.gid_prefix, ipp->ip_port_gid.gid_guid);
477 
478 		if (srcip->family == ipp->ip_inet_family) {
479 			if ((srcip->family == AF_INET) &&
480 			    (bcmp(&srcip->un.ip4addr, &ipp->ip_cm_sin.sin_addr,
481 			    sizeof (in_addr_t)) == 0)) {
482 				found = B_TRUE;
483 			} else if ((srcip->family == AF_INET6) &&
484 			    IN6_ARE_ADDR_EQUAL(&srcip->un.ip6addr,
485 			    &ipp->ip_cm_sin6.sin6_addr)) {
486 				found = B_TRUE;
487 			}
488 			if (found) {
489 				*sgid = ipp->ip_port_gid;
490 
491 				IBTF_DPRINTF_L4(cmlog, "ibcm_arp_ibd_mac2gid: "
492 				    "Found GID %llX:%llX", sgid->gid_prefix,
493 				    sgid->gid_guid);
494 				return (IBT_SUCCESS);
495 			}
496 		} else {
497 			IBTF_DPRINTF_L3(cmlog, "ibcm_arp_ibd_mac2gid: Different"
498 			    " family keep searching...");
499 		}
500 	}
501 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_ibd_mac2gid: Matching SRC info "
502 	    "NOT Found");
503 	return (IBT_SRC_IP_NOT_FOUND);
504 }
505 
506 static int
507 ibcm_arp_get_ibd_insts_cb(dev_info_t *dip, void *arg)
508 {
509 	ibcm_arp_ibd_insts_t *ibds = (ibcm_arp_ibd_insts_t *)arg;
510 	ibcm_arp_ip_t	*ipp;
511 	ib_pkey_t	pkey;
512 	uint8_t		port;
513 	ib_guid_t	hca_guid;
514 	ib_gid_t	port_gid;
515 
516 	if (i_ddi_devi_attached(dip) &&
517 	    (strcmp(ddi_node_name(dip), "ibport") == 0) &&
518 	    (strstr(ddi_get_name_addr(dip), "ipib") != NULL)) {
519 
520 		if (ibds->ibcm_arp_ibd_cnt >= ibds->ibcm_arp_ibd_alloc) {
521 			ibcm_arp_ip_t	*tmp = NULL;
522 			uint8_t		new_count;
523 
524 			new_count = ibds->ibcm_arp_ibd_alloc +
525 			    IBCM_ARP_IBD_INSTANCES;
526 
527 			tmp = (ibcm_arp_ip_t *)kmem_zalloc(
528 			    new_count * sizeof (ibcm_arp_ip_t), KM_SLEEP);
529 			bcopy(ibds->ibcm_arp_ip, tmp,
530 			    ibds->ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t));
531 			kmem_free(ibds->ibcm_arp_ip,
532 			    ibds->ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t));
533 			ibds->ibcm_arp_ibd_alloc = new_count;
534 			ibds->ibcm_arp_ip = tmp;
535 		}
536 
537 		if (((hca_guid = ddi_prop_get_int64(DDI_DEV_T_ANY, dip, 0,
538 		    "hca-guid", 0)) == 0) ||
539 		    ((port = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
540 		    "port-number", 0)) == 0) ||
541 		    (ibt_get_port_state_byguid(hca_guid, port, &port_gid,
542 		    NULL) != IBT_SUCCESS) ||
543 		    ((pkey = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
544 		    "port-pkey", IB_PKEY_INVALID_LIMITED)) <=
545 		    IB_PKEY_INVALID_FULL)) {
546 			return (DDI_WALK_CONTINUE);
547 		}
548 
549 		ipp = &ibds->ibcm_arp_ip[ibds->ibcm_arp_ibd_cnt];
550 		ipp->ip_inst = ddi_get_instance(dip);
551 		ipp->ip_pkey = pkey;
552 		ipp->ip_hca_guid = hca_guid;
553 		ipp->ip_port_gid = port_gid;
554 		ibds->ibcm_arp_ibd_cnt++;
555 	}
556 	return (DDI_WALK_CONTINUE);
557 }
558 
559 static void
560 ibcm_arp_get_ibd_insts(ibcm_arp_ibd_insts_t *ibds)
561 {
562 	ddi_walk_devs(ddi_root_node(), ibcm_arp_get_ibd_insts_cb, ibds);
563 }
564 
565 /*
566  * Issue an ioctl down to IP.  There are several similar versions of this
567  * function (e.g., rpcib_do_ip_ioctl()); clearly a utility routine is needed.
568  */
569 static int
570 ibcm_do_ip_ioctl(int cmd, int len, void *arg)
571 {
572 	vnode_t *kvp;
573 	TIUSER  *tiptr;
574 	struct  strioctl iocb;
575 	int	err = 0;
576 
577 	if (lookupname("/dev/udp", UIO_SYSSPACE, FOLLOW, NULLVPP, &kvp) != 0)
578 		return (EPROTO);
579 
580 	if (t_kopen(NULL, kvp->v_rdev, FREAD|FWRITE, &tiptr, CRED()) != 0) {
581 		VN_RELE(kvp);
582 		return (EPROTO);
583 	}
584 
585 	iocb.ic_cmd = cmd;
586 	iocb.ic_timout = 0;
587 	iocb.ic_len = len;
588 	iocb.ic_dp = (caddr_t)arg;
589 	err = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb);
590 	(void) t_kclose(tiptr, 0);
591 	VN_RELE(kvp);
592 	return (err);
593 }
594 
595 /*
596  * Issue an SIOCGLIFCONF down to IP and return the result in `lifcp'.
597  * lifcp->lifc_buf is dynamically allocated to be *bufsizep bytes.
598  */
599 static int
600 ibcm_do_lifconf(struct lifconf *lifcp, uint_t *bufsizep, sa_family_t family_loc)
601 {
602 	int err;
603 	struct lifnum lifn;
604 
605 	bzero(&lifn, sizeof (struct lifnum));
606 	lifn.lifn_family = family_loc;
607 
608 	err = ibcm_do_ip_ioctl(SIOCGLIFNUM, sizeof (struct lifnum), &lifn);
609 	if (err != 0)
610 		return (err);
611 
612 	IBTF_DPRINTF_L4(cmlog, "ibcm_do_lifconf: Family %d, lifn_count %d",
613 	    family_loc, lifn.lifn_count);
614 	/*
615 	 * Pad the interface count to account for additional interfaces that
616 	 * may have been configured between the SIOCGLIFNUM and SIOCGLIFCONF.
617 	 */
618 	lifn.lifn_count += 4;
619 
620 	bzero(lifcp, sizeof (struct lifconf));
621 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lifcp))
622 	lifcp->lifc_family = family_loc;
623 	lifcp->lifc_len = *bufsizep = lifn.lifn_count * sizeof (struct lifreq);
624 	lifcp->lifc_buf = kmem_zalloc(*bufsizep, KM_SLEEP);
625 
626 	err = ibcm_do_ip_ioctl(SIOCGLIFCONF, sizeof (struct lifconf), lifcp);
627 	if (err != 0) {
628 		kmem_free(lifcp->lifc_buf, *bufsizep);
629 		return (err);
630 	}
631 	return (0);
632 }
633 
634 /*
635  * Fill in `ibds' with IP addresses tied to IFT_IB IP interfaces.  Returns
636  * B_TRUE if at least one address was filled in.
637  */
638 static boolean_t
639 ibcm_arp_get_ibd_ipaddr(ibcm_arp_ibd_insts_t *ibds, sa_family_t family_loc)
640 {
641 	int i, nifs, naddr = 0;
642 	uint_t bufsize;
643 	struct lifconf lifc;
644 	struct lifreq *lifrp;
645 	ibcm_arp_ip_t *ipp;
646 
647 	if (ibcm_do_lifconf(&lifc, &bufsize, family_loc) != 0)
648 		return (B_FALSE);
649 
650 	nifs = lifc.lifc_len / sizeof (struct lifreq);
651 
652 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibd_ipaddr: Family %d, nifs %d",
653 	    family_loc, nifs);
654 
655 	for (lifrp = lifc.lifc_req, i = 0;
656 	    i < nifs && naddr < ibds->ibcm_arp_ibd_cnt; i++, lifrp++) {
657 		if (lifrp->lifr_type != IFT_IB)
658 			continue;
659 
660 		ipp = &ibds->ibcm_arp_ip[naddr];
661 		switch (lifrp->lifr_addr.ss_family) {
662 		case AF_INET:
663 			ipp->ip_inet_family = AF_INET;
664 			bcopy(&lifrp->lifr_addr, &ipp->ip_cm_sin,
665 			    sizeof (struct sockaddr_in));
666 			naddr++;
667 			break;
668 		case AF_INET6:
669 			ipp->ip_inet_family = AF_INET6;
670 			bcopy(&lifrp->lifr_addr, &ipp->ip_cm_sin6,
671 			    sizeof (struct sockaddr_in6));
672 			naddr++;
673 			break;
674 		}
675 	}
676 
677 	kmem_free(lifc.lifc_buf, bufsize);
678 	return (naddr > 0);
679 }
680 
681 ibt_status_t
682 ibcm_arp_get_ibds(ibcm_arp_ibd_insts_t *ibdp, sa_family_t family_loc)
683 {
684 #ifdef DEBUG
685 	int i;
686 #endif
687 
688 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds(%p)", ibdp);
689 
690 	ibcm_arp_get_ibd_insts(ibdp);
691 
692 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibds: Found %d ibd instances",
693 	    ibdp->ibcm_arp_ibd_cnt);
694 
695 	if (ibdp->ibcm_arp_ibd_cnt == 0)
696 		return (IBT_SRC_IP_NOT_FOUND);
697 
698 	/* Get the IP addresses of active ports. */
699 	if (!ibcm_arp_get_ibd_ipaddr(ibdp, family_loc)) {
700 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_ibds: failed to get "
701 		    "ibd instance: IBT_SRC_IP_NOT_FOUND");
702 		return (IBT_SRC_IP_NOT_FOUND);
703 	}
704 
705 #ifdef DEBUG
706 	for (i = 0; i < ibdp->ibcm_arp_ibd_cnt; i++) {
707 		char    my_buf[INET6_ADDRSTRLEN];
708 		ibcm_arp_ip_t	*aip = &ibdp->ibcm_arp_ip[i];
709 
710 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: ibd[%d]: Family %d "
711 		    "Instance %d PKey 0x%lX \n HCAGUID 0x%llX SGID %llX:%llX",
712 		    i, aip->ip_inet_family, aip->ip_inst, aip->ip_pkey,
713 		    aip->ip_hca_guid, aip->ip_port_gid.gid_prefix,
714 		    aip->ip_port_gid.gid_guid);
715 		if (aip->ip_inet_family == AF_INET) {
716 			IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: IPV4: %s",
717 			    inet_ntop(AF_INET, &aip->ip_cm_sin.sin_addr, my_buf,
718 			    sizeof (my_buf)));
719 		} else if (aip->ip_inet_family == AF_INET6) {
720 			IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: IPV6: %s",
721 			    inet_ntop(AF_INET6, &aip->ip_cm_sin6.sin6_addr,
722 			    my_buf, sizeof (my_buf)));
723 		} else {
724 			IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_ibds: Unknown "
725 			    "Family %d", aip->ip_inet_family);
726 		}
727 	}
728 #endif
729 
730 	return (IBT_SUCCESS);
731 }
732 
733 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibtl_cm_port_list_t))
734 
735 ibt_status_t
736 ibcm_arp_get_srcip_plist(ibt_ip_path_attr_t *ipattr, ibt_path_flags_t flags,
737     ibtl_cm_port_list_t **port_list_p)
738 {
739 	ibt_path_attr_t		attr;
740 	ibt_status_t		ret;
741 	ibcm_arp_ibd_insts_t	ibds;
742 	ibcm_arp_ip_t		*ipp;
743 	ibtl_cm_port_list_t	*plistp;
744 	ib_gid_t		sgid;
745 	sa_family_t		family_interested = AF_UNSPEC;
746 
747 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist(%p, %llX)",
748 	    ipattr, flags);
749 
750 	if (ipattr->ipa_src_ip.family != AF_UNSPEC)
751 		family_interested = ipattr->ipa_src_ip.family;
752 	else
753 		family_interested = ipattr->ipa_dst_ip[0].family;
754 
755 	sgid.gid_prefix = sgid.gid_guid = 0;
756 	bzero(&ibds, sizeof (ibcm_arp_ibd_insts_t));
757 	ibds.ibcm_arp_ibd_alloc = IBCM_ARP_IBD_INSTANCES;
758 	ibds.ibcm_arp_ibd_cnt = 0;
759 	ibds.ibcm_arp_ip = (ibcm_arp_ip_t *)kmem_zalloc(
760 	    ibds.ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t), KM_SLEEP);
761 
762 	ret = ibcm_arp_get_ibds(&ibds, family_interested);
763 	if (ret != IBT_SUCCESS) {
764 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_srcip_plist: "
765 		    "ibcm_arp_get_ibds failed : 0x%x", ret);
766 		goto srcip_plist_end;
767 	}
768 
769 	if (ipattr->ipa_src_ip.family != AF_UNSPEC) {
770 		ret = ibcm_arp_ibd_mac2gid(&ibds, &ipattr->ipa_src_ip, &sgid);
771 		if (ret != IBT_SUCCESS) {
772 			IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_srcip_plist: "
773 			    "SGID for the specified SRCIP Not found %X", ret);
774 			goto srcip_plist_end;
775 		}
776 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist: SGID "
777 		    "%llX:%llX", sgid.gid_prefix, sgid.gid_guid);
778 	}
779 
780 	bzero(&attr, sizeof (ibt_path_attr_t));
781 	attr.pa_hca_guid = ipattr->ipa_hca_guid;
782 	attr.pa_hca_port_num = ipattr->ipa_hca_port_num;
783 	attr.pa_sgid = sgid;
784 	bcopy(&ipattr->ipa_mtu,  &attr.pa_mtu, sizeof (ibt_mtu_req_t));
785 	bcopy(&ipattr->ipa_srate,  &attr.pa_srate, sizeof (ibt_srate_req_t));
786 	bcopy(&ipattr->ipa_pkt_lt,  &attr.pa_pkt_lt, sizeof (ibt_pkt_lt_req_t));
787 
788 	ret = ibtl_cm_get_active_plist(&attr, flags, port_list_p);
789 	if (ret == IBT_SUCCESS) {
790 		int		i;
791 		uint8_t		cnt;
792 		boolean_t	no_srcip_configured = B_FALSE;
793 		uint8_t		no_srcip_cnt = 0;
794 
795 		plistp = port_list_p[0];
796 		cnt = plistp->p_count;
797 		for (i = 0; i < cnt; i++, plistp++) {
798 			ipp = ibcm_arp_ibd_gid2mac(&plistp->p_sgid, 0, &ibds);
799 			if ((ipp == NULL) ||
800 			    (ipp->ip_inet_family == AF_UNSPEC)) {
801 				plistp->p_src_ip.family = AF_UNSPEC;
802 				no_srcip_configured = B_TRUE;
803 				no_srcip_cnt++;
804 				IBTF_DPRINTF_L3(cmlog,
805 				    "ibcm_arp_get_srcip_plist: SrcIP NOT "
806 				    "Configured for GID %llX:%llX",
807 				    plistp->p_sgid.gid_prefix,
808 				    plistp->p_sgid.gid_guid);
809 			} else {
810 				IBTF_DPRINTF_L4(cmlog,
811 				    "ibcm_arp_get_srcip_plist: GID %llX:%llX",
812 				    plistp->p_sgid.gid_prefix,
813 				    plistp->p_sgid.gid_guid);
814 				if (ipp->ip_inet_family == AF_INET) {
815 					plistp->p_src_ip.family = AF_INET;
816 					bcopy(&ipp->ip_cm_sin.sin_addr,
817 					    &plistp->p_src_ip.un.ip4addr,
818 					    sizeof (in_addr_t));
819 
820 				} else if (ipp->ip_inet_family == AF_INET6) {
821 					plistp->p_src_ip.family = AF_INET6;
822 					bcopy(&ipp->ip_cm_sin6.sin6_addr,
823 					    &plistp->p_src_ip.un.ip6addr,
824 					    sizeof (in6_addr_t));
825 				}
826 				IBCM_PRINT_IP("ibcm_arp_get_srcip_plist: "
827 				    "IP Addr is:", &plistp->p_src_ip);
828 			}
829 		}
830 		if (no_srcip_configured) {
831 			ibtl_cm_port_list_t	*n_plistp, *tmp_n_plistp;
832 			uint8_t			new_cnt;
833 
834 			new_cnt = cnt - no_srcip_cnt;
835 
836 			/*
837 			 * Looks like some of the SRC GID we found have no
838 			 * IP ADDR configured, so remove these entries from
839 			 * our list.
840 			 */
841 			plistp = port_list_p[0];
842 			IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist: "
843 			    "Only %d SGID (%d/%d) have SrcIP Configured",
844 			    new_cnt, no_srcip_cnt, cnt);
845 			if (new_cnt) {
846 				/* Allocate Memory to hold Src Point info. */
847 				n_plistp = kmem_zalloc(new_cnt *
848 				    sizeof (ibtl_cm_port_list_t), KM_SLEEP);
849 
850 				tmp_n_plistp = n_plistp;
851 				for (i = 0; i < cnt; i++, plistp++) {
852 					if (plistp->p_src_ip.family ==
853 					    AF_UNSPEC)
854 						continue;
855 
856 					bcopy(plistp, n_plistp,
857 					    sizeof (ibtl_cm_port_list_t));
858 					n_plistp->p_count = new_cnt;
859 					n_plistp++;
860 				}
861 				plistp = port_list_p[0];
862 				*port_list_p = tmp_n_plistp;
863 			} else {
864 				/*
865 				 * All entries we have, do not have IP-Addr
866 				 * configured so return empty hand.
867 				 */
868 				IBTF_DPRINTF_L2(cmlog,
869 				    "ibcm_arp_get_srcip_plist: None of SGID "
870 				    "found have SrcIP Configured");
871 				*port_list_p = NULL;
872 				ret = IBT_SRC_IP_NOT_FOUND;
873 			}
874 			IBTF_DPRINTF_L4(cmlog, "FREE OLD list %p, NEW list is "
875 			    "%p - %p", plistp, port_list_p, *port_list_p);
876 			kmem_free(plistp, cnt * sizeof (ibtl_cm_port_list_t));
877 		}
878 	}
879 
880 srcip_plist_end:
881 	if (ibds.ibcm_arp_ip)
882 		kmem_free(ibds.ibcm_arp_ip, ibds.ibcm_arp_ibd_alloc *
883 		    sizeof (ibcm_arp_ip_t));
884 
885 	return (ret);
886 }
887 /* Routines for warlock */
888 
889 /* ARGSUSED */
890 static int
891 ibcm_arp_dummy_ibaddr_hdl(void *arg, int status)
892 {
893 	ibcm_arp_prwqn_t		dummy_wqn1;
894 	ibcm_arp_prwqn_t		dummy_wqn2;
895 
896 	dummy_wqn1.func = ibcm_arp_get_ibaddr_cb;
897 	dummy_wqn2.func = ibcm_arp_dummy_ibaddr_hdl;
898 
899 	IBTF_DPRINTF_L5(cmlog, "ibcm_arp_dummy_ibaddr_hdl: "
900 	    "dummy_wqn1.func %p %p", dummy_wqn1.func, dummy_wqn2.func);
901 
902 	return (0);
903 }
904