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