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