/* * dapl_hca_alloc * * alloc and initialize an HCA struct * * Input: * name * port * * Output: * hca_ptr * * Returns: * none * */ DAPL_HCA *dapl_hca_alloc(char *name, char *port) { DAPL_HCA *hca_ptr; hca_ptr = dapl_os_alloc(sizeof(DAPL_HCA)); if (NULL == hca_ptr) { goto bail; } dapl_os_memzero(hca_ptr, sizeof(DAPL_HCA)); dapl_os_lock_init(&hca_ptr->lock); dapl_llist_init_head(&hca_ptr->ia_list_head); hca_ptr->name = dapl_os_strdup(name); if (NULL == hca_ptr->name) { goto bail; } hca_ptr->ib_hca_handle = IB_INVALID_HANDLE; hca_ptr->port_num = dapl_os_strtol(port, NULL, 0); return (hca_ptr); bail: if (NULL != hca_ptr) dapl_os_free(hca_ptr, sizeof(DAPL_HCA)); return NULL; }
DAPL_LMR *dapl_lmr_alloc(IN DAPL_IA * ia, IN DAT_MEM_TYPE mem_type, IN DAT_REGION_DESCRIPTION region_desc, IN DAT_VLEN length, IN DAT_PZ_HANDLE pz_handle, IN DAT_MEM_PRIV_FLAGS mem_priv) { DAPL_LMR *lmr; /* Allocate LMR */ lmr = (DAPL_LMR *) dapl_os_alloc(sizeof(DAPL_LMR)); if (NULL == lmr) { return (NULL); } /* zero the structure */ dapl_os_memzero(lmr, sizeof(DAPL_LMR)); /* * initialize the header */ lmr->header.provider = ia->header.provider; lmr->header.magic = DAPL_MAGIC_LMR; lmr->header.handle_type = DAT_HANDLE_TYPE_LMR; lmr->header.owner_ia = ia; lmr->header.user_context.as_64 = 0; lmr->header.user_context.as_ptr = NULL; dapl_llist_init_entry(&lmr->header.ia_list_entry); dapl_ia_link_lmr(ia, lmr); dapl_os_lock_init(&lmr->header.lock); /* * initialize the body */ lmr->param.ia_handle = (DAT_IA_HANDLE) ia; lmr->param.mem_type = mem_type; lmr->param.region_desc = region_desc; lmr->param.length = length; lmr->param.pz_handle = pz_handle; lmr->param.mem_priv = mem_priv; dapl_os_atomic_set(&lmr->lmr_ref_count, 0); return (lmr); }
/* * dapl_cno_alloc * * alloc and initialize an EVD struct * * Input: * ia * * Returns: * cno_ptr, or null on failure. */ DAPL_CNO * dapl_cno_alloc( IN DAPL_IA *ia_ptr, IN DAT_OS_WAIT_PROXY_AGENT wait_agent) { DAPL_CNO *cno_ptr; cno_ptr = (DAPL_CNO *) dapl_os_alloc(sizeof (DAPL_CNO)); if (!cno_ptr) { return (NULL); } /* zero the structure */ (void) dapl_os_memzero(cno_ptr, sizeof (DAPL_CNO)); /* * Initialize the header. */ cno_ptr->header.provider = ia_ptr->header.provider; cno_ptr->header.magic = DAPL_MAGIC_CNO; cno_ptr->header.handle_type = DAT_HANDLE_TYPE_CNO; cno_ptr->header.owner_ia = ia_ptr; cno_ptr->header.user_context.as_64 = 0; cno_ptr->header.user_context.as_ptr = NULL; dapl_llist_init_entry(&cno_ptr->header.ia_list_entry); dapl_llist_init_head(&cno_ptr->evd_list_head); dapl_os_lock_init(&cno_ptr->header.lock); /* * Initialize the body */ cno_ptr->cno_waiters = 0; cno_ptr->cno_ref_count = 0; cno_ptr->cno_state = DAPL_CNO_STATE_UNTRIGGERED; cno_ptr->cno_evd_triggered = NULL; cno_ptr->cno_wait_agent = wait_agent; (void) dapl_os_wait_object_init(&cno_ptr->cno_wait_object); return (cno_ptr); }
/* * dapl_sp_alloc * * alloc and initialize a PSP INFO struct * * Input: * IA INFO struct ptr * * Output: * sp_ptr * * Returns: * NULL * pointer to sp info struct * */ DAPL_SP * dapls_sp_alloc( IN DAPL_IA *ia_ptr, IN DAT_BOOLEAN is_psp) { DAPL_SP *sp_ptr; /* Allocate EP */ sp_ptr = (DAPL_SP *)dapl_os_alloc(sizeof (DAPL_SP)); if (sp_ptr == NULL) { return (NULL); } /* zero the structure */ (void) dapl_os_memzero(sp_ptr, sizeof (DAPL_SP)); /* * initialize the header */ sp_ptr->header.provider = ia_ptr->header.provider; if (is_psp) { sp_ptr->header.magic = DAPL_MAGIC_PSP; sp_ptr->header.handle_type = DAT_HANDLE_TYPE_PSP; } else { sp_ptr->header.magic = DAPL_MAGIC_RSP; sp_ptr->header.handle_type = DAT_HANDLE_TYPE_RSP; } sp_ptr->header.owner_ia = ia_ptr; sp_ptr->header.user_context.as_64 = 0; sp_ptr->header.user_context.as_ptr = NULL; dapl_llist_init_entry(&sp_ptr->header.ia_list_entry); dapl_os_lock_init(&sp_ptr->header.lock); /* * Initialize the Body (set to NULL above) */ dapl_llist_init_head(&sp_ptr->cr_list_head); return (sp_ptr); }
/* * dapl_ep_connect * * DAPL Requirements Version xxx, 6.5.7 * * Request a connection be established between the local Endpoint * and a remote Endpoint. This operation is used by the active/client * side of a connection * * Input: * ep_handle * remote_ia_address * remote_conn_qual * timeout * private_data_size * privaet_data * qos * connect_flags * * Output: * None * * Returns: * DAT_SUCCESS * DAT_INSUFFICIENT_RESOUCRES * DAT_INVALID_PARAMETER * DAT_MODLE_NOT_SUPPORTED */ DAT_RETURN dapl_ep_connect( IN DAT_EP_HANDLE ep_handle, IN DAT_IA_ADDRESS_PTR remote_ia_address, IN DAT_CONN_QUAL remote_conn_qual, IN DAT_TIMEOUT timeout, IN DAT_COUNT private_data_size, IN const DAT_PVOID private_data, IN DAT_QOS qos, IN DAT_CONNECT_FLAGS connect_flags) { DAPL_EP *ep_ptr; DAPL_PRIVATE prd; DAPL_EP alloc_ep; DAT_RETURN dat_status; dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, "dapl_ep_connect (%p, {%u.%u.%u.%u}, %X, %d, %d, %p, %x, %x)\n", ep_handle, remote_ia_address->sa_data[2], remote_ia_address->sa_data[3], remote_ia_address->sa_data[4], remote_ia_address->sa_data[5], remote_conn_qual, timeout, private_data_size, private_data, qos, connect_flags); dat_status = DAT_SUCCESS; ep_ptr = (DAPL_EP *) ep_handle; /* * Verify parameter & state. The connection handle must be good * at this point. */ if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } if (DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN); goto bail; } /* * If the endpoint needs a QP, associated the QP with it. * This needs to be done carefully, in order to: * * Avoid allocating under a lock. * * Not step on data structures being altered by * routines with which we are racing. * So we: * * Confirm that a new QP is needed and is not forbidden by the * current state. * * Allocate it into a separate EP. * * Take the EP lock. * * Reconfirm that the EP is in a state where it needs a QP. * * Assign the QP and release the lock. */ if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { if (ep_ptr->param.pz_handle == NULL || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ)) { dat_status = DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY); goto bail; } alloc_ep = *ep_ptr; dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia, &alloc_ep, ep_ptr); if (dat_status != DAT_SUCCESS) { dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); goto bail; } dapl_os_lock(&ep_ptr->header.lock); /* * PZ shouldn't have changed since we're only racing with * dapl_cr_accept() */ if (ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED) { /* Bail, cleaning up. */ dapl_os_unlock(&ep_ptr->header.lock); dat_status = dapls_ib_qp_free(ep_ptr->header.owner_ia, &alloc_ep); if (dat_status != DAT_SUCCESS) { dapl_dbg_log(DAPL_DBG_TYPE_WARN, "ep_connect: ib_qp_free failed with %x\n", dat_status); } dat_status = DAT_ERROR(DAT_INVALID_STATE, dapls_ep_state_subtype(ep_ptr)); goto bail; } ep_ptr->qp_handle = alloc_ep.qp_handle; ep_ptr->qpn = alloc_ep.qpn; ep_ptr->qp_state = alloc_ep.qp_state; dapl_os_unlock(&ep_ptr->header.lock); } /* * We do state checks and transitions under lock. * The only code we're racing against is dapl_cr_accept. */ dapl_os_lock(&ep_ptr->header.lock); /* * Verify the attributes of the EP handle before we connect it. Test * all of the handles to make sure they are currently valid. * Specifically: * pz_handle required * recv_evd_handle optional, but must be valid * request_evd_handle optional, but must be valid * connect_evd_handle required */ if (ep_ptr->param.pz_handle == NULL || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) || ep_ptr->param.connect_evd_handle == NULL || DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) || !(((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG) || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL && (DAPL_BAD_HANDLE(ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL && (DAPL_BAD_HANDLE(ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY); goto bail; } /* * Check both the EP state and the QP state: if we don't have a QP * we need to attach one now. */ if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia, ep_ptr, ep_ptr); if (dat_status != DAT_SUCCESS) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_TEP); goto bail; } } if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_STATE, dapls_ep_state_subtype(ep_ptr)); goto bail; } if (qos != DAT_QOS_BEST_EFFORT || connect_flags != DAT_CONNECT_DEFAULT_FLAG) { /* * At this point we only support one QOS level */ dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_MODEL_NOT_SUPPORTED, 0); goto bail; } /* * Verify the private data size doesn't exceed the max */ if (private_data_size > DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5); goto bail; } /* * transition the state before requesting a connection to avoid * race conditions */ ep_ptr->param.ep_state = DAT_EP_STATE_ACTIVE_CONNECTION_PENDING; /* * At this point we're committed, and done with the endpoint * except for the connect, so we can drop the lock. */ dapl_os_unlock(&ep_ptr->header.lock); /* * fill in the private data */ (void) dapl_os_memzero(&prd, sizeof (DAPL_PRIVATE)); if (private_data_size > 0) (void) dapl_os_memcpy(prd.private_data, private_data, private_data_size); /* Copy the connection qualifiers */ (void) dapl_os_memcpy(ep_ptr->param.remote_ia_address_ptr, remote_ia_address, sizeof (DAT_SOCK_ADDR6)); ep_ptr->param.remote_port_qual = remote_conn_qual; dat_status = dapls_ib_connect(ep_handle, remote_ia_address, remote_conn_qual, private_data_size, &prd, timeout); if (dat_status != DAT_SUCCESS) { DAPL_EVD *evd_ptr; if (dat_status == DAT_ERROR(DAT_INVALID_ADDRESS, DAT_INVALID_ADDRESS_UNREACHABLE)) { /* Unreachable IP address */ evd_ptr = (DAPL_EVD *)ep_ptr->param.connect_evd_handle; if (evd_ptr != NULL) { (void) dapls_evd_post_connection_event(evd_ptr, DAT_CONNECTION_EVENT_UNREACHABLE, (DAT_HANDLE) ep_ptr, 0, 0); } ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dat_status = DAT_SUCCESS; } else if (dat_status == DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ADDRESS_UNREACHABLE)) { /* Non-existant connection qualifier */ evd_ptr = (DAPL_EVD *)ep_ptr->param.connect_evd_handle; if (evd_ptr != NULL) { (void) dapls_evd_post_connection_event(evd_ptr, DAT_CONNECTION_EVENT_NON_PEER_REJECTED, (DAT_HANDLE) ep_ptr, 0, 0); } ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED; dat_status = DAT_SUCCESS; } else { ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED; } } bail: dapl_dbg_log(DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM, "dapl_ep_connect () returns 0x%x\n", dat_status); return (dat_status); }
/* * dapl_cr_accept * * DAPL Requirements Version xxx, 6.4.2.1 * * Establish a connection between active remote side requesting Endpoint * and passic side local Endpoint. * * Input: * cr_handle * ep_handle * private_data_size * private_data * * Output: * none * * Returns: * DAT_SUCCESS * DAT_INVALID_PARAMETER * DAT_INVALID_ATTRIBUTE */ DAT_RETURN dapl_cr_accept( IN DAT_CR_HANDLE cr_handle, IN DAT_EP_HANDLE ep_handle, IN DAT_COUNT private_data_size, IN const DAT_PVOID private_data) { DAPL_EP *ep_ptr; DAT_RETURN dat_status; DAPL_PRIVATE prd; DAPL_CR *cr_ptr; DAT_EP_STATE entry_ep_state; DAT_EP_HANDLE entry_ep_handle; dapl_dbg_log(DAPL_DBG_TYPE_API, "dapl_cr_accept(%p, %p, %d, %p)\n", cr_handle, ep_handle, private_data_size, private_data); if (DAPL_BAD_HANDLE(cr_handle, DAPL_MAGIC_CR)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_CR); goto bail; } cr_ptr = (DAPL_CR *) cr_handle; /* * Return an error if we have an ep_handle and the CR already has an * EP, indicating this is an RSP connection or PSP_PROVIDER_FLAG was * specified. */ if (ep_handle != NULL && (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP) || cr_ptr->param.local_ep_handle != NULL)) { dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } if ((0 != private_data_size) && (NULL == private_data)) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4); goto bail; } /* * Verify the private data size doesn't exceed the max */ if (private_data_size > DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE) { dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3); goto bail; } /* * ep_handle is NULL if the user specified DAT_PSP_PROVIDER_FLAG * OR this is an RSP connection; retrieve it from the cr. */ if (ep_handle == NULL) { ep_handle = cr_ptr->param.local_ep_handle; if ((((DAPL_EP *) ep_handle)->param.ep_state != DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING) && (((DAPL_EP *)ep_handle)->param.ep_state != DAT_EP_STATE_PASSIVE_CONNECTION_PENDING)) { return (DAT_INVALID_STATE); } } else { /* ensure this EP isn't connected or in use */ if (((DAPL_EP *)ep_handle)->param.ep_state != DAT_EP_STATE_UNCONNECTED) { return (DAT_INVALID_STATE); } } ep_ptr = (DAPL_EP *) ep_handle; /* * Verify the attributes of the EP handle before we connect it. Test * all of the handles to make sure they are currently valid. * Specifically: * pz_handle required * recv_evd_handle optional, but must be valid * request_evd_handle optional, but must be valid * connect_evd_handle required * We do all verification and state change under lock, at which * point the EP state should protect us from most races. */ dapl_os_lock(&ep_ptr->header.lock); if ((ep_ptr->param.pz_handle == NULL) || DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) || (ep_ptr->param.connect_evd_handle == NULL) || DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) || !(((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG) || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL && (DAPL_BAD_HANDLE(ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL && (DAPL_BAD_HANDLE(ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD)))) { dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) { /* * If we are lazy attaching the QP then we may need to * hook it up here. Typically, we run this code only for * DAT_PSP_PROVIDER_FLAG */ dat_status = dapls_ib_qp_alloc(cr_ptr->header.owner_ia, ep_ptr, ep_ptr); if (dat_status != DAT_SUCCESS) { /* This is not a great error code, but spec allows */ dapl_os_unlock(&ep_ptr->header.lock); dat_status = DAT_ERROR(DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP); goto bail; } } entry_ep_state = ep_ptr->param.ep_state; entry_ep_handle = cr_ptr->param.local_ep_handle; ep_ptr->param.ep_state = DAT_EP_STATE_COMPLETION_PENDING; ep_ptr->cm_handle = cr_ptr->ib_cm_handle; ep_ptr->cr_ptr = cr_ptr; ep_ptr->param.remote_ia_address_ptr = cr_ptr->param. remote_ia_address_ptr; cr_ptr->param.local_ep_handle = ep_handle; /* * private data */ (void) dapl_os_memcpy(prd.private_data, private_data, private_data_size); (void) dapl_os_memzero(prd.private_data + private_data_size, sizeof (DAPL_PRIVATE) - private_data_size); dapl_os_unlock(&ep_ptr->header.lock); dat_status = dapls_ib_accept_connection(cr_handle, ep_handle, &prd); /* * If the provider failed, unwind the damage so we are back at * the initial state. */ if (dat_status != DAT_SUCCESS) { ep_ptr->param.ep_state = entry_ep_state; cr_ptr->param.local_ep_handle = entry_ep_handle; } else { /* * Make this CR invalid. We need to hang on to it until * the connection terminates, but it's destroyed from * the app point of view. */ cr_ptr->header.magic = DAPL_MAGIC_CR_DESTROYED; } bail: return (dat_status); }
DAT_RETURN dapls_ib_connect(IN DAT_EP_HANDLE ep_handle, IN DAT_IA_ADDRESS_PTR remote_ia_address, IN DAT_CONN_QUAL remote_conn_qual, IN DAT_COUNT prd_size, IN DAPL_PRIVATE *prd_ptr, IN DAT_TIMEOUT timeout) { dapl_ep_connect_t args; DAPL_EP *ep_p = (DAPL_EP *)ep_handle; struct sockaddr *s; char addr_buf[64]; ib_gid_t dgid; int retval; struct sockaddr_in6 *v6addr; struct sockaddr_in *v4addr; dapl_ia_addr_t *sap; s = (struct sockaddr *)remote_ia_address; dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_connect: ep 0x%p\n" " addr %s, conn_qual %016llu, ep_hkey %016llx\n" " prd_size %d, timeout 0x%x\n", ep_p, dapls_inet_ntop(s, addr_buf, 64), remote_conn_qual, ep_p->qp_handle->ep_hkey, prd_size, timeout); if (ep_p->qp_handle == NULL) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_connect: ep 0x%p, addr %s, conn_qual %016llu, " "qp_handle == NULL\n", ep_p, dapls_inet_ntop(s, addr_buf, 64), remote_conn_qual); return (DAT_INVALID_PARAMETER); } if (timeout == DAT_TIMEOUT_INFINITE) { args.epc_timeout = 0; } else { args.epc_timeout = timeout; } /* resolve remote address to dgid */ retval = dapls_ns_lookup_address(ep_p->header.owner_ia, remote_ia_address, timeout, &dgid); if (retval == DAT_SUCCESS) { args.epc_dgid = dgid; } else if ((retval & DAT_SUBTYPE_MASK) == DAT_INVALID_ADDRESS_UNREACHABLE) { /* let the kernel driver look up the dgid from ATS */ args.epc_dgid.gid_guid = 0ULL; args.epc_dgid.gid_prefix = 0ULL; } else { return (retval); } args.epc_sid = remote_conn_qual; args.epc_hkey = ep_p->qp_handle->ep_hkey; sap = (dapl_ia_addr_t *)&args.epc_raddr_sadata; /* * filled in the remote_ia_address for consistent though * not necessary when dapls_ns_lookup_address has resolved the dgid */ switch (s->sa_family) { case AF_INET: /* LINTED: E_BAD_PTR_CAST_ALIGN */ v4addr = (struct sockaddr_in *)s; sap->iad_v4pad[0] = 0; sap->iad_v4pad[1] = 0; sap->iad_v4pad[2] = 0; sap->iad_v4 = v4addr->sin_addr; break; case AF_INET6: /* LINTED: E_BAD_PTR_CAST_ALIGN */ v6addr = (struct sockaddr_in6 *)s; sap->iad_v6 = v6addr->sin6_addr; break; } /* establish the hello message */ (void) dapl_os_memzero((void *)&prd_ptr->hello_msg, sizeof (DAPL_HELLO_MSG)); /* on ATS leave the msg blank to avoid confusion to 3rd parties */ if ((args.epc_dgid.gid_guid | args.epc_dgid.gid_prefix)) { prd_ptr->hello_msg.hi_checksum = DAPL_CHECKSUM; prd_ptr->hello_msg.hi_clen = prd_size; prd_ptr->hello_msg.hi_mid = 0; prd_ptr->hello_msg.hi_vers = DAPL_HELLO_MSG_VERS; /* fill in local address */ s = (struct sockaddr *) &ep_p->header.owner_ia->hca_ptr->hca_address; prd_ptr->hello_msg.hi_ipv = (uint8_t)s->sa_family; switch (s->sa_family) { case AF_INET: /* LINTED: E_BAD_PTR_CAST_ALIGN */ v4addr = (struct sockaddr_in *)s; prd_ptr->hello_msg.hi_port = v4addr->sin_port; prd_ptr->hello_msg.hi_v4ipaddr = v4addr->sin_addr; break; case AF_INET6: /* LINTED: E_BAD_PTR_CAST_ALIGN */ v6addr = (struct sockaddr_in6 *)s; prd_ptr->hello_msg.hi_port = v6addr->sin6_port; prd_ptr->hello_msg.hi_v6ipaddr = v6addr->sin6_addr; break; default: break; /* fall through */ } } if (prd_size > 0) { (void) dapl_os_memcpy((void *)&args.epc_priv[0], (void *)prd_ptr, sizeof (DAPL_PRIVATE)); } else { (void) dapl_os_memcpy((void *) &args.epc_priv[DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE], (void *)&prd_ptr->hello_msg, sizeof (DAPL_HELLO_MSG)); } args.epc_priv_sz = sizeof (DAPL_PRIVATE); retval = ioctl(ep_p->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd, DAPL_EP_CONNECT, &args); if (retval != 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "dapls_ib_connect: connect failed %s, retval %d\n\n", strerror(errno), retval); return (dapls_convert_error(errno, retval)); } dapl_dbg_log(DAPL_DBG_TYPE_CM, "dapls_ib_connect: connected to %s\n\n", dapls_inet_ntop(s, addr_buf, 64)); return (DAT_SUCCESS); }
static int dapls_ns_resolve_addr(int af, struct sockaddr *addr, DAT_TIMEOUT timeout) { struct sockaddr_storage sock; struct sockaddr_in *v4dest; struct sockaddr_in6 *v6dest; struct pollfd pollfd; int fd, retval; int tmo; int ip_version; if (af == AF_INET) { ip_version = 4; } else if (af == AF_INET6) { ip_version = 6; } else { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_resolve_addr: invalid af %d\n", af); return (-1); } fd = socket(af, SOCK_STREAM, 0); if (fd < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_resolve_addr: ipv%d, cannot create socket %s\n", ip_version, strerror(errno)); return (-1); } /* * set socket to non-blocking mode */ retval = fcntl(fd, F_SETFL, O_NONBLOCK); if (retval < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_resolve_addr: ipv%d, fcntl failed: %s\n", ip_version, strerror(errno)); (void) close(fd); return (-1); } /* * connect to the discard port (9) at the dest IP */ (void) dapl_os_memzero(&sock, sizeof (sock)); if (af == AF_INET) { v4dest = (struct sockaddr_in *)&sock; v4dest->sin_family = AF_INET; v4dest->sin_addr.s_addr = /* LINTED: E_BAD_PTR_CAST_ALIGN */ ((struct sockaddr_in *)addr)->sin_addr.s_addr; v4dest->sin_port = htons(9); retval = connect(fd, (struct sockaddr *)v4dest, sizeof (struct sockaddr_in)); } else { v6dest = (struct sockaddr_in6 *)&sock; v6dest->sin6_family = AF_INET6; /* LINTED: E_BAD_PTR_CAST_ALIGN */ (void) dapl_os_memcpy(&v6dest->sin6_addr, &((struct sockaddr_in6 *)addr)->sin6_addr, sizeof (struct sockaddr_in6)); v6dest->sin6_port = htons(9); retval = connect(fd, (struct sockaddr *)v6dest, sizeof (struct sockaddr_in6)); } /* * we can return immediately if connect succeeds */ if (retval == 0) { (void) close(fd); return (0); } /* * receiving a RST means that the arp/nd entry should * already be resolved */ if (retval < 0 && errno == ECONNREFUSED) { errno = 0; (void) close(fd); return (0); } /* * for all other cases, we poll on the fd */ pollfd.fd = fd; pollfd.events = POLLIN | POLLOUT; pollfd.revents = 0; if (timeout == DAT_TIMEOUT_INFINITE || timeout == 0) { /* * -1 means infinite */ tmo = -1; } else { /* * convert timeout from usecs to msecs */ tmo = timeout/1000; } retval = poll(&pollfd, 1, tmo); if (retval > 0) { int so_error = 0, len = sizeof (so_error); retval = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len); if (retval == 0) { /* * we only return 0 if so_error == 0 or * so_error == ECONNREFUSED. for all other * cases retval is non-zero. */ if (so_error != 0 && so_error != ECONNREFUSED) { retval = -1; errno = so_error; dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_resolve_addr: ipv%d, so_error: %s\n", ip_version, strerror(errno)); } } else { /* * if retval != 0, it must be -1. and errno must * have been set by getsockopt. */ dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_resolve_addr: ipv%d, getsockopt: %s\n", ip_version, strerror(errno)); } } else { if (retval == 0) { errno = ETIMEDOUT; } retval = -1; dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_resolve_addr: ipv%d, poll: %s\n", ip_version, strerror(errno)); } (void) close(fd); return (retval); }
DAT_RETURN dapls_ns_lookup_v6( IN DAPL_IA *ia_ptr, IN struct sockaddr_in6 *addr, IN DAT_TIMEOUT timeout, OUT ib_gid_t *gid) { struct lifreq lifr; uchar_t *mac; int s, retries = 0; s = socket(AF_INET6, SOCK_DGRAM, 0); if (s < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_lookup_v6: socket: %s\n", strerror(errno)); return (DAT_INTERNAL_ERROR); } if (dapls_ns_subnet_match_v6(s, ia_ptr, addr) != 0) { (void) close(s); return (DAT_INVALID_ADDRESS); } (void) dapl_os_memzero(&lifr, sizeof (lifr)); (void) dapl_os_memcpy(&lifr.lifr_nd.lnr_addr, addr, sizeof (*addr)); (void) dapl_os_strcpy(lifr.lifr_name, ia_ptr->hca_ptr->name); again:; if (ioctl(s, SIOCLIFGETND, (caddr_t)&lifr) < 0) { /* * if SIOCLIFGETND failed, we force the ND * cache to be filled by connecting to the * destination IP address. */ if (retries < NS_MAX_RETRIES && dapls_ns_send_packet_v6(s, addr) == 0 && dapls_ns_resolve_addr(AF_INET6, (struct sockaddr *)addr, timeout) == 0) { retries++; goto again; } dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_lookup_v6: giving up\n"); (void) close(s); return (DAT_ERROR(DAT_INVALID_ADDRESS, DAT_INVALID_ADDRESS_UNREACHABLE)); } if (lifr.lifr_nd.lnr_hdw_len == 0 && retries <= NS_MAX_RETRIES) { /* * lnr_hdw_len == 0 means that the ND entry * is still incomplete. we need to retry the ioctl. */ retries++; (void) sleep(1); goto again; } (void) close(s); mac = (uchar_t *)lifr.lifr_nd.lnr_hdw_addr; if (lifr.lifr_nd.lnr_hdw_len >= sizeof (ipoib_mac_t)) { ib_gid_t tmp_gid; /* LINTED: E_BAD_PTR_CAST_ALIGN */ (void) dapl_os_memcpy(&tmp_gid, &((ipoib_mac_t *)mac)->ipoib_gidpref, sizeof (ib_gid_t)); /* * gids from the ND table are in network order, convert * the gids from network order to host byte order */ gid->gid_prefix = BETOH_64(tmp_gid.gid_prefix); gid->gid_guid = BETOH_64(tmp_gid.gid_guid); } else { int i, len; len = lifr.lifr_nd.lnr_hdw_len; dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_lookup_v6: failed, non IB address: " "len = %d, addr = 0x", len); if (len > 0) { for (i = 0; i < len; i++) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "%02x", (int)mac[i] & 0xff); } } else { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "0"); } dapl_dbg_log(DAPL_DBG_TYPE_ERR, "\n"); return (DAT_INVALID_ADDRESS); } return (DAT_SUCCESS); }
DAT_RETURN dapls_ns_lookup_v4( IN DAPL_IA *ia_ptr, IN struct sockaddr_in *addr, IN DAT_TIMEOUT timeout, OUT ib_gid_t *gid) { struct xarpreq ar; struct sockaddr_in *sin; uchar_t *mac; int s, retries = 0; (void) dapl_os_memzero(&ar, sizeof (ar)); sin = (struct sockaddr_in *)&ar.xarp_pa; sin->sin_family = AF_INET; sin->sin_addr.s_addr = addr->sin_addr.s_addr; ar.xarp_ha.sdl_family = AF_LINK; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_lookup_v4: socket: %s\n", strerror(errno)); return (DAT_INTERNAL_ERROR); } if (dapls_ns_subnet_match_v4(s, ia_ptr, addr) != 0) { (void) close(s); return (DAT_INVALID_ADDRESS); } again:; if (ioctl(s, SIOCGXARP, (caddr_t)&ar) < 0) { /* * if SIOCGXARP failed, we force the ARP * cache to be filled by connecting to the * destination IP address. */ if (retries <= NS_MAX_RETRIES && dapls_ns_resolve_addr(AF_INET, (struct sockaddr *)addr, timeout) == 0) { retries++; goto again; } dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_lookup_v4: giving up\n"); (void) close(s); return (DAT_ERROR(DAT_INVALID_ADDRESS, DAT_INVALID_ADDRESS_UNREACHABLE)); } if ((ar.xarp_flags & ATF_COM) == 0 && ar.xarp_ha.sdl_type == IFT_IB && retries <= NS_MAX_RETRIES) { /* * we get here if arp resolution is still incomplete */ retries++; (void) sleep(1); goto again; } (void) close(s); mac = (uchar_t *)LLADDR(&ar.xarp_ha); if (ar.xarp_flags & ATF_COM && ar.xarp_ha.sdl_type == IFT_IB && ar.xarp_ha.sdl_alen >= sizeof (ipoib_mac_t)) { ib_gid_t tmp_gid; /* LINTED: E_BAD_PTR_CAST_ALIGN */ (void) dapl_os_memcpy(&tmp_gid, &((ipoib_mac_t *)mac)->ipoib_gidpref, sizeof (ib_gid_t)); /* * gids from the ARP table are in network order, convert * the gids from network order to host byte order */ gid->gid_prefix = BETOH_64(tmp_gid.gid_prefix); gid->gid_guid = BETOH_64(tmp_gid.gid_guid); } else { int i, len; len = ar.xarp_ha.sdl_alen; dapl_dbg_log(DAPL_DBG_TYPE_ERR, "ns_lookup_v4: failed, non IB address: " "len = %d, addr = 0x", len); if (len > 0) { for (i = 0; i < len; i++) { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "%02x", (int)mac[i] & 0xff); } } else { dapl_dbg_log(DAPL_DBG_TYPE_ERR, "0"); } dapl_dbg_log(DAPL_DBG_TYPE_ERR, "\n"); return (DAT_INVALID_ADDRESS); } return (DAT_SUCCESS); }