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