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