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 	int			ret = 0;
362 
363 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr(%p, %p, %p, %p)",
364 	    srcaddr, destaddr, sgid, dgid);
365 
366 	ib_s = (ibcm_arp_streams_t *)kmem_zalloc(sizeof (ibcm_arp_streams_t),
367 	    KM_SLEEP);
368 
369 	mutex_init(&ib_s->lock, NULL, MUTEX_DEFAULT, NULL);
370 	cv_init(&ib_s->cv, NULL, CV_DRIVER, NULL);
371 
372 	ret = ibcm_arp_link_drivers(ib_s);
373 	if (ret != 0) {
374 		IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: "
375 		    "ibcm_arp_link_drivers failed %d", ret);
376 		goto arp_ibaddr_error;
377 	}
378 
379 	mutex_enter(&ib_s->lock);
380 	ib_s->done = B_FALSE;
381 	mutex_exit(&ib_s->lock);
382 
383 	ret = ibcm_arp_pr_lookup(ib_s, &destaddr, &srcaddr,
384 	    ibcm_arp_get_ibaddr_cb);
385 
386 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: ibcm_arp_pr_lookup "
387 	    "returned: %d", ret);
388 	if (ret == 0) {
389 		mutex_enter(&ib_s->lock);
390 		while (ib_s->done != B_TRUE)
391 			cv_wait(&ib_s->cv, &ib_s->lock);
392 		mutex_exit(&ib_s->lock);
393 	}
394 
395 	(void) ibcm_arp_unlink_drivers(ib_s);
396 	mutex_enter(&ib_s->lock);
397 	ret = ib_s->status;
398 	if (ret == 0) {
399 		ibcm_arp_prwqn_t *wqnp = ib_s->wqnp;
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 		mutex_exit(&ib_s->lock);
411 		ibcm_arp_prwqn_delete(wqnp);
412 		mutex_enter(&ib_s->lock);
413 	}
414 	mutex_exit(&ib_s->lock);
415 
416 arp_ibaddr_error:
417 
418 	mutex_destroy(&ib_s->lock);
419 	cv_destroy(&ib_s->cv);
420 	kmem_free(ib_s, sizeof (ibcm_arp_streams_t));
421 
422 	if (ret)
423 		return (IBT_FAILURE);
424 	else
425 		return (IBT_SUCCESS);
426 }
427 
428 
429 /*
430  * Routine to get list of "local" IP-ADDR to GID/P_KEY mapping information.
431  * Optionally, if "gid" and/or "p_key" info are specified, then retrieve the
432  * IP-ADDR info for that attribute only.
433  */
434 
435 static ibcm_arp_ip_t *
436 ibcm_arp_ibd_gid2mac(ib_gid_t *gid, ib_pkey_t pkey, ibcm_arp_ibd_insts_t *ibdp)
437 {
438 	ibcm_arp_ip_t		*ipp;
439 	int			i;
440 
441 	for (i = 0, ipp = ibdp->ibcm_arp_ip; i < ibdp->ibcm_arp_ibd_cnt;
442 	    i++, ipp++) {
443 		if ((ipp->ip_port_gid.gid_prefix == gid->gid_prefix) &&
444 		    (ipp->ip_port_gid.gid_guid == gid->gid_guid)) {
445 			if (pkey) {
446 				if (ipp->ip_pkey == pkey)
447 					return (ipp);
448 				else
449 					continue;
450 			}
451 			return (ipp);
452 		}
453 	}
454 	return (NULL);
455 }
456 
457 static ibt_status_t
458 ibcm_arp_ibd_mac2gid(ibcm_arp_ibd_insts_t *ibdp, ibt_ip_addr_t *srcip,
459     ib_gid_t *sgid)
460 {
461 	ibcm_arp_ip_t		*ipp;
462 	int			i;
463 	boolean_t		found = B_FALSE;
464 
465 	for (i = 0, ipp = ibdp->ibcm_arp_ip; i < ibdp->ibcm_arp_ibd_cnt;
466 	    i++, ipp++) {
467 
468 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_ibd_mac2gid: GID %llX:%llX",
469 		    ipp->ip_port_gid.gid_prefix, ipp->ip_port_gid.gid_guid);
470 
471 		if (srcip->family == ipp->ip_inet_family) {
472 			if ((srcip->family == AF_INET) &&
473 			    (bcmp(&srcip->un.ip4addr, &ipp->ip_cm_sin.sin_addr,
474 			    sizeof (in_addr_t)) == 0)) {
475 				found = B_TRUE;
476 			} else if ((srcip->family == AF_INET6) &&
477 			    IN6_ARE_ADDR_EQUAL(&srcip->un.ip6addr,
478 			    &ipp->ip_cm_sin6.sin6_addr)) {
479 				found = B_TRUE;
480 			}
481 			if (found) {
482 				*sgid = ipp->ip_port_gid;
483 
484 				IBTF_DPRINTF_L4(cmlog, "ibcm_arp_ibd_mac2gid: "
485 				    "Found GID %llX:%llX", sgid->gid_prefix,
486 				    sgid->gid_guid);
487 				return (IBT_SUCCESS);
488 			}
489 		} else {
490 			IBTF_DPRINTF_L3(cmlog, "ibcm_arp_ibd_mac2gid: Different"
491 			    " family keep searching...");
492 		}
493 	}
494 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_ibd_mac2gid: Matching SRC info "
495 	    "NOT Found");
496 	return (IBT_SRC_IP_NOT_FOUND);
497 }
498 
499 static int
500 ibcm_arp_get_ibd_insts_cb(dev_info_t *dip, void *arg)
501 {
502 	ibcm_arp_ibd_insts_t *ibds = (ibcm_arp_ibd_insts_t *)arg;
503 	ibcm_arp_ip_t	*ipp;
504 	ib_pkey_t	pkey;
505 	uint8_t		port;
506 	ib_guid_t	hca_guid;
507 	ib_gid_t	port_gid;
508 
509 	if (i_ddi_devi_attached(dip) &&
510 	    (strcmp(ddi_node_name(dip), "ibport") == 0) &&
511 	    (strstr(ddi_get_name_addr(dip), "ipib") != NULL)) {
512 
513 		if (ibds->ibcm_arp_ibd_cnt >= ibds->ibcm_arp_ibd_alloc) {
514 			ibcm_arp_ip_t	*tmp = NULL;
515 			uint8_t		new_count;
516 
517 			new_count = ibds->ibcm_arp_ibd_alloc +
518 			    IBCM_ARP_IBD_INSTANCES;
519 
520 			tmp = (ibcm_arp_ip_t *)kmem_zalloc(
521 			    new_count * sizeof (ibcm_arp_ip_t), KM_SLEEP);
522 			bcopy(ibds->ibcm_arp_ip, tmp,
523 			    ibds->ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t));
524 			kmem_free(ibds->ibcm_arp_ip,
525 			    ibds->ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t));
526 			ibds->ibcm_arp_ibd_alloc = new_count;
527 			ibds->ibcm_arp_ip = tmp;
528 		}
529 
530 		if (((hca_guid = ddi_prop_get_int64(DDI_DEV_T_ANY, dip, 0,
531 		    "hca-guid", 0)) == 0) ||
532 		    ((port = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
533 		    "port-number", 0)) == 0) ||
534 		    (ibt_get_port_state_byguid(hca_guid, port, &port_gid,
535 		    NULL) != IBT_SUCCESS) ||
536 		    ((pkey = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
537 		    "port-pkey", IB_PKEY_INVALID_LIMITED)) <=
538 		    IB_PKEY_INVALID_FULL)) {
539 			return (DDI_WALK_CONTINUE);
540 		}
541 
542 		ipp = &ibds->ibcm_arp_ip[ibds->ibcm_arp_ibd_cnt];
543 		ipp->ip_inst = ddi_get_instance(dip);
544 		ipp->ip_pkey = pkey;
545 		ipp->ip_hca_guid = hca_guid;
546 		ipp->ip_port_gid = port_gid;
547 		ibds->ibcm_arp_ibd_cnt++;
548 	}
549 	return (DDI_WALK_CONTINUE);
550 }
551 
552 static void
553 ibcm_arp_get_ibd_insts(ibcm_arp_ibd_insts_t *ibds)
554 {
555 	ddi_walk_devs(ddi_root_node(), ibcm_arp_get_ibd_insts_cb, ibds);
556 }
557 
558 /*
559  * Issue an ioctl down to IP.  There are several similar versions of this
560  * function (e.g., rpcib_do_ip_ioctl()); clearly a utility routine is needed.
561  */
562 static int
563 ibcm_do_ip_ioctl(int cmd, int len, void *arg)
564 {
565 	vnode_t *kvp;
566 	TIUSER  *tiptr;
567 	struct  strioctl iocb;
568 	int	err = 0;
569 
570 	if (lookupname("/dev/udp", UIO_SYSSPACE, FOLLOW, NULLVPP, &kvp) != 0)
571 		return (EPROTO);
572 
573 	if (t_kopen(NULL, kvp->v_rdev, FREAD|FWRITE, &tiptr, CRED()) != 0) {
574 		VN_RELE(kvp);
575 		return (EPROTO);
576 	}
577 
578 	iocb.ic_cmd = cmd;
579 	iocb.ic_timout = 0;
580 	iocb.ic_len = len;
581 	iocb.ic_dp = (caddr_t)arg;
582 	err = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb);
583 	(void) t_kclose(tiptr, 0);
584 	VN_RELE(kvp);
585 	return (err);
586 }
587 
588 /*
589  * Issue an SIOCGLIFCONF down to IP and return the result in `lifcp'.
590  * lifcp->lifc_buf is dynamically allocated to be *bufsizep bytes.
591  */
592 static int
593 ibcm_do_lifconf(struct lifconf *lifcp, uint_t *bufsizep, sa_family_t family_loc)
594 {
595 	int err;
596 	struct lifnum lifn;
597 
598 	bzero(&lifn, sizeof (struct lifnum));
599 	lifn.lifn_family = family_loc;
600 
601 	err = ibcm_do_ip_ioctl(SIOCGLIFNUM, sizeof (struct lifnum), &lifn);
602 	if (err != 0)
603 		return (err);
604 
605 	IBTF_DPRINTF_L4(cmlog, "ibcm_do_lifconf: Family %d, lifn_count %d",
606 	    family_loc, lifn.lifn_count);
607 	/*
608 	 * Pad the interface count to account for additional interfaces that
609 	 * may have been configured between the SIOCGLIFNUM and SIOCGLIFCONF.
610 	 */
611 	lifn.lifn_count += 4;
612 
613 	bzero(lifcp, sizeof (struct lifconf));
614 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lifcp))
615 	lifcp->lifc_family = family_loc;
616 	lifcp->lifc_len = *bufsizep = lifn.lifn_count * sizeof (struct lifreq);
617 	lifcp->lifc_buf = kmem_zalloc(*bufsizep, KM_SLEEP);
618 
619 	err = ibcm_do_ip_ioctl(SIOCGLIFCONF, sizeof (struct lifconf), lifcp);
620 	if (err != 0) {
621 		kmem_free(lifcp->lifc_buf, *bufsizep);
622 		return (err);
623 	}
624 	return (0);
625 }
626 
627 /*
628  * Fill in `ibds' with IP addresses tied to IFT_IB IP interfaces.  Returns
629  * B_TRUE if at least one address was filled in.
630  */
631 static boolean_t
632 ibcm_arp_get_ibd_ipaddr(ibcm_arp_ibd_insts_t *ibds, sa_family_t family_loc)
633 {
634 	int i, nifs, naddr = 0;
635 	uint_t bufsize;
636 	struct lifconf lifc;
637 	struct lifreq *lifrp;
638 	ibcm_arp_ip_t *ipp;
639 
640 	if (ibcm_do_lifconf(&lifc, &bufsize, family_loc) != 0)
641 		return (B_FALSE);
642 
643 	nifs = lifc.lifc_len / sizeof (struct lifreq);
644 
645 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibd_ipaddr: Family %d, nifs %d",
646 	    family_loc, nifs);
647 
648 	for (lifrp = lifc.lifc_req, i = 0;
649 	    i < nifs && naddr < ibds->ibcm_arp_ibd_cnt; i++, lifrp++) {
650 		if (lifrp->lifr_type != IFT_IB)
651 			continue;
652 
653 		ipp = &ibds->ibcm_arp_ip[naddr];
654 		switch (lifrp->lifr_addr.ss_family) {
655 		case AF_INET:
656 			ipp->ip_inet_family = AF_INET;
657 			bcopy(&lifrp->lifr_addr, &ipp->ip_cm_sin,
658 			    sizeof (struct sockaddr_in));
659 			naddr++;
660 			break;
661 		case AF_INET6:
662 			ipp->ip_inet_family = AF_INET6;
663 			bcopy(&lifrp->lifr_addr, &ipp->ip_cm_sin6,
664 			    sizeof (struct sockaddr_in6));
665 			naddr++;
666 			break;
667 		}
668 	}
669 
670 	kmem_free(lifc.lifc_buf, bufsize);
671 	return (naddr > 0);
672 }
673 
674 ibt_status_t
675 ibcm_arp_get_ibds(ibcm_arp_ibd_insts_t *ibdp, sa_family_t family_loc)
676 {
677 #ifdef DEBUG
678 	int i;
679 #endif
680 
681 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds(%p)", ibdp);
682 
683 	ibcm_arp_get_ibd_insts(ibdp);
684 
685 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibds: Found %d ibd instances",
686 	    ibdp->ibcm_arp_ibd_cnt);
687 
688 	if (ibdp->ibcm_arp_ibd_cnt == 0)
689 		return (IBT_SRC_IP_NOT_FOUND);
690 
691 	/* Get the IP addresses of active ports. */
692 	if (!ibcm_arp_get_ibd_ipaddr(ibdp, family_loc)) {
693 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_ibds: failed to get "
694 		    "ibd instance: IBT_SRC_IP_NOT_FOUND");
695 		return (IBT_SRC_IP_NOT_FOUND);
696 	}
697 
698 #ifdef DEBUG
699 	for (i = 0; i < ibdp->ibcm_arp_ibd_cnt; i++) {
700 		char    my_buf[INET6_ADDRSTRLEN];
701 		ibcm_arp_ip_t	*aip = &ibdp->ibcm_arp_ip[i];
702 
703 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: ibd[%d]: Family %d "
704 		    "Instance %d PKey 0x%lX \n HCAGUID 0x%llX SGID %llX:%llX",
705 		    i, aip->ip_inet_family, aip->ip_inst, aip->ip_pkey,
706 		    aip->ip_hca_guid, aip->ip_port_gid.gid_prefix,
707 		    aip->ip_port_gid.gid_guid);
708 		if (aip->ip_inet_family == AF_INET) {
709 			IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: IPV4: %s",
710 			    inet_ntop(AF_INET, &aip->ip_cm_sin.sin_addr, my_buf,
711 			    sizeof (my_buf)));
712 		} else if (aip->ip_inet_family == AF_INET6) {
713 			IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: IPV6: %s",
714 			    inet_ntop(AF_INET6, &aip->ip_cm_sin6.sin6_addr,
715 			    my_buf, sizeof (my_buf)));
716 		} else {
717 			IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_ibds: Unknown "
718 			    "Family %d", aip->ip_inet_family);
719 		}
720 	}
721 #endif
722 
723 	return (IBT_SUCCESS);
724 }
725 
726 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibtl_cm_port_list_t))
727 
728 ibt_status_t
729 ibcm_arp_get_srcip_plist(ibt_ip_path_attr_t *ipattr, ibt_path_flags_t flags,
730     ibtl_cm_port_list_t **port_list_p)
731 {
732 	ibt_path_attr_t		attr;
733 	ibt_status_t		ret;
734 	ibcm_arp_ibd_insts_t	ibds;
735 	ibcm_arp_ip_t		*ipp;
736 	ibtl_cm_port_list_t	*plistp;
737 	ib_gid_t		sgid;
738 	sa_family_t		family_interested = AF_UNSPEC;
739 
740 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist(%p, %llX)",
741 	    ipattr, flags);
742 
743 	if (ipattr->ipa_src_ip.family != AF_UNSPEC)
744 		family_interested = ipattr->ipa_src_ip.family;
745 	else
746 		family_interested = ipattr->ipa_dst_ip[0].family;
747 
748 	sgid.gid_prefix = sgid.gid_guid = 0;
749 	bzero(&ibds, sizeof (ibcm_arp_ibd_insts_t));
750 	ibds.ibcm_arp_ibd_alloc = IBCM_ARP_IBD_INSTANCES;
751 	ibds.ibcm_arp_ibd_cnt = 0;
752 	ibds.ibcm_arp_ip = (ibcm_arp_ip_t *)kmem_zalloc(
753 	    ibds.ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t), KM_SLEEP);
754 
755 	ret = ibcm_arp_get_ibds(&ibds, family_interested);
756 	if (ret != IBT_SUCCESS) {
757 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_srcip_plist: "
758 		    "ibcm_arp_get_ibds failed : 0x%x", ret);
759 		goto srcip_plist_end;
760 	}
761 
762 	if (ipattr->ipa_src_ip.family != AF_UNSPEC) {
763 		ret = ibcm_arp_ibd_mac2gid(&ibds, &ipattr->ipa_src_ip, &sgid);
764 		if (ret != IBT_SUCCESS) {
765 			IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_srcip_plist: "
766 			    "SGID for the specified SRCIP Not found %X", ret);
767 			goto srcip_plist_end;
768 		}
769 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist: SGID "
770 		    "%llX:%llX", sgid.gid_prefix, sgid.gid_guid);
771 	}
772 
773 	bzero(&attr, sizeof (ibt_path_attr_t));
774 	attr.pa_hca_guid = ipattr->ipa_hca_guid;
775 	attr.pa_hca_port_num = ipattr->ipa_hca_port_num;
776 	attr.pa_sgid = sgid;
777 	bcopy(&ipattr->ipa_mtu,  &attr.pa_mtu, sizeof (ibt_mtu_req_t));
778 	bcopy(&ipattr->ipa_srate,  &attr.pa_srate, sizeof (ibt_srate_req_t));
779 	bcopy(&ipattr->ipa_pkt_lt,  &attr.pa_pkt_lt, sizeof (ibt_pkt_lt_req_t));
780 
781 	ret = ibtl_cm_get_active_plist(&attr, flags, port_list_p);
782 	if (ret == IBT_SUCCESS) {
783 		int		i;
784 		uint8_t		cnt;
785 		boolean_t	no_srcip_configured = B_FALSE;
786 		uint8_t		no_srcip_cnt = 0;
787 
788 		plistp = port_list_p[0];
789 		cnt = plistp->p_count;
790 		for (i = 0; i < cnt; i++, plistp++) {
791 			ipp = ibcm_arp_ibd_gid2mac(&plistp->p_sgid, 0, &ibds);
792 			if ((ipp == NULL) ||
793 			    (ipp->ip_inet_family == AF_UNSPEC)) {
794 				plistp->p_src_ip.family = AF_UNSPEC;
795 				no_srcip_configured = B_TRUE;
796 				no_srcip_cnt++;
797 				IBTF_DPRINTF_L3(cmlog,
798 				    "ibcm_arp_get_srcip_plist: SrcIP NOT "
799 				    "Configured for GID %llX:%llX",
800 				    plistp->p_sgid.gid_prefix,
801 				    plistp->p_sgid.gid_guid);
802 			} else {
803 				IBTF_DPRINTF_L4(cmlog,
804 				    "ibcm_arp_get_srcip_plist: GID %llX:%llX",
805 				    plistp->p_sgid.gid_prefix,
806 				    plistp->p_sgid.gid_guid);
807 				if (ipp->ip_inet_family == AF_INET) {
808 					plistp->p_src_ip.family = AF_INET;
809 					bcopy(&ipp->ip_cm_sin.sin_addr,
810 					    &plistp->p_src_ip.un.ip4addr,
811 					    sizeof (in_addr_t));
812 
813 				} else if (ipp->ip_inet_family == AF_INET6) {
814 					plistp->p_src_ip.family = AF_INET6;
815 					bcopy(&ipp->ip_cm_sin6.sin6_addr,
816 					    &plistp->p_src_ip.un.ip6addr,
817 					    sizeof (in6_addr_t));
818 				}
819 				IBCM_PRINT_IP("ibcm_arp_get_srcip_plist: "
820 				    "IP Addr is:", &plistp->p_src_ip);
821 			}
822 		}
823 		if (no_srcip_configured) {
824 			ibtl_cm_port_list_t	*n_plistp, *tmp_n_plistp;
825 			uint8_t			new_cnt;
826 
827 			new_cnt = cnt - no_srcip_cnt;
828 
829 			/*
830 			 * Looks like some of the SRC GID we found have no
831 			 * IP ADDR configured, so remove these entries from
832 			 * our list.
833 			 */
834 			plistp = port_list_p[0];
835 			IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist: "
836 			    "Only %d SGID (%d/%d) have SrcIP Configured",
837 			    new_cnt, no_srcip_cnt, cnt);
838 			if (new_cnt) {
839 				/* Allocate Memory to hold Src Point info. */
840 				n_plistp = kmem_zalloc(new_cnt *
841 				    sizeof (ibtl_cm_port_list_t), KM_SLEEP);
842 
843 				tmp_n_plistp = n_plistp;
844 				for (i = 0; i < cnt; i++, plistp++) {
845 					if (plistp->p_src_ip.family ==
846 					    AF_UNSPEC)
847 						continue;
848 
849 					bcopy(plistp, n_plistp,
850 					    sizeof (ibtl_cm_port_list_t));
851 					n_plistp->p_count = new_cnt;
852 					n_plistp++;
853 				}
854 				plistp = port_list_p[0];
855 				*port_list_p = tmp_n_plistp;
856 			} else {
857 				/*
858 				 * All entries we have, do not have IP-Addr
859 				 * configured so return empty hand.
860 				 */
861 				IBTF_DPRINTF_L2(cmlog,
862 				    "ibcm_arp_get_srcip_plist: None of SGID "
863 				    "found have SrcIP Configured");
864 				*port_list_p = NULL;
865 				ret = IBT_SRC_IP_NOT_FOUND;
866 			}
867 			IBTF_DPRINTF_L4(cmlog, "FREE OLD list %p, NEW list is "
868 			    "%p - %p", plistp, port_list_p, *port_list_p);
869 			kmem_free(plistp, cnt * sizeof (ibtl_cm_port_list_t));
870 		}
871 	}
872 
873 srcip_plist_end:
874 	if (ibds.ibcm_arp_ip)
875 		kmem_free(ibds.ibcm_arp_ip, ibds.ibcm_arp_ibd_alloc *
876 		    sizeof (ibcm_arp_ip_t));
877 
878 	return (ret);
879 }
880 /* Routines for warlock */
881 
882 /* ARGSUSED */
883 static int
884 ibcm_arp_dummy_ibaddr_hdl(void *arg, int status)
885 {
886 	ibcm_arp_prwqn_t		dummy_wqn1;
887 	ibcm_arp_prwqn_t		dummy_wqn2;
888 
889 	dummy_wqn1.func = ibcm_arp_get_ibaddr_cb;
890 	dummy_wqn2.func = ibcm_arp_dummy_ibaddr_hdl;
891 
892 	IBTF_DPRINTF_L5(cmlog, "ibcm_arp_dummy_ibaddr_hdl: "
893 	    "dummy_wqn1.func %p %p", dummy_wqn1.func, dummy_wqn2.func);
894 
895 	return (0);
896 }
897