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