| /* | |
| * Copyright (c) 2010-2014 Intel Corporation. All rights reserved. | |
| * | |
| * This software is available to you under a choice of one of two | |
| * licenses. You may choose to be licensed under the terms of the GNU | |
| * General Public License (GPL) Version 2, available from the file | |
| * COPYING in the main directory of this source tree, or the | |
| * OpenIB.org BSD license below: | |
| * | |
| * Redistribution and use in source and binary forms, with or | |
| * without modification, are permitted provided that the following | |
| * conditions are met: | |
| * | |
| * - Redistributions of source code must retain the above | |
| * copyright notice, this list of conditions and the following | |
| * disclaimer. | |
| * | |
| * - Redistributions in binary form must reproduce the above | |
| * copyright notice, this list of conditions and the following | |
| * disclaimer in the documentation and/or other materials | |
| * provided with the distribution. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| * SOFTWARE. | |
| * | |
| * $Id: cm.c 3453 2005-09-15 21:43:21Z sean.hefty $ | |
| */ | |
| #include <config.h> | |
| #include <sys/types.h> | |
| #include <sys/socket.h> | |
| #include <netdb.h> | |
| #include <unistd.h> | |
| #include "cma.h" | |
| #include <rdma/rdma_cma.h> | |
| #include <infiniband/ib.h> | |
| static struct rdma_addrinfo nohints; | |
| static void ucma_convert_to_ai(struct addrinfo *ai, | |
| const struct rdma_addrinfo *rai) | |
| { | |
| memset(ai, 0, sizeof(*ai)); | |
| if (rai->ai_flags & RAI_PASSIVE) | |
| ai->ai_flags = AI_PASSIVE; | |
| if (rai->ai_flags & RAI_NUMERICHOST) | |
| ai->ai_flags |= AI_NUMERICHOST; | |
| if (rai->ai_family != AF_IB) | |
| ai->ai_family = rai->ai_family; | |
| switch (rai->ai_qp_type) { | |
| case IBV_QPT_RC: | |
| case IBV_QPT_UC: | |
| case IBV_QPT_XRC_SEND: | |
| case IBV_QPT_XRC_RECV: | |
| ai->ai_socktype = SOCK_STREAM; | |
| break; | |
| case IBV_QPT_UD: | |
| ai->ai_socktype = SOCK_DGRAM; | |
| break; | |
| } | |
| switch (rai->ai_port_space) { | |
| case RDMA_PS_TCP: | |
| ai->ai_protocol = IPPROTO_TCP; | |
| break; | |
| case RDMA_PS_IPOIB: | |
| case RDMA_PS_UDP: | |
| ai->ai_protocol = IPPROTO_UDP; | |
| break; | |
| case RDMA_PS_IB: | |
| if (ai->ai_socktype == SOCK_STREAM) | |
| ai->ai_protocol = IPPROTO_TCP; | |
| else if (ai->ai_socktype == SOCK_DGRAM) | |
| ai->ai_protocol = IPPROTO_UDP; | |
| break; | |
| } | |
| if (rai->ai_flags & RAI_PASSIVE) { | |
| ai->ai_addrlen = rai->ai_src_len; | |
| ai->ai_addr = rai->ai_src_addr; | |
| } else { | |
| ai->ai_addrlen = rai->ai_dst_len; | |
| ai->ai_addr = rai->ai_dst_addr; | |
| } | |
| ai->ai_canonname = rai->ai_dst_canonname; | |
| ai->ai_next = NULL; | |
| } | |
| static int ucma_copy_addr(struct sockaddr **dst, socklen_t *dst_len, | |
| struct sockaddr *src, socklen_t src_len) | |
| { | |
| *dst = malloc(src_len); | |
| if (!(*dst)) | |
| return ERR(ENOMEM); | |
| memcpy(*dst, src, src_len); | |
| *dst_len = src_len; | |
| return 0; | |
| } | |
| void ucma_set_sid(enum rdma_port_space ps, struct sockaddr *addr, | |
| struct sockaddr_ib *sib) | |
| { | |
| __be16 port; | |
| port = addr ? ucma_get_port(addr) : 0; | |
| sib->sib_sid = htobe64(((uint64_t) ps << 16) + be16toh(port)); | |
| if (ps) | |
| sib->sib_sid_mask = htobe64(RDMA_IB_IP_PS_MASK); | |
| if (port) | |
| sib->sib_sid_mask |= htobe64(RDMA_IB_IP_PORT_MASK); | |
| } | |
| static int ucma_convert_in6(int ps, struct sockaddr_ib **dst, socklen_t *dst_len, | |
| struct sockaddr_in6 *src, socklen_t src_len) | |
| { | |
| *dst = calloc(1, sizeof(struct sockaddr_ib)); | |
| if (!(*dst)) | |
| return ERR(ENOMEM); | |
| (*dst)->sib_family = AF_IB; | |
| (*dst)->sib_pkey = htobe16(0xFFFF); | |
| (*dst)->sib_flowinfo = src->sin6_flowinfo; | |
| ib_addr_set(&(*dst)->sib_addr, src->sin6_addr.s6_addr32[0], | |
| src->sin6_addr.s6_addr32[1], src->sin6_addr.s6_addr32[2], | |
| src->sin6_addr.s6_addr32[3]); | |
| ucma_set_sid(ps, (struct sockaddr *) src, *dst); | |
| (*dst)->sib_scope_id = src->sin6_scope_id; | |
| *dst_len = sizeof(struct sockaddr_ib); | |
| return 0; | |
| } | |
| static int ucma_convert_to_rai(struct rdma_addrinfo *rai, | |
| const struct rdma_addrinfo *hints, | |
| const struct addrinfo *ai) | |
| { | |
| int ret; | |
| if (hints->ai_qp_type) { | |
| rai->ai_qp_type = hints->ai_qp_type; | |
| } else { | |
| switch (ai->ai_socktype) { | |
| case SOCK_STREAM: | |
| rai->ai_qp_type = IBV_QPT_RC; | |
| break; | |
| case SOCK_DGRAM: | |
| rai->ai_qp_type = IBV_QPT_UD; | |
| break; | |
| } | |
| } | |
| if (hints->ai_port_space) { | |
| rai->ai_port_space = hints->ai_port_space; | |
| } else { | |
| switch (ai->ai_protocol) { | |
| case IPPROTO_TCP: | |
| rai->ai_port_space = RDMA_PS_TCP; | |
| break; | |
| case IPPROTO_UDP: | |
| rai->ai_port_space = RDMA_PS_UDP; | |
| break; | |
| } | |
| } | |
| if (ai->ai_flags & AI_PASSIVE) { | |
| rai->ai_flags = RAI_PASSIVE; | |
| if (ai->ai_canonname) | |
| rai->ai_src_canonname = strdup(ai->ai_canonname); | |
| if ((hints->ai_flags & RAI_FAMILY) && (hints->ai_family == AF_IB) && | |
| (hints->ai_flags & RAI_NUMERICHOST)) { | |
| rai->ai_family = AF_IB; | |
| ret = ucma_convert_in6(rai->ai_port_space, | |
| (struct sockaddr_ib **) &rai->ai_src_addr, | |
| &rai->ai_src_len, | |
| (struct sockaddr_in6 *) ai->ai_addr, | |
| ai->ai_addrlen); | |
| } else { | |
| rai->ai_family = ai->ai_family; | |
| ret = ucma_copy_addr(&rai->ai_src_addr, &rai->ai_src_len, | |
| ai->ai_addr, ai->ai_addrlen); | |
| } | |
| } else { | |
| if (ai->ai_canonname) | |
| rai->ai_dst_canonname = strdup(ai->ai_canonname); | |
| if ((hints->ai_flags & RAI_FAMILY) && (hints->ai_family == AF_IB) && | |
| (hints->ai_flags & RAI_NUMERICHOST)) { | |
| rai->ai_family = AF_IB; | |
| ret = ucma_convert_in6(rai->ai_port_space, | |
| (struct sockaddr_ib **) &rai->ai_dst_addr, | |
| &rai->ai_dst_len, | |
| (struct sockaddr_in6 *) ai->ai_addr, | |
| ai->ai_addrlen); | |
| } else { | |
| rai->ai_family = ai->ai_family; | |
| ret = ucma_copy_addr(&rai->ai_dst_addr, &rai->ai_dst_len, | |
| ai->ai_addr, ai->ai_addrlen); | |
| } | |
| } | |
| return ret; | |
| } | |
| static int ucma_getaddrinfo(const char *node, const char *service, | |
| const struct rdma_addrinfo *hints, | |
| struct rdma_addrinfo *rai) | |
| { | |
| struct addrinfo ai_hints; | |
| struct addrinfo *ai; | |
| int ret; | |
| if (hints != &nohints) { | |
| ucma_convert_to_ai(&ai_hints, hints); | |
| ret = getaddrinfo(node, service, &ai_hints, &ai); | |
| } else { | |
| ret = getaddrinfo(node, service, NULL, &ai); | |
| } | |
| if (ret) | |
| return ret; | |
| ret = ucma_convert_to_rai(rai, hints, ai); | |
| freeaddrinfo(ai); | |
| return ret; | |
| } | |
| int rdma_getaddrinfo(const char *node, const char *service, | |
| const struct rdma_addrinfo *hints, | |
| struct rdma_addrinfo **res) | |
| { | |
| struct rdma_addrinfo *rai; | |
| int ret; | |
| if (!service && !node && !hints) | |
| return ERR(EINVAL); | |
| ret = ucma_init(); | |
| if (ret) | |
| return ret; | |
| if (hints && hints->ai_flags & RAI_SA) { | |
| if (node || (hints->ai_flags & RAI_DNS)) | |
| return ERR(EOPNOTSUPP); | |
| return ucma_getaddrinfo_sa(service, res); | |
| } | |
| rai = calloc(1, sizeof(*rai)); | |
| if (!rai) | |
| return ERR(ENOMEM); | |
| if (!hints) | |
| hints = &nohints; | |
| if (node || service) { | |
| ret = ucma_getaddrinfo(node, service, hints, rai); | |
| } else { | |
| rai->ai_flags = hints->ai_flags; | |
| rai->ai_family = hints->ai_family; | |
| rai->ai_qp_type = hints->ai_qp_type; | |
| rai->ai_port_space = hints->ai_port_space; | |
| if (hints->ai_dst_len) { | |
| ret = ucma_copy_addr(&rai->ai_dst_addr, &rai->ai_dst_len, | |
| hints->ai_dst_addr, hints->ai_dst_len); | |
| } | |
| } | |
| if (ret) | |
| goto err; | |
| if (!rai->ai_src_len && hints->ai_src_len) { | |
| ret = ucma_copy_addr(&rai->ai_src_addr, &rai->ai_src_len, | |
| hints->ai_src_addr, hints->ai_src_len); | |
| if (ret) | |
| goto err; | |
| } | |
| if (!(rai->ai_flags & RAI_PASSIVE)) | |
| ucma_ib_resolve(&rai, hints); | |
| *res = rai; | |
| return 0; | |
| err: | |
| rdma_freeaddrinfo(rai); | |
| return ret; | |
| } | |
| void rdma_freeaddrinfo(struct rdma_addrinfo *res) | |
| { | |
| struct rdma_addrinfo *rai; | |
| while (res) { | |
| rai = res; | |
| res = res->ai_next; | |
| if (rai->ai_connect) | |
| free(rai->ai_connect); | |
| if (rai->ai_route) | |
| free(rai->ai_route); | |
| if (rai->ai_src_canonname) | |
| free(rai->ai_src_canonname); | |
| if (rai->ai_dst_canonname) | |
| free(rai->ai_dst_canonname); | |
| if (rai->ai_src_addr) | |
| free(rai->ai_src_addr); | |
| if (rai->ai_dst_addr) | |
| free(rai->ai_dst_addr); | |
| free(rai); | |
| } | |
| } |