xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp_link.c (revision 015f8fff605f2fbd5fd0072e555576297804d57b)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/stream.h>
30 #include <sys/dlpi.h>
31 #include <sys/stropts.h>
32 #include <sys/strsun.h>
33 #include <sys/sysmacros.h>
34 #include <sys/strlog.h>
35 #include <sys/ddi.h>
36 #include <sys/cmn_err.h>
37 #include <sys/socket.h>
38 #include <sys/tihdr.h>
39 #include <net/if.h>
40 #include <net/if_arp.h>
41 #include <net/if_types.h>
42 #include <net/if_dl.h>
43 #include <net/route.h>
44 #include <sys/sockio.h>
45 #include <netinet/in.h>
46 #include <netinet/ip6.h>
47 #include <netinet/icmp6.h>
48 #include <sys/ethernet.h>
49 #include <inet/common.h>	/* for various inet/mi.h and inet/nd.h needs */
50 #include <inet/mi.h>
51 #include <inet/arp.h>
52 #include <inet/ip.h>
53 #include <inet/ip_multi.h>
54 #include <inet/ip_ire.h>
55 #include <inet/ip_rts.h>
56 #include <inet/ip_if.h>
57 #include <sys/ib/mgt/ibcm/ibcm_arp.h>
58 #include <inet/ip_ftable.h>
59 
60 static areq_t ibcm_arp_areq_template = {
61 	AR_ENTRY_QUERY,	/* cmd */
62 	sizeof (areq_t) + (2 * IP_ADDR_LEN),	/* name offset */
63 	sizeof (areq_t),	/* name len */
64 	IP_ARP_PROTO_TYPE,	/* protocol, from arps perspective */
65 	sizeof (areq_t),	/* target addr offset */
66 	IP_ADDR_LEN,	/* target ADDR_length */
67 	0,	/* flags */
68 	sizeof (areq_t) + IP_ADDR_LEN,	/* sender addr offset */
69 	IP_ADDR_LEN,	/* sender addr length */
70 	IBCM_ARP_XMIT_COUNT,	/* xmit_count */
71 	IBCM_ARP_XMIT_INTERVAL,	/* (re)xmit_interval in milliseconds */
72 	4	/* max # of requests to buffer */
73 		/*
74 		 * anything else filled in by the code
75 		 */
76 };
77 
78 static area_t ibcm_arp_area_template = {
79 	AR_ENTRY_ADD,			/* cmd */
80 	sizeof (area_t) + IPOIB_ADDRL + (2 * IP_ADDR_LEN), /* name offset */
81 	sizeof (area_t),		/* name len */
82 	IP_ARP_PROTO_TYPE,		/* protocol, from arps perspective */
83 	sizeof (area_t),		/* proto addr offset */
84 	IP_ADDR_LEN,			/* proto ADDR_length */
85 	sizeof (area_t) + (IP_ADDR_LEN),	/* proto mask offset */
86 	0,				/* flags */
87 	sizeof (area_t) + (2 * IP_ADDR_LEN),	/* hw addr offset */
88 	IPOIB_ADDRL				/* hw addr length */
89 };
90 
91 extern char cmlog[];
92 
93 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", msgb))
94 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", area_t))
95 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_streams_t))
96 
97 static void ibcm_arp_timeout(void *arg);
98 void ibcm_arp_pr_callback(ibcm_arp_prwqn_t *wqnp, int status);
99 
100 /*
101  * issue a AR_ENTRY_QUERY to arp driver and schedule a timeout.
102  */
103 int
104 ibcm_arp_query_arp(ibcm_arp_prwqn_t *wqnp)
105 {
106 	int len;
107 	int name_len;
108 	int name_offset;
109 	char *cp;
110 	mblk_t *mp;
111 	mblk_t *mp1;
112 	areq_t *areqp;
113 	ibcm_arp_streams_t *ib_s = (ibcm_arp_streams_t *)wqnp->arg;
114 
115 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_query_arp(ib_s: %p wqnp: %p)",
116 	    ib_s, wqnp);
117 
118 	name_offset = ibcm_arp_areq_template.areq_name_offset;
119 
120 	/*
121 	 * allocate mblk for AR_ENTRY_QUERY
122 	 */
123 	name_len = strlen(wqnp->ifname) + 1;
124 	len = name_len + name_offset;
125 	if ((mp = allocb(len, BPRI_HI)) == NULL) {
126 		return (ENOMEM);
127 	}
128 	bzero(mp->b_rptr, len);
129 	mp->b_wptr += len;
130 
131 	/*
132 	 * allocate a mblk and set wqnp in the data
133 	 */
134 	if ((mp1 = allocb(sizeof (void *), BPRI_HI)) == NULL) {
135 		freeb(mp);
136 		return (ENOMEM);
137 	}
138 
139 	mp1->b_wptr += sizeof (void *);
140 	/* LINTED */
141 	*(uintptr_t *)mp1->b_rptr = (uintptr_t)wqnp;	/* store wqnp */
142 
143 	cp = (char *)mp->b_rptr;
144 	bcopy(&ibcm_arp_areq_template, cp, sizeof (areq_t));
145 	/* LINTED */
146 	areqp = (areq_t *)cp;
147 	areqp->areq_name_length = name_len;
148 
149 	cp = (char *)areqp + areqp->areq_name_offset;
150 	bcopy(wqnp->ifname, cp, name_len);
151 
152 	areqp->areq_proto = wqnp->ifproto;
153 	bcopy(&wqnp->ifproto, areqp->areq_sap, 2);
154 	cp = (char *)areqp + areqp->areq_target_addr_offset;
155 	bcopy(&wqnp->dst_addr.un.ip4addr, cp, IP_ADDR_LEN);
156 	cp = (char *)areqp + areqp->areq_sender_addr_offset;
157 	bcopy(&wqnp->src_addr.un.ip4addr, cp, IP_ADDR_LEN);
158 
159 	mp->b_cont = mp1;
160 
161 	DB_TYPE(mp) = M_PROTO;
162 
163 	/*
164 	 * issue the request to arp
165 	 */
166 	wqnp->flags |= IBCM_ARP_PR_ARP_PENDING;
167 	wqnp->timeout_id = timeout(ibcm_arp_timeout, wqnp,
168 	    drv_usectohz(IBCM_ARP_TIMEOUT * 1000));
169 	if (canputnext(ib_s->arpqueue)) {
170 		putnext(ib_s->arpqueue, mp);
171 	} else {
172 		(void) putq(ib_s->arpqueue, mp);
173 		qenable(ib_s->arpqueue);
174 	}
175 
176 	return (0);
177 }
178 
179 /*
180  * issue AR_ENTRY_SQUERY to arp driver
181  */
182 int
183 ibcm_arp_squery_arp(ibcm_arp_prwqn_t *wqnp)
184 {
185 	int len;
186 	int name_len;
187 	char *cp;
188 	mblk_t *mp;
189 	mblk_t *mp1;
190 	area_t *areap;
191 	uint32_t  proto_mask = 0xffffffff;
192 	struct iocblk *ioc;
193 	ibcm_arp_streams_t *ib_s = (ibcm_arp_streams_t *)wqnp->arg;
194 
195 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_squery_arp(ib_s: %p wqnp: %p)",
196 	    ib_s, wqnp);
197 
198 	/*
199 	 * allocate mblk for AR_ENTRY_SQUERY
200 	 */
201 	name_len = strlen(wqnp->ifname) + 1;
202 	len = ibcm_arp_area_template.area_name_offset + name_len +
203 	    sizeof (uintptr_t);
204 	if ((mp = allocb(len, BPRI_HI)) == NULL) {
205 		return (ENOMEM);
206 	}
207 	bzero(mp->b_rptr, len);
208 	mp->b_wptr += len + sizeof (uintptr_t);
209 
210 	/* LINTED */
211 	*(uintptr_t *)mp->b_rptr = (uintptr_t)wqnp;	/* store wqnp */
212 	mp->b_rptr += sizeof (uintptr_t);
213 
214 
215 	cp = (char *)mp->b_rptr;
216 	bcopy(&ibcm_arp_area_template, cp, sizeof (area_t));
217 
218 	/* LINTED */
219 	areap = (area_t *)cp;
220 	areap->area_cmd = AR_ENTRY_SQUERY;
221 	areap->area_name_length = name_len;
222 	cp = (char *)areap + areap->area_name_offset;
223 	bcopy(wqnp->ifname, cp, name_len);
224 
225 	cp = (char *)areap + areap->area_proto_addr_offset;
226 	bcopy(&wqnp->dst_addr.un.ip4addr, cp, IP_ADDR_LEN);
227 
228 	cp = (char *)areap + areap->area_proto_mask_offset;
229 	bcopy(&proto_mask, cp, IP_ADDR_LEN);
230 
231 	mp1 = allocb(sizeof (struct iocblk), BPRI_HI);
232 	if (mp1 == NULL) {
233 		freeb(mp);
234 		return (ENOMEM);
235 	}
236 	/* LINTED */
237 	ioc = (struct iocblk *)mp1->b_rptr;
238 	ioc->ioc_cmd = AR_ENTRY_SQUERY;
239 	ioc->ioc_error = 0;
240 	ioc->ioc_cr = NULL;
241 	ioc->ioc_count = msgdsize(mp);
242 	mp1->b_wptr += sizeof (struct iocblk);
243 	mp1->b_cont = mp;
244 
245 	DB_TYPE(mp1) = M_IOCTL;
246 
247 	if (canputnext(ib_s->arpqueue)) {
248 		putnext(ib_s->arpqueue, mp1);
249 	} else {
250 		(void) putq(ib_s->arpqueue, mp1);
251 		qenable(ib_s->arpqueue);
252 	}
253 	return (0);
254 }
255 
256 /*
257  * issue a AR_ENTRY_ADD to arp driver
258  * This is required as arp driver does not maintain a cache.
259  */
260 int
261 ibcm_arp_add(ibcm_arp_prwqn_t *wqnp)
262 {
263 	int len;
264 	int name_len;
265 	char *cp;
266 	mblk_t *mp;
267 	area_t *areap;
268 	uint32_t  proto_mask = 0xffffffff;
269 	ibcm_arp_streams_t *ib_s = (ibcm_arp_streams_t *)wqnp->arg;
270 
271 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_add(ib_s: %p wqnp: %p)", ib_s, wqnp);
272 
273 	/*
274 	 * allocate mblk for AR_ENTRY_ADD
275 	 */
276 
277 	name_len = strlen(wqnp->ifname) + 1;
278 	len = ibcm_arp_area_template.area_name_offset + name_len;
279 	if ((mp = allocb(len, BPRI_HI)) == NULL) {
280 		return (ENOMEM);
281 	}
282 	bzero(mp->b_rptr, len);
283 	mp->b_wptr += len;
284 
285 	cp = (char *)mp->b_rptr;
286 	bcopy(&ibcm_arp_area_template, cp, sizeof (area_t));
287 
288 	/* LINTED */
289 	areap = (area_t *)mp->b_rptr;
290 	areap->area_name_length = name_len;
291 	cp = (char *)areap + areap->area_name_offset;
292 	bcopy(wqnp->ifname, cp, name_len);
293 
294 	cp = (char *)areap + areap->area_proto_addr_offset;
295 	bcopy(&wqnp->dst_addr.un.ip4addr, cp, IP_ADDR_LEN);
296 
297 	cp = (char *)areap + areap->area_proto_mask_offset;
298 	bcopy(&proto_mask, cp, IP_ADDR_LEN);
299 
300 	cp = (char *)areap + areap->area_hw_addr_offset;
301 	bcopy(&wqnp->dst_mac, cp, IPOIB_ADDRL);
302 
303 	DB_TYPE(mp) = M_PROTO;
304 
305 	if (canputnext(ib_s->arpqueue)) {
306 		putnext(ib_s->arpqueue, mp);
307 	} else {
308 		(void) putq(ib_s->arpqueue, mp);
309 		qenable(ib_s->arpqueue);
310 	}
311 	return (0);
312 }
313 
314 
315 /*
316  * timeout routine when there is no response to AR_ENTRY_QUERY
317  */
318 static void
319 ibcm_arp_timeout(void *arg)
320 {
321 	ibcm_arp_prwqn_t *wqnp = (ibcm_arp_prwqn_t *)arg;
322 	ibcm_arp_streams_t *ib_s = (ibcm_arp_streams_t *)wqnp->arg;
323 
324 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_timeout(ib_s: %p wqnp: %p)",
325 	    ib_s, wqnp);
326 
327 	/*
328 	 * indicate to user
329 	 */
330 	ibcm_arp_pr_callback(wqnp, EHOSTUNREACH);
331 }
332 
333 /*
334  * delete a wait queue node from the list.
335  * assumes mutex is acquired
336  */
337 void
338 ibcm_arp_prwqn_delete(ibcm_arp_prwqn_t *wqnp)
339 {
340 	ibcm_arp_streams_t *ib_s;
341 
342 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_prwqn_delete(%p)", wqnp);
343 
344 	ib_s = (ibcm_arp_streams_t *)wqnp->arg;
345 	ib_s->wqnp = NULL;
346 	kmem_free(wqnp, sizeof (ibcm_arp_prwqn_t));
347 }
348 
349 /*
350  * allocate a wait queue node, and insert it in the list
351  */
352 ibcm_arp_prwqn_t *
353 ibcm_arp_create_prwqn(ibcm_arp_streams_t *ib_s, ibt_ip_addr_t *dst_addr,
354     ibt_ip_addr_t *src_addr, uint32_t localroute, uint32_t bound_dev_if,
355     ibcm_arp_pr_comp_func_t func)
356 {
357 	ibcm_arp_prwqn_t *wqnp;
358 
359 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_create_prwqn(ib_s: 0x%p)", ib_s);
360 
361 	if (dst_addr == NULL) {
362 		return (NULL);
363 	}
364 	if ((wqnp = kmem_zalloc(sizeof (ibcm_arp_prwqn_t), KM_NOSLEEP)) ==
365 	    NULL) {
366 		return (NULL);
367 	}
368 	wqnp->dst_addr = *dst_addr;
369 
370 	if (src_addr) {
371 		wqnp->usrc_addr = *src_addr;
372 	}
373 	wqnp->func = func;
374 	wqnp->arg = ib_s;
375 	wqnp->localroute = localroute;
376 	wqnp->bound_dev_if = bound_dev_if;
377 	wqnp->ifproto = ETHERTYPE_IP;
378 
379 	ib_s->wqnp = wqnp;
380 
381 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_create_prwqn: Return wqnp: %p", wqnp);
382 
383 	return (wqnp);
384 }
385 
386 /*
387  * call the user function
388  * called with lock held
389  */
390 void
391 ibcm_arp_pr_callback(ibcm_arp_prwqn_t *wqnp, int status)
392 {
393 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_pr_callback(%p, %d)", wqnp, status);
394 
395 	wqnp->func((void *)wqnp, status);
396 }
397 
398 static int
399 ibcm_arp_check_interface(ibcm_arp_prwqn_t *wqnp, int length)
400 {
401 	/*
402 	 * if the i/f is not ib or lo device, fail the request
403 	 */
404 	if (bcmp(wqnp->ifname, "ibd", 3) == 0) {
405 		if (length != IPOIB_ADDRL) {
406 			return (EINVAL);
407 		}
408 	} else if (bcmp(wqnp->ifname, "lo", 2)) {
409 		return (ETIMEDOUT);
410 	}
411 
412 	return (0);
413 }
414 
415 #define	IBTL_IPV4_ADDR(a)	(a->un.ip4addr)
416 
417 int
418 ibcm_arp_pr_lookup(ibcm_arp_streams_t *ib_s, ibt_ip_addr_t *dst_addr,
419     ibt_ip_addr_t *src_addr, uint8_t localroute, uint32_t bound_dev_if,
420     ibcm_arp_pr_comp_func_t func)
421 {
422 	ibcm_arp_prwqn_t *wqnp;
423 	ire_t	*ire;
424 	ire_t	*src_ire;
425 	ipif_t	*ipif;
426 	ill_t	*ill;
427 	int length;
428 	ip_stack_t *ipst;
429 
430 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_pr_lookup(src %p dest %p)",
431 	    src_addr, dst_addr);
432 
433 	if (dst_addr->family != AF_INET_OFFLOAD) {
434 		ib_s->status = EAFNOSUPPORT;
435 		return (1);
436 	}
437 
438 	if ((wqnp = ibcm_arp_create_prwqn(ib_s, dst_addr,
439 	    src_addr, localroute, bound_dev_if, func)) == NULL) {
440 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_pr_lookup: "
441 		    "ibcm_arp_create_prwqn failed");
442 		ib_s->status = ENOMEM;
443 		return (1);
444 	}
445 
446 	ipst = netstack_find_by_zoneid(GLOBAL_ZONEID)->netstack_ip;
447 	/*
448 	 * Get the ire for the local address
449 	 */
450 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_pr_lookup: srcip %lX destip %lX",
451 	    IBTL_IPV4_ADDR(src_addr), IBTL_IPV4_ADDR(dst_addr));
452 
453 	src_ire = ire_ctable_lookup(IBTL_IPV4_ADDR(src_addr), NULL,
454 	    IRE_LOCAL, NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE, ipst);
455 	if (src_ire == NULL) {
456 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_pr_lookup: "
457 		    "ire_ctable_lookup failed");
458 		netstack_rele(ipst->ips_netstack);
459 		ibcm_arp_prwqn_delete(wqnp);
460 		ib_s->status = EFAULT;
461 		return (1);
462 	}
463 
464 
465 	/*
466 	 * get an ire for the destination adress with the matching source
467 	 * address
468 	 */
469 	ire = ire_ftable_lookup(IBTL_IPV4_ADDR(dst_addr), 0, 0, 0,
470 	    src_ire->ire_ipif, 0, src_ire->ire_zoneid, 0, NULL, MATCH_IRE_SRC,
471 	    ipst);
472 
473 	netstack_rele(ipst->ips_netstack);
474 
475 	if (ire == NULL) {
476 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_pr_lookup: "
477 		    "ire_ftable_lookup failed");
478 		IRE_REFRELE(src_ire);
479 		ibcm_arp_prwqn_delete(wqnp);
480 		ib_s->status = EFAULT;
481 		return (1);
482 	}
483 
484 	wqnp->src_addr.un.ip4addr = ire->ire_src_addr;
485 	wqnp->src_addr.family = AF_INET_OFFLOAD;
486 
487 	ipif = src_ire->ire_ipif;
488 	ill = ipif->ipif_ill;
489 	length = ill->ill_name_length;
490 	bcopy(ill->ill_name, &wqnp->ifname, ill->ill_name_length);
491 	wqnp->ifname[length] = '\0';
492 	bcopy(ill->ill_phys_addr, &wqnp->src_mac,
493 	    ill->ill_phys_addr_length);
494 
495 	IRE_REFRELE(ire);
496 	IRE_REFRELE(src_ire);
497 
498 	ib_s->status =
499 	    ibcm_arp_check_interface(wqnp, ill->ill_phys_addr_length);
500 	if (ib_s->status) {
501 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_pr_lookup: "
502 		    "ibcm_arp_check_interface failed");
503 		ibcm_arp_prwqn_delete(wqnp);
504 		return (1);
505 	}
506 
507 	ib_s->status = ibcm_arp_squery_arp(wqnp);
508 	if (ib_s->status) {
509 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_pr_lookup: "
510 		    "ibcm_arp_squery_arp failed");
511 		ibcm_arp_prwqn_delete(wqnp);
512 		return (1);
513 	}
514 
515 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_pr_lookup: Return: 0x%p", wqnp);
516 
517 	return (0);
518 }
519 
520 #define	IBCM_H2N_GID(gid) \
521 { \
522 	uint32_t	*ptr; \
523 	ptr = (uint32_t *)&gid.gid_prefix; \
524 	gid.gid_prefix = (uint64_t)(((uint64_t)ntohl(ptr[0]) << 32) | \
525 			(ntohl(ptr[1]))); \
526 	ptr = (uint32_t *)&gid.gid_guid; \
527 	gid.gid_guid = (uint64_t)(((uint64_t)ntohl(ptr[0]) << 32) | \
528 			(ntohl(ptr[1]))); \
529 }
530 
531 /*
532  * called from lrsrv.
533  * process a AR_ENTRY_QUERY reply from arp
534  * the message should be M_DATA -->> dl_unitdata_req
535  */
536 void
537 ibcm_arp_pr_arp_query_ack(mblk_t *mp)
538 {
539 	ibcm_arp_prwqn_t 	*wqnp;
540 	dl_unitdata_req_t *dlreq;
541 	ibcm_arp_streams_t *ib_s;
542 	char *cp;
543 	int rc;
544 
545 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_pr_arp_query_ack(%p)", mp);
546 
547 	/*
548 	 * the first mblk contains the wqnp pointer for the request
549 	 */
550 	/* LINTED */
551 	if (MBLKL(mp) != sizeof (void *)) {
552 		freemsg(mp);
553 		return;
554 	}
555 
556 	/* LINTED */
557 	wqnp = *(ibcm_arp_prwqn_t **)mp->b_rptr;	/* retrieve wqnp */
558 	ib_s = (ibcm_arp_streams_t *)wqnp->arg;
559 
560 	mutex_enter(&ib_s->lock);
561 
562 	/*
563 	 * cancel the timeout for this request
564 	 */
565 	(void) untimeout(wqnp->timeout_id);
566 
567 	/*
568 	 * sanity checks on the dl_unitdata_req block
569 	 */
570 	if (!mp->b_cont) {
571 		IBTF_DPRINTF_L2(cmlog, "areq_ack: b_cont = NULL\n");
572 		rc = EPROTO;
573 		goto user_callback;
574 	}
575 	/* LINTED */
576 	if (MBLKL(mp->b_cont) < (sizeof (dl_unitdata_req_t) + IPOIB_ADDRL)) {
577 		IBTF_DPRINTF_L2(cmlog, "areq_ack: invalid len in "
578 		    "dl_unitdatareq_t block\n");
579 		rc = EPROTO;
580 		goto user_callback;
581 	}
582 	/* LINTED */
583 	dlreq = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
584 	if (dlreq->dl_primitive != DL_UNITDATA_REQ) {
585 		IBTF_DPRINTF_L2(cmlog, "areq_ack: invalid dl_primitive "
586 		    "in dl_unitdatareq_t block\n");
587 		rc = EPROTO;
588 		goto user_callback;
589 	}
590 	if (dlreq->dl_dest_addr_length != (IPOIB_ADDRL + 2)) {
591 		IBTF_DPRINTF_L2(cmlog, "areq_ack: invalid hw len in "
592 		    "dl_unitdatareq_t block %d\n", dlreq->dl_dest_addr_length);
593 		rc = EPROTO;
594 		goto user_callback;
595 	}
596 	cp = (char *)mp->b_cont->b_rptr + dlreq->dl_dest_addr_offset;
597 	bcopy(cp, &wqnp->dst_mac, IPOIB_ADDRL);
598 
599 	/*
600 	 * at this point we have src/dst gid's derived from the mac addresses
601 	 * now get the hca, port
602 	 */
603 	bcopy(&wqnp->src_mac.ipoib_gidpref, &wqnp->sgid, sizeof (ib_gid_t));
604 	bcopy(&wqnp->dst_mac.ipoib_gidpref, &wqnp->dgid, sizeof (ib_gid_t));
605 	freemsg(mp);
606 
607 	IBCM_H2N_GID(wqnp->sgid);
608 	IBCM_H2N_GID(wqnp->dgid);
609 
610 	(void) ibcm_arp_add(wqnp);
611 
612 	mutex_exit(&ib_s->lock);
613 	ibcm_arp_pr_callback(wqnp, 0);
614 
615 	return;
616 user_callback:
617 	freemsg(mp);
618 	mutex_exit(&ib_s->lock);
619 
620 	/*
621 	 * indicate to user
622 	 */
623 	ibcm_arp_pr_callback(wqnp, rc);
624 }
625 
626 /*
627  * process a AR_ENTRY_SQUERY reply from arp
628  * the message should be M_IOCACK -->> area_t
629  */
630 void
631 ibcm_arp_pr_arp_squery_ack(mblk_t *mp)
632 {
633 	struct iocblk *ioc;
634 	mblk_t	*mp1;
635 	ibcm_arp_prwqn_t 	*wqnp;
636 	ibcm_arp_streams_t *ib_s;
637 	area_t *areap;
638 	char *cp;
639 
640 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_pr_arp_squery_ack(%p)", mp);
641 
642 	/* LINTED */
643 	if (MBLKL(mp) < sizeof (struct iocblk)) {
644 		freemsg(mp);
645 		return;
646 	}
647 
648 	/* LINTED */
649 	ioc = (struct iocblk *)mp->b_rptr;
650 	if ((ioc->ioc_cmd != AR_ENTRY_SQUERY) || (mp->b_cont == NULL)) {
651 		freemsg(mp);
652 		return;
653 	}
654 
655 	mp1 = mp->b_cont;
656 
657 	wqnp = *(ibcm_arp_prwqn_t **)((uintptr_t)mp1->b_rptr -
658 	    sizeof (uintptr_t));
659 	ib_s = (ibcm_arp_streams_t *)wqnp->arg;
660 
661 	mutex_enter(&ib_s->lock);
662 
663 	/* If the entry was not in arp cache, ioc_error is set */
664 	if (ioc->ioc_error) {
665 
666 		/*
667 		 * send out AR_ENTRY_QUERY which would send
668 		 * arp-request on wire
669 		 */
670 		IBTF_DPRINTF_L3(cmlog, "Sending a Query_ARP");
671 
672 		(void) ibcm_arp_query_arp(wqnp);
673 		freemsg(mp);
674 		mutex_exit(&ib_s->lock);
675 		return;
676 	}
677 
678 	/* LINTED */
679 	areap = (area_t *)mp1->b_rptr;
680 	cp = (char *)areap + areap->area_hw_addr_offset;
681 	bcopy(cp, &wqnp->dst_mac, IPOIB_ADDRL);
682 
683 	/*
684 	 * at this point we have src/dst gid's derived from the mac addresses
685 	 * now get the hca, port
686 	 */
687 	bcopy(&wqnp->src_mac.ipoib_gidpref, &wqnp->sgid, sizeof (ib_gid_t));
688 	bcopy(&wqnp->dst_mac.ipoib_gidpref, &wqnp->dgid, sizeof (ib_gid_t));
689 	freemsg(mp);
690 
691 	IBCM_H2N_GID(wqnp->sgid);
692 	IBCM_H2N_GID(wqnp->dgid);
693 
694 	mutex_exit(&ib_s->lock);
695 	ibcm_arp_pr_callback(wqnp, 0);
696 }
697 
698 /*
699  * Process arp ack's.
700  */
701 void
702 ibcm_arp_pr_arp_ack(mblk_t *mp)
703 {
704 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_pr_arp_ack(0x%p, DB_TYPE %lX)",
705 	    mp, DB_TYPE(mp));
706 
707 	if (DB_TYPE(mp) == M_DATA) {
708 		ibcm_arp_pr_arp_query_ack(mp);
709 	} else if ((DB_TYPE(mp) == M_IOCACK) ||
710 	    (DB_TYPE(mp) == M_IOCNAK)) {
711 		ibcm_arp_pr_arp_squery_ack(mp);
712 	} else {
713 		freemsg(mp);
714 	}
715 }
716