| /* | |
| * Copyright (c) 2013-2016 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. | |
| * | |
| */ | |
| #include "config.h" | |
| #include <systemd/sd-daemon.h> | |
| #include <getopt.h> | |
| #include "iwarp_pm.h" | |
| #include <sys/types.h> | |
| #include <fcntl.h> | |
| static const char iwpm_ulib_name [] = "iWarpPortMapperUser"; | |
| static __u16 iwpm_version = IWPM_UABI_VERSION; | |
| LIST_HEAD(mapping_reqs); /* list of map tracking objects */ | |
| LIST_HEAD(pending_messages); /* list of pending wire messages */ | |
| iwpm_client client_list[IWARP_PM_MAX_CLIENTS];/* list of iwarp port mapper clients */ | |
| static int mapinfo_num_list[IWARP_PM_MAX_CLIENTS]; /* list of iwarp port mapper clients */ | |
| /* socket handles */ | |
| static int pmv4_sock, pmv6_sock, netlink_sock, pmv4_client_sock, pmv6_client_sock; | |
| static pthread_t map_req_thread; /* handling mapping requests timeout */ | |
| pthread_cond_t cond_req_complete; | |
| pthread_mutex_t map_req_mutex = PTHREAD_MUTEX_INITIALIZER; | |
| int wake = 0; /* set if map_req_thread is wake */ | |
| static pthread_t pending_msg_thread; /* sending iwpm wire messages */ | |
| pthread_cond_t cond_pending_msg; | |
| pthread_mutex_t pending_msg_mutex = PTHREAD_MUTEX_INITIALIZER; | |
| static void iwpm_cleanup(void); | |
| static int print_mappings = 0; | |
| static int send_iwpm_mapinfo_request(int nl_sock, int client); | |
| /** | |
| * iwpm_signal_handler - Handle signals which iwarp port mapper receives | |
| * @signum: the number of the caught signal | |
| */ | |
| static void iwpm_signal_handler(int signum) | |
| { | |
| switch(signum) { | |
| case SIGHUP: | |
| syslog(LOG_WARNING, "iwpm_signal_handler: Received SIGHUP signal\n"); | |
| iwpm_cleanup(); | |
| exit(signum); | |
| break; | |
| case SIGTERM: | |
| syslog(LOG_WARNING, "iwpm_signal_handler: Received SIGTERM signal\n"); | |
| iwpm_cleanup(); | |
| exit(EXIT_SUCCESS); | |
| break; | |
| case SIGUSR1: | |
| syslog(LOG_WARNING, "iwpm_signal_handler: Received SIGUSR1 signal\n"); | |
| print_mappings = 1; | |
| break; | |
| default: | |
| syslog(LOG_WARNING, "iwpm_signal_handler: Unhandled signal %d\n", signum); | |
| break; | |
| } | |
| } | |
| /** | |
| * iwpm_mapping_reqs_handler - Handle mapping requests timeouts and retries | |
| */ | |
| static void *iwpm_mapping_reqs_handler(void *unused) | |
| { | |
| iwpm_mapping_request *iwpm_map_req, *next_map_req; | |
| int ret = 0; | |
| while (1) { | |
| pthread_mutex_lock(&map_req_mutex); | |
| wake = 0; | |
| if (list_empty(&mapping_reqs)) { | |
| /* wait until a new mapping request is posted */ | |
| ret = pthread_cond_wait(&cond_req_complete, &map_req_mutex); | |
| if (ret) { | |
| syslog(LOG_WARNING, "mapping_reqs_handler: " | |
| "Condition wait failed (ret = %d)\n", ret); | |
| pthread_mutex_unlock(&map_req_mutex); | |
| goto mapping_reqs_handler_exit; | |
| } | |
| } | |
| pthread_mutex_unlock(&map_req_mutex); | |
| /* update timeouts of the posted mapping requests */ | |
| do { | |
| pthread_mutex_lock(&map_req_mutex); | |
| wake = 1; | |
| list_for_each_safe(&mapping_reqs, iwpm_map_req, next_map_req, entry) { | |
| if (iwpm_map_req->timeout > 0) { | |
| if (iwpm_map_req->timeout < IWPM_MAP_REQ_TIMEOUT && | |
| iwpm_map_req->msg_type != IWARP_PM_REQ_ACK) { | |
| /* the request is still incomplete, retransmit the message (every 1sec) */ | |
| add_iwpm_pending_msg(iwpm_map_req->send_msg); | |
| iwpm_debug(IWARP_PM_RETRY_DBG, "mapping_reqs_handler: " | |
| "Going to retransmit a msg, map request " | |
| "(assochandle = %llu, type = %u, timeout = %d)\n", | |
| iwpm_map_req->assochandle, iwpm_map_req->msg_type, | |
| iwpm_map_req->timeout); | |
| } | |
| iwpm_map_req->timeout--; /* hang around for 10s */ | |
| } else { | |
| remove_iwpm_map_request(iwpm_map_req); | |
| } | |
| } | |
| pthread_mutex_unlock(&map_req_mutex); | |
| sleep(1); | |
| } while (!list_empty(&mapping_reqs)); | |
| } | |
| mapping_reqs_handler_exit: | |
| return NULL; | |
| } | |
| /** | |
| * iwpm_pending_msgs_handler - Handle sending iwarp port mapper wire messages | |
| */ | |
| static void *iwpm_pending_msgs_handler(void *unused) | |
| { | |
| iwpm_pending_msg *pending_msg; | |
| iwpm_send_msg *send_msg; | |
| int retries = IWPM_SEND_MSG_RETRIES; | |
| int ret = 0; | |
| pthread_mutex_lock(&pending_msg_mutex); | |
| while (1) { | |
| /* wait until a new message is posted */ | |
| ret = pthread_cond_wait(&cond_pending_msg, &pending_msg_mutex); | |
| if (ret) { | |
| syslog(LOG_WARNING, "pending_msgs_handler: " | |
| "Condition wait failed (ret = %d)\n", ret); | |
| pthread_mutex_unlock(&pending_msg_mutex); | |
| goto pending_msgs_handler_exit; | |
| } | |
| /* try sending out each pending message and remove it from the list */ | |
| while ((pending_msg = list_pop(&pending_messages, | |
| iwpm_pending_msg, entry))) { | |
| retries = IWPM_SEND_MSG_RETRIES; | |
| while (retries) { | |
| send_msg = &pending_msg->send_msg; | |
| /* send out the message */ | |
| int bytes_sent = sendto(send_msg->pm_sock, (char *)&send_msg->data, | |
| send_msg->length, 0, | |
| (struct sockaddr *)&send_msg->dest_addr, | |
| sizeof(send_msg->dest_addr)); | |
| if (bytes_sent != send_msg->length) { | |
| retries--; | |
| syslog(LOG_WARNING, "pending_msgs_handler: " | |
| "Could not send to PM Socket send_msg = %p, retries = %d\n", | |
| send_msg, retries); | |
| } else | |
| retries = 0; /* no need to retry */ | |
| } | |
| free(pending_msg); | |
| } | |
| } | |
| pthread_mutex_unlock(&pending_msg_mutex); | |
| pending_msgs_handler_exit: | |
| return NULL; | |
| } | |
| static int send_iwpm_error_msg(__u32, __u16, int, int); | |
| /* Register pid query - nlmsg attributes */ | |
| static struct nla_policy reg_pid_policy[IWPM_NLA_REG_PID_MAX] = { | |
| [IWPM_NLA_REG_PID_SEQ] = { .type = NLA_U32 }, | |
| [IWPM_NLA_REG_IF_NAME] = { .type = NLA_STRING, | |
| .maxlen = IWPM_IFNAME_SIZE }, | |
| [IWPM_NLA_REG_IBDEV_NAME] = { .type = NLA_STRING, | |
| .maxlen = IWPM_ULIBNAME_SIZE }, | |
| [IWPM_NLA_REG_ULIB_NAME] = { .type = NLA_STRING, | |
| .maxlen = IWPM_ULIBNAME_SIZE } | |
| }; | |
| /** | |
| * process_iwpm_register_pid - Service a client query for port mapper pid | |
| * @req_nlh: netlink header of the received client message | |
| * @client_idx: the index of the client (unique for each iwpm client) | |
| * @nl_sock: netlink socket to send a message back to the client | |
| * | |
| * Process a query and send a response to the client which contains the iwpm pid | |
| * nlmsg response attributes: | |
| * IWPM_NLA_RREG_PID_SEQ | |
| * IWPM_NLA_RREG_IBDEV_NAME | |
| * IWPM_NLA_RREG_ULIB_NAME | |
| * IWPM_NLA_RREG_ULIB_VER | |
| * IWPM_NLA_RREG_PID_ERR | |
| */ | |
| static int process_iwpm_register_pid(struct nlmsghdr *req_nlh, int client_idx, int nl_sock) | |
| { | |
| iwpm_client *client; | |
| struct nlattr *nltb [IWPM_NLA_REG_PID_MAX]; | |
| struct nl_msg *resp_nlmsg = NULL; | |
| const char *ifname, *devname, *libname; | |
| __u16 err_code = 0; | |
| const char *msg_type = "Register Pid Request"; | |
| const char *str_err; | |
| int ret = -EINVAL; | |
| if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_REG_PID_MAX, reg_pid_policy, nltb, msg_type)) { | |
| str_err = "Received Invalid nlmsg"; | |
| err_code = IWPM_INVALID_NLMSG_ERR; | |
| goto register_pid_error; | |
| } | |
| ifname = (const char *)nla_get_string(nltb[IWPM_NLA_REG_IF_NAME]); | |
| devname = (const char *)nla_get_string(nltb[IWPM_NLA_REG_IBDEV_NAME]); | |
| libname = (const char *)nla_get_string(nltb[IWPM_NLA_REG_ULIB_NAME]); | |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "process_register_pid: PID request from " | |
| "IB device %s Ethernet device %s User library %s " | |
| "(client idx = %d, msg seq = %u).\n", | |
| devname, ifname, libname, client_idx, req_nlh->nlmsg_seq); | |
| /* register a first time client */ | |
| client = &client_list[client_idx]; | |
| if (!client->valid) { | |
| memcpy(client->ibdevname, devname, IWPM_DEVNAME_SIZE); | |
| memcpy(client->ifname, ifname, IWPM_IFNAME_SIZE); | |
| memcpy(client->ulibname, libname, IWPM_ULIBNAME_SIZE); | |
| client->valid = 1; | |
| } else { /* check client info */ | |
| if (strcmp(client->ulibname, libname)) { | |
| str_err = "Incorrect library version"; | |
| err_code = IWPM_USER_LIB_INFO_ERR; | |
| goto register_pid_error; | |
| } | |
| } | |
| resp_nlmsg = create_iwpm_nlmsg(req_nlh->nlmsg_type, client_idx); | |
| if (!resp_nlmsg) { | |
| ret = -ENOMEM; | |
| str_err = "Unable to create nlmsg response"; | |
| goto register_pid_error; | |
| } | |
| str_err = "Invalid nlmsg attribute"; | |
| if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_RREG_PID_SEQ, req_nlh->nlmsg_seq))) | |
| goto register_pid_error; | |
| if ((ret = nla_put_string(resp_nlmsg, IWPM_NLA_RREG_IBDEV_NAME, devname))) | |
| goto register_pid_error; | |
| if ((ret = nla_put_string(resp_nlmsg, IWPM_NLA_RREG_ULIB_NAME, iwpm_ulib_name))) | |
| goto register_pid_error; | |
| if ((ret = nla_put_u16(resp_nlmsg, IWPM_NLA_RREG_ULIB_VER, iwpm_version))) | |
| goto register_pid_error; | |
| if ((ret = nla_put_u16(resp_nlmsg, IWPM_NLA_RREG_PID_ERR, err_code))) | |
| goto register_pid_error; | |
| if ((ret = send_iwpm_nlmsg(nl_sock, resp_nlmsg, req_nlh->nlmsg_pid))) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto register_pid_error; | |
| } | |
| nlmsg_free(resp_nlmsg); | |
| return 0; | |
| register_pid_error: | |
| if (resp_nlmsg) | |
| nlmsg_free(resp_nlmsg); | |
| syslog(LOG_WARNING, "process_register_pid: %s ret = %d.\n", str_err, ret); | |
| if (err_code) | |
| send_iwpm_error_msg(req_nlh->nlmsg_seq, err_code, client_idx, nl_sock); | |
| return ret; | |
| } | |
| /* Add mapping request - nlmsg attributes */ | |
| static struct nla_policy manage_map_policy[IWPM_NLA_MANAGE_MAPPING_MAX] = { | |
| [IWPM_NLA_MANAGE_MAPPING_SEQ] = { .type = NLA_U32 }, | |
| [IWPM_NLA_MANAGE_ADDR] = { .minlen = sizeof(struct sockaddr_storage) }, | |
| [IWPM_NLA_MANAGE_FLAGS] = { .type = NLA_U32 } | |
| }; | |
| /** | |
| * process_iwpm_add_mapping - Service a client request for mapping of a local address | |
| * @req_nlh: netlink header of the received client message | |
| * @client_idx: the index of the client (unique for each iwpm client) | |
| * @nl_sock: netlink socket to send a message back to the client | |
| * | |
| * Process a mapping request for a local address and send a response to the client | |
| * which contains the mapped local address (IP address and TCP port) | |
| * nlmsg response attributes: | |
| * [IWPM_NLA_RMANAGE_MAPPING_SEQ] | |
| * [IWPM_NLA_RMANAGE_ADDR] | |
| * [IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR] | |
| * [IWPM_NLA_RMANAGE_MAPPING_ERR] | |
| */ | |
| static int process_iwpm_add_mapping(struct nlmsghdr *req_nlh, int client_idx, int nl_sock) | |
| { | |
| iwpm_mapped_port *iwpm_port = NULL; | |
| struct nlattr *nltb [IWPM_NLA_MANAGE_MAPPING_MAX] = {}; | |
| struct nl_msg *resp_nlmsg = NULL; | |
| struct sockaddr_storage *local_addr; | |
| int not_mapped = 1; | |
| __u16 err_code = 0; | |
| const char *msg_type = "Add Mapping Request"; | |
| const char *str_err = ""; | |
| int ret = -EINVAL; | |
| __u32 flags; | |
| int max = IWPM_NLA_MANAGE_MAPPING_MAX; | |
| if (iwpm_version != IWPM_UABI_VERSION) | |
| max--; | |
| if (parse_iwpm_nlmsg(req_nlh, max, manage_map_policy, nltb, msg_type)) { | |
| err_code = IWPM_INVALID_NLMSG_ERR; | |
| str_err = "Received Invalid nlmsg"; | |
| goto add_mapping_error; | |
| } | |
| local_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_MANAGE_ADDR]); | |
| flags = nltb[IWPM_NLA_MANAGE_FLAGS] ? nla_get_u32(nltb[IWPM_NLA_MANAGE_FLAGS]) : 0; | |
| iwpm_port = find_iwpm_mapping(local_addr, not_mapped); | |
| if (iwpm_port) { | |
| if (check_same_sockaddr(local_addr, &iwpm_port->local_addr) && iwpm_port->wcard) { | |
| atomic_fetch_add(&iwpm_port->ref_cnt, 1); | |
| } else { | |
| err_code = IWPM_DUPLICATE_MAPPING_ERR; | |
| str_err = "Duplicate mapped port"; | |
| goto add_mapping_error; | |
| } | |
| } else { | |
| iwpm_port = create_iwpm_mapped_port(local_addr, client_idx, flags); | |
| if (!iwpm_port) { | |
| err_code = IWPM_CREATE_MAPPING_ERR; | |
| str_err = "Unable to create new mapping"; | |
| goto add_mapping_error; | |
| } | |
| } | |
| resp_nlmsg = create_iwpm_nlmsg(req_nlh->nlmsg_type, client_idx); | |
| if (!resp_nlmsg) { | |
| ret = -ENOMEM; | |
| str_err = "Unable to create nlmsg response"; | |
| goto add_mapping_free_error; | |
| } | |
| str_err = "Invalid nlmsg attribute"; | |
| if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_RMANAGE_MAPPING_SEQ, req_nlh->nlmsg_seq))) | |
| goto add_mapping_free_error; | |
| if ((ret = nla_put(resp_nlmsg, IWPM_NLA_RMANAGE_ADDR, | |
| sizeof(struct sockaddr_storage), &iwpm_port->local_addr))) | |
| goto add_mapping_free_error; | |
| if ((ret = nla_put(resp_nlmsg, IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR, | |
| sizeof(struct sockaddr_storage), &iwpm_port->mapped_addr))) | |
| goto add_mapping_free_error; | |
| if ((ret = nla_put_u16(resp_nlmsg, IWPM_NLA_RMANAGE_MAPPING_ERR, err_code))) | |
| goto add_mapping_free_error; | |
| if ((ret = send_iwpm_nlmsg(nl_sock, resp_nlmsg, req_nlh->nlmsg_pid))) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto add_mapping_free_error; | |
| } | |
| /* add the new mapping to the list */ | |
| add_iwpm_mapped_port(iwpm_port); | |
| nlmsg_free(resp_nlmsg); | |
| return 0; | |
| add_mapping_free_error: | |
| if (resp_nlmsg) | |
| nlmsg_free(resp_nlmsg); | |
| if (iwpm_port) { | |
| if (atomic_fetch_sub(&iwpm_port->ref_cnt, 1) == 1) | |
| free_iwpm_port(iwpm_port); | |
| } | |
| add_mapping_error: | |
| syslog(LOG_WARNING, "process_add_mapping: %s (failed request from client = %s).\n", | |
| str_err, client_list[client_idx].ibdevname); | |
| if (err_code) { | |
| /* send error message to the client */ | |
| send_iwpm_error_msg(req_nlh->nlmsg_seq, err_code, client_idx, nl_sock); | |
| } | |
| return ret; | |
| } | |
| /* Query mapping request - nlmsg attributes */ | |
| static struct nla_policy query_map_policy[IWPM_NLA_QUERY_MAPPING_MAX] = { | |
| [IWPM_NLA_QUERY_MAPPING_SEQ] = { .type = NLA_U32 }, | |
| [IWPM_NLA_QUERY_LOCAL_ADDR] = { .minlen = sizeof(struct sockaddr_storage) }, | |
| [IWPM_NLA_QUERY_REMOTE_ADDR] = { .minlen = sizeof(struct sockaddr_storage) }, | |
| [IWPM_NLA_QUERY_FLAGS] = { .type = NLA_U32 } | |
| }; | |
| /** | |
| * process_iwpm_query_mapping - Service a client request for local and remote mapping | |
| * @req_nlh: netlink header of the received client message | |
| * @client_idx: the index of the client (the index is unique for each iwpm client) | |
| * @nl_sock: netlink socket to send a message back to the client | |
| * | |
| * Process a client request for local and remote address mapping | |
| * Create mapping for the local address (IP address and TCP port) | |
| * Send a request to the remote port mapper peer to find out the remote address mapping | |
| */ | |
| static int process_iwpm_query_mapping(struct nlmsghdr *req_nlh, int client_idx, int nl_sock) | |
| { | |
| iwpm_mapped_port *iwpm_port = NULL; | |
| iwpm_mapping_request *iwpm_map_req = NULL; | |
| struct nlattr *nltb [IWPM_NLA_QUERY_MAPPING_MAX] = {}; | |
| struct sockaddr_storage *local_addr, *remote_addr; | |
| sockaddr_union dest_addr; | |
| iwpm_msg_parms msg_parms; | |
| iwpm_send_msg *send_msg = NULL; | |
| int pm_client_sock; | |
| int not_mapped = 1; | |
| __u16 err_code = 0; | |
| const char *msg_type = "Add & Query Mapping Request"; | |
| const char *str_err = ""; | |
| int ret = -EINVAL; | |
| __u32 flags; | |
| int max = IWPM_NLA_QUERY_MAPPING_MAX; | |
| if (iwpm_version != IWPM_UABI_VERSION) | |
| max--; | |
| if (parse_iwpm_nlmsg(req_nlh, max, query_map_policy, nltb, msg_type)) { | |
| err_code = IWPM_INVALID_NLMSG_ERR; | |
| str_err = "Received Invalid nlmsg"; | |
| goto query_mapping_error; | |
| } | |
| local_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]); | |
| remote_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]); | |
| flags = nltb[IWPM_NLA_QUERY_FLAGS] ? nla_get_u32(nltb[IWPM_NLA_QUERY_FLAGS]) : 0; | |
| iwpm_port = find_iwpm_mapping(local_addr, not_mapped); | |
| if (iwpm_port) { | |
| atomic_fetch_add(&iwpm_port->ref_cnt, 1); | |
| } else { | |
| iwpm_port = create_iwpm_mapped_port(local_addr, client_idx, flags); | |
| if (!iwpm_port) { | |
| err_code = IWPM_CREATE_MAPPING_ERR; | |
| str_err = "Unable to create new mapping"; | |
| goto query_mapping_error; | |
| } | |
| } | |
| if (iwpm_port->wcard) { | |
| err_code = IWPM_CREATE_MAPPING_ERR; | |
| str_err = "Invalid wild card mapping"; | |
| goto query_mapping_free_error; | |
| } | |
| /* create iwpm wire message */ | |
| memcpy(&dest_addr.s_sockaddr, remote_addr, sizeof(struct sockaddr_storage)); | |
| switch (dest_addr.s_sockaddr.ss_family) { | |
| case AF_INET: | |
| dest_addr.v4_sockaddr.sin_port = htobe16(IWARP_PM_PORT); | |
| msg_parms.ip_ver = 4; | |
| msg_parms.address_family = AF_INET; | |
| pm_client_sock = pmv4_client_sock; | |
| break; | |
| case AF_INET6: | |
| dest_addr.v6_sockaddr.sin6_port = htobe16(IWARP_PM_PORT); | |
| msg_parms.ip_ver = 6; | |
| msg_parms.address_family = AF_INET6; | |
| pm_client_sock = pmv6_client_sock; | |
| break; | |
| default: | |
| str_err = "Invalid Internet address family"; | |
| goto query_mapping_free_error; | |
| } | |
| /* fill in the remote peer address and the local mapped address */ | |
| copy_iwpm_sockaddr(dest_addr.s_sockaddr.ss_family, remote_addr, NULL, NULL, | |
| &msg_parms.apipaddr[0], &msg_parms.apport); | |
| copy_iwpm_sockaddr(dest_addr.s_sockaddr.ss_family, local_addr, NULL, NULL, | |
| &msg_parms.cpipaddr[0], &msg_parms.cpport); | |
| copy_iwpm_sockaddr(dest_addr.s_sockaddr.ss_family, &iwpm_port->mapped_addr, NULL, NULL, | |
| &msg_parms.mapped_cpipaddr[0], &msg_parms.mapped_cpport); | |
| msg_parms.pmtime = 0; | |
| msg_parms.ver = 0; | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_query_mapping: Local port = 0x%04X, " | |
| "remote port = 0x%04X\n", | |
| be16toh(msg_parms.cpport), be16toh(msg_parms.apport)); | |
| ret = -ENOMEM; | |
| send_msg = malloc(sizeof(iwpm_send_msg)); | |
| if (!send_msg) { | |
| str_err = "Unable to allocate send msg buffer"; | |
| goto query_mapping_free_error; | |
| } | |
| iwpm_map_req = create_iwpm_map_request(req_nlh, &iwpm_port->local_addr, remote_addr, 0, | |
| IWARP_PM_REQ_QUERY, send_msg); | |
| if (!iwpm_map_req) { | |
| str_err = "Unable to allocate mapping request"; | |
| goto query_mapping_free_error; | |
| } | |
| msg_parms.assochandle = iwpm_map_req->assochandle; | |
| form_iwpm_request(&send_msg->data, &msg_parms); | |
| form_iwpm_send_msg(pm_client_sock, &dest_addr.s_sockaddr, msg_parms.msize, send_msg); | |
| add_iwpm_map_request(iwpm_map_req); | |
| add_iwpm_mapped_port(iwpm_port); | |
| return send_iwpm_msg(form_iwpm_request, &msg_parms, &dest_addr.s_sockaddr, pm_client_sock); | |
| query_mapping_free_error: | |
| if (iwpm_port) { | |
| if (atomic_fetch_sub(&iwpm_port->ref_cnt, 1) == 1) | |
| free_iwpm_port(iwpm_port); | |
| } | |
| if (send_msg) | |
| free(send_msg); | |
| if (iwpm_map_req) | |
| free(iwpm_map_req); | |
| query_mapping_error: | |
| syslog(LOG_WARNING, "process_query_mapping: %s (failed request from client = %s).\n", | |
| str_err, client_list[client_idx].ibdevname); | |
| if (err_code) { | |
| /* send error message to the client */ | |
| send_iwpm_error_msg(req_nlh->nlmsg_seq, err_code, client_idx, nl_sock); | |
| } | |
| return ret; | |
| } | |
| /** | |
| * process_iwpm_remove_mapping - Remove a local mapping and close the mapped TCP port | |
| * @req_nlh: netlink header of the received client message | |
| * @client_idx: the index of the client (the index is unique for each iwpm client) | |
| * @nl_sock: netlink socket to send a message to the client | |
| */ | |
| static int process_iwpm_remove_mapping(struct nlmsghdr *req_nlh, int client_idx, int nl_sock) | |
| { | |
| iwpm_mapped_port *iwpm_port = NULL; | |
| struct sockaddr_storage *local_addr; | |
| struct nlattr *nltb [IWPM_NLA_MANAGE_MAPPING_MAX]; | |
| int not_mapped = 1; | |
| const char *msg_type = "Remove Mapping Request"; | |
| int ret = 0; | |
| if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_REMOVE_MAPPING_MAX, manage_map_policy, nltb, msg_type)) { | |
| send_iwpm_error_msg(req_nlh->nlmsg_seq, IWPM_INVALID_NLMSG_ERR, client_idx, nl_sock); | |
| syslog(LOG_WARNING, "process_remove_mapping: Received Invalid nlmsg from client = %d\n", | |
| client_idx); | |
| ret = -EINVAL; | |
| goto remove_mapping_exit; | |
| } | |
| local_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_MANAGE_ADDR]); | |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "process_remove_mapping: Going to remove mapping" | |
| " (client idx = %d)\n", client_idx); | |
| iwpm_port = find_iwpm_same_mapping(local_addr, not_mapped); | |
| if (!iwpm_port) { | |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "process_remove_mapping: Unable to find mapped port object\n"); | |
| print_iwpm_sockaddr(local_addr, "process_remove_mapping: Local address", IWARP_PM_ALL_DBG); | |
| /* the client sends a remove mapping request when terminating a connection | |
| and it is possible that there isn't a successful mapping for this connection */ | |
| goto remove_mapping_exit; | |
| } | |
| if (iwpm_port->owner_client != client_idx) { | |
| syslog(LOG_WARNING, "process_remove_mapping: Invalid request from client = %d\n", | |
| client_idx); | |
| goto remove_mapping_exit; | |
| } | |
| if (atomic_fetch_sub(&iwpm_port->ref_cnt, 1) == 1) { | |
| remove_iwpm_mapped_port(iwpm_port); | |
| free_iwpm_port(iwpm_port); | |
| } | |
| remove_mapping_exit: | |
| return ret; | |
| } | |
| static int send_conn_info_nlmsg(struct sockaddr_storage *local_addr, | |
| struct sockaddr_storage *remote_addr, | |
| struct sockaddr_storage *mapped_loc_addr, | |
| struct sockaddr_storage *mapped_rem_addr, | |
| int owner_client, __u16 nlmsg_type, __u32 nlmsg_seq, | |
| __u32 nlmsg_pid, __u16 nlmsg_err, int nl_sock) | |
| { | |
| struct nl_msg *resp_nlmsg = NULL; | |
| const char *str_err; | |
| int ret; | |
| resp_nlmsg = create_iwpm_nlmsg(nlmsg_type, owner_client); | |
| if (!resp_nlmsg) { | |
| str_err = "Unable to create nlmsg response"; | |
| ret = -ENOMEM; | |
| goto nlmsg_error; | |
| } | |
| str_err = "Invalid nlmsg attribute"; | |
| if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_QUERY_MAPPING_SEQ, nlmsg_seq))) | |
| goto nlmsg_free_error; | |
| if ((ret = nla_put(resp_nlmsg, IWPM_NLA_QUERY_LOCAL_ADDR, | |
| sizeof(struct sockaddr_storage), local_addr))) | |
| goto nlmsg_free_error; | |
| if ((ret = nla_put(resp_nlmsg, IWPM_NLA_QUERY_REMOTE_ADDR, | |
| sizeof(struct sockaddr_storage), remote_addr))) | |
| goto nlmsg_free_error; | |
| if ((ret = nla_put(resp_nlmsg, IWPM_NLA_RQUERY_MAPPED_LOC_ADDR, | |
| sizeof(struct sockaddr_storage), mapped_loc_addr))) | |
| goto nlmsg_free_error; | |
| if ((ret = nla_put(resp_nlmsg, IWPM_NLA_RQUERY_MAPPED_REM_ADDR, | |
| sizeof(struct sockaddr_storage), mapped_rem_addr))) | |
| goto nlmsg_free_error; | |
| if ((ret = nla_put_u16(resp_nlmsg, IWPM_NLA_RQUERY_MAPPING_ERR, nlmsg_err))) | |
| goto nlmsg_free_error; | |
| if ((ret = send_iwpm_nlmsg(nl_sock, resp_nlmsg, nlmsg_pid))) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto nlmsg_free_error; | |
| } | |
| nlmsg_free(resp_nlmsg); | |
| return 0; | |
| nlmsg_free_error: | |
| if (resp_nlmsg) | |
| nlmsg_free(resp_nlmsg); | |
| nlmsg_error: | |
| syslog(LOG_WARNING, "send_conn_info_nlmsg: %s.\n", str_err); | |
| return ret; | |
| } | |
| /** | |
| * process_iwpm_wire_request - Process a mapping query from remote port mapper peer | |
| * @msg_parms: the received iwpm request message | |
| * @recv_addr: address of the remote peer | |
| * @pm_sock: socket handle to send a response to the remote iwpm peer | |
| * | |
| * Look up the accepting peer local address to find the corresponding mapping, | |
| * send reject message to the remote connecting peer, if no mapping is found, | |
| * otherwise, send accept message with the accepting peer mapping info | |
| */ | |
| static int process_iwpm_wire_request(iwpm_msg_parms *msg_parms, int nl_sock, | |
| struct sockaddr_storage *recv_addr, int pm_sock) | |
| { | |
| iwpm_mapped_port *iwpm_port; | |
| iwpm_mapping_request *iwpm_map_req = NULL; | |
| iwpm_mapping_request iwpm_copy_req; | |
| iwpm_send_msg *send_msg = NULL; | |
| struct sockaddr_storage local_addr, mapped_loc_addr; | |
| struct sockaddr_storage remote_addr = {}, mapped_rem_addr = {}; | |
| __u16 nlmsg_type; | |
| int not_mapped = 1; | |
| int ret = 0; | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &local_addr, | |
| &msg_parms->apipaddr[0], NULL, &msg_parms->apport); | |
| iwpm_port = find_iwpm_mapping(&local_addr, not_mapped); | |
| if (!iwpm_port) { | |
| /* could not find mapping for the requested address */ | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_wire_request: " | |
| "Sending Reject to port mapper peer.\n"); | |
| print_iwpm_sockaddr(&local_addr, "process_wire_request: Local address", | |
| IWARP_PM_ALL_DBG); | |
| return send_iwpm_msg(form_iwpm_reject, msg_parms, recv_addr, pm_sock); | |
| } | |
| /* record mapping in the accept message */ | |
| if (iwpm_port->wcard) | |
| msg_parms->apport = get_sockaddr_port(&iwpm_port->mapped_addr); | |
| else | |
| copy_iwpm_sockaddr(msg_parms->address_family, &iwpm_port->mapped_addr, | |
| NULL, NULL, &msg_parms->apipaddr[0], &msg_parms->apport); | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &mapped_loc_addr, | |
| &msg_parms->apipaddr[0], NULL, &msg_parms->apport); | |
| /* check if there is already a request */ | |
| ret = update_iwpm_map_request(msg_parms->assochandle, &mapped_loc_addr, | |
| IWARP_PM_REQ_ACCEPT, &iwpm_copy_req, 0); | |
| if (!ret) { /* found request */ | |
| iwpm_debug(IWARP_PM_WIRE_DBG,"process_wire_request: Detected retransmission " | |
| "map request (assochandle = %llu type = %d timeout = %u complete = %d)\n", | |
| iwpm_copy_req.assochandle, iwpm_copy_req.msg_type, | |
| iwpm_copy_req.timeout, iwpm_copy_req.complete); | |
| return 0; | |
| } | |
| /* allocate response message */ | |
| send_msg = malloc(sizeof(iwpm_send_msg)); | |
| if (!send_msg) { | |
| syslog(LOG_WARNING, "process_wire_request: Unable to allocate send msg.\n"); | |
| return -ENOMEM; | |
| } | |
| form_iwpm_accept(&send_msg->data, msg_parms); | |
| form_iwpm_send_msg(pm_sock, recv_addr, msg_parms->msize, send_msg); | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &remote_addr, | |
| &msg_parms->cpipaddr[0], NULL, &msg_parms->cpport); | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &mapped_rem_addr, | |
| &msg_parms->mapped_cpipaddr[0], NULL, &msg_parms->mapped_cpport); | |
| iwpm_map_req = create_iwpm_map_request(NULL, &mapped_loc_addr, &remote_addr, | |
| msg_parms->assochandle, IWARP_PM_REQ_ACCEPT, send_msg); | |
| if (!iwpm_map_req) { | |
| syslog(LOG_WARNING, "process_wire_request: Unable to allocate mapping request.\n"); | |
| free(send_msg); | |
| return -ENOMEM; | |
| } | |
| add_iwpm_map_request(iwpm_map_req); | |
| ret = send_iwpm_msg(form_iwpm_accept, msg_parms, recv_addr, pm_sock); | |
| if (ret) { | |
| syslog(LOG_WARNING, "process_wire_request: Unable to allocate accept message.\n"); | |
| return ret; | |
| } | |
| nlmsg_type = RDMA_NL_GET_TYPE(iwpm_port->owner_client, RDMA_NL_IWPM_REMOTE_INFO); | |
| ret = send_conn_info_nlmsg(&iwpm_port->local_addr, &remote_addr, | |
| &iwpm_port->mapped_addr, &mapped_rem_addr, | |
| iwpm_port->owner_client, nlmsg_type, 0, 0, 0, nl_sock); | |
| return ret; | |
| } | |
| /** | |
| * process_iwpm_wire_accept - Process accept message from the remote port mapper peer | |
| * @msg_parms: the received iwpm accept message, containing the remote peer mapping info | |
| * @nl_sock: netlink socket to send a message to the iwpm client | |
| * @recv_addr: address of the remote peer | |
| * @pm_sock: socket handle to send ack message back to the remote peer | |
| * | |
| * Send acknowledgement to the remote/accepting peer, | |
| * send a netlink message with the local and remote mapping info to the iwpm client | |
| * nlmsg response attributes: | |
| * [IWPM_NLA_QUERY_MAPPING_SEQ] | |
| * [IWPM_NLA_QUERY_LOCAL_ADDR] | |
| * [IWPM_NLA_QUERY_REMOTE_ADDR] | |
| * [IWPM_NLA_RQUERY_MAPPED_LOC_ADDR] | |
| * [IWPM_NLA_RQUERY_MAPPED_REM_ADDR] | |
| * [IWPM_NLA_RQUERY_MAPPING_ERR] | |
| */ | |
| static int process_iwpm_wire_accept(iwpm_msg_parms *msg_parms, int nl_sock, | |
| struct sockaddr_storage *recv_addr, int pm_sock) | |
| { | |
| iwpm_mapping_request iwpm_map_req; | |
| iwpm_mapping_request *iwpm_retry_req = NULL; | |
| iwpm_mapped_port *iwpm_port; | |
| struct sockaddr_storage local_addr, remote_mapped_addr; | |
| int not_mapped = 1; | |
| const char *str_err; | |
| int ret; | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &local_addr, | |
| &msg_parms->cpipaddr[0], NULL, &msg_parms->cpport); | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &remote_mapped_addr, | |
| &msg_parms->apipaddr[0], NULL, &msg_parms->apport); | |
| ret = -EINVAL; | |
| iwpm_port = find_iwpm_same_mapping(&local_addr, not_mapped); | |
| if (!iwpm_port) { | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_wire_accept: " | |
| "Received accept for unknown mapping.\n"); | |
| return 0; | |
| } | |
| /* there should be a request for the accept message */ | |
| ret = update_iwpm_map_request(msg_parms->assochandle, &iwpm_port->local_addr, | |
| (IWARP_PM_REQ_QUERY|IWARP_PM_REQ_ACK), &iwpm_map_req, 1); | |
| if (ret) { | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_wire_accept: " | |
| "No matching mapping request (assochandle = %llu)\n", | |
| msg_parms->assochandle); | |
| return 0; /* ok when retransmission */ | |
| } | |
| if (iwpm_map_req.complete) | |
| return 0; | |
| /* if the accept has already been processed and this is retransmission */ | |
| if (iwpm_map_req.msg_type == IWARP_PM_REQ_ACK) { | |
| iwpm_debug(IWARP_PM_RETRY_DBG, "process_wire_accept: Detected retransmission " | |
| "(map request assochandle = %llu)\n", iwpm_map_req.assochandle); | |
| goto wire_accept_send_ack; | |
| } | |
| ret = send_conn_info_nlmsg(&iwpm_port->local_addr, &iwpm_map_req.remote_addr, | |
| &iwpm_port->mapped_addr, &remote_mapped_addr, | |
| iwpm_port->owner_client, iwpm_map_req.nlmsg_type, | |
| iwpm_map_req.nlmsg_seq, iwpm_map_req.nlmsg_pid, 0, nl_sock); | |
| if (ret) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto wire_accept_error; | |
| } | |
| /* object to detect retransmission */ | |
| iwpm_retry_req = create_iwpm_map_request(NULL, &iwpm_map_req.src_addr, &iwpm_map_req.remote_addr, | |
| iwpm_map_req.assochandle, IWARP_PM_REQ_ACK, NULL); | |
| if (!iwpm_retry_req) { | |
| ret = -ENOMEM; | |
| str_err = "Unable to allocate retry request"; | |
| goto wire_accept_error; | |
| } | |
| add_iwpm_map_request(iwpm_retry_req); | |
| wire_accept_send_ack: | |
| return send_iwpm_msg(form_iwpm_ack, msg_parms, recv_addr, pm_sock); | |
| wire_accept_error: | |
| syslog(LOG_WARNING, "process_iwpm_wire_accept: %s.\n", str_err); | |
| return ret; | |
| } | |
| /** | |
| * process_iwpm_wire_reject - Process reject message from the port mapper remote peer | |
| * @msg_parms: the received iwpm reject message | |
| * @nl_sock: netlink socket to send through a message to the iwpm client | |
| * | |
| * Send notification to the iwpm client that its | |
| * mapping request is rejected by the remote/accepting port mapper peer | |
| */ | |
| static int process_iwpm_wire_reject(iwpm_msg_parms *msg_parms, int nl_sock) | |
| { | |
| iwpm_mapping_request iwpm_map_req; | |
| iwpm_mapped_port *iwpm_port; | |
| struct sockaddr_storage local_addr, remote_addr; | |
| int not_mapped = 1; | |
| __u16 err_code = IWPM_REMOTE_QUERY_REJECT; | |
| const char *str_err; | |
| int ret = -EINVAL; | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &local_addr, | |
| &msg_parms->cpipaddr[0], NULL, &msg_parms->cpport); | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &remote_addr, | |
| &msg_parms->apipaddr[0], NULL, &msg_parms->apport); | |
| print_iwpm_sockaddr(&local_addr, "process_wire_reject: Local address", | |
| IWARP_PM_ALL_DBG); | |
| print_iwpm_sockaddr(&remote_addr, "process_wire_reject: Remote address", | |
| IWARP_PM_ALL_DBG); | |
| ret = -EINVAL; | |
| iwpm_port = find_iwpm_same_mapping(&local_addr, not_mapped); | |
| if (!iwpm_port) { | |
| syslog(LOG_WARNING, "process_wire_reject: Received reject for unknown mapping.\n"); | |
| return 0; | |
| } | |
| /* make sure there is request posted */ | |
| ret = update_iwpm_map_request(msg_parms->assochandle, &iwpm_port->local_addr, | |
| IWARP_PM_REQ_QUERY, &iwpm_map_req, 1); | |
| if (ret) { | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_wire_reject: " | |
| "No matching mapping request (assochandle = %llu)\n", | |
| msg_parms->assochandle); | |
| return 0; /* ok when retransmission */ | |
| } | |
| if (iwpm_map_req.complete) | |
| return 0; | |
| ret = send_conn_info_nlmsg(&iwpm_port->local_addr, &iwpm_map_req.remote_addr, | |
| &iwpm_port->mapped_addr, &iwpm_map_req.remote_addr, | |
| iwpm_port->owner_client, iwpm_map_req.nlmsg_type, | |
| iwpm_map_req.nlmsg_seq, iwpm_map_req.nlmsg_pid, err_code, nl_sock); | |
| if (ret) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto wire_reject_error; | |
| } | |
| return 0; | |
| wire_reject_error: | |
| syslog(LOG_WARNING, "process_wire_reject: %s.\n", str_err); | |
| return ret; | |
| } | |
| /** | |
| * process_iwpm_wire_ack - Process acknowledgement from the remote port mapper peer | |
| * @msg_parms: received iwpm acknowledgement | |
| */ | |
| static int process_iwpm_wire_ack(iwpm_msg_parms *msg_parms) | |
| { | |
| iwpm_mapped_port *iwpm_port; | |
| iwpm_mapping_request iwpm_map_req; | |
| struct sockaddr_storage local_mapped_addr; | |
| int not_mapped = 0; | |
| int ret; | |
| copy_iwpm_sockaddr(msg_parms->address_family, NULL, &local_mapped_addr, | |
| &msg_parms->apipaddr[0], NULL, &msg_parms->apport); | |
| iwpm_port = find_iwpm_mapping(&local_mapped_addr, not_mapped); | |
| if (!iwpm_port) { | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_wire_ack: Received ack for unknown mapping.\n"); | |
| return 0; | |
| } | |
| /* make sure there is accept for the ack */ | |
| ret = update_iwpm_map_request(msg_parms->assochandle, &local_mapped_addr, | |
| IWARP_PM_REQ_ACCEPT, &iwpm_map_req, 1); | |
| if (ret) | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_wire_ack: No matching mapping request\n"); | |
| return 0; | |
| } | |
| /* Mapping info message - nlmsg attributes */ | |
| static struct nla_policy mapinfo_policy[IWPM_NLA_MAPINFO_MAX] = { | |
| [IWPM_NLA_MAPINFO_LOCAL_ADDR] = { .minlen = sizeof(struct sockaddr_storage) }, | |
| [IWPM_NLA_MAPINFO_MAPPED_ADDR] = { .minlen = sizeof(struct sockaddr_storage) }, | |
| [IWPM_NLA_MAPINFO_FLAGS] = { .type = NLA_U32 } | |
| }; | |
| /** | |
| * process_iwpm_mapinfo - Process a mapping info message from the port mapper client | |
| * @req_nlh: netlink header of the received client message | |
| * @client_idx: the index of the client (the index is unique for each iwpm client) | |
| * @nl_sock: netlink socket to send a message to the client | |
| * | |
| * In case the userspace iwarp port mapper daemon is restarted, | |
| * the iwpm client needs to send a record of mappings it is currently using. | |
| * The port mapper needs to reopen the mapped ports used by the client. | |
| */ | |
| static int process_iwpm_mapinfo(struct nlmsghdr *req_nlh, int client_idx, int nl_sock) | |
| { | |
| iwpm_mapped_port *iwpm_port = NULL; | |
| struct sockaddr_storage *local_addr, *local_mapped_addr; | |
| struct nlattr *nltb [IWPM_NLA_MAPINFO_MAX] = {}; | |
| int not_mapped = 1; | |
| __u16 err_code = 0; | |
| const char *msg_type = "Mapping Info Msg"; | |
| const char *str_err = ""; | |
| int ret = -EINVAL; | |
| __u32 flags; | |
| int max = IWPM_NLA_MAPINFO_MAX; | |
| if (iwpm_version != IWPM_UABI_VERSION) | |
| max--; | |
| if (parse_iwpm_nlmsg(req_nlh, max, mapinfo_policy, nltb, msg_type)) { | |
| err_code = IWPM_INVALID_NLMSG_ERR; | |
| str_err = "Received Invalid nlmsg"; | |
| goto process_mapinfo_error; | |
| } | |
| local_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_MAPINFO_LOCAL_ADDR]); | |
| local_mapped_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_MAPINFO_MAPPED_ADDR]); | |
| flags = nltb[IWPM_NLA_MAPINFO_FLAGS] ? nla_get_u32(nltb[IWPM_NLA_MAPINFO_FLAGS]) : 0; | |
| iwpm_port = find_iwpm_mapping(local_addr, not_mapped); | |
| if (iwpm_port) { | |
| /* Can be safely ignored, if the mapinfo is exactly the same, | |
| * because the client will provide all the port information it has and | |
| * it could have started using the port mapper service already */ | |
| if (check_same_sockaddr(&iwpm_port->local_addr, local_addr) && | |
| check_same_sockaddr(&iwpm_port->mapped_addr, local_mapped_addr)) | |
| goto process_mapinfo_exit; | |
| /* partial duplicates matching wcard ip address aren't allowed as well */ | |
| err_code = IWPM_DUPLICATE_MAPPING_ERR; | |
| str_err = "Duplicate mapped port"; | |
| goto process_mapinfo_error; | |
| } | |
| iwpm_port = reopen_iwpm_mapped_port(local_addr, local_mapped_addr, client_idx, flags); | |
| if (!iwpm_port) { | |
| err_code = IWPM_CREATE_MAPPING_ERR; | |
| str_err = "Unable to create new mapping"; | |
| goto process_mapinfo_error; | |
| } | |
| /* add the new mapping to the list */ | |
| add_iwpm_mapped_port(iwpm_port); | |
| process_mapinfo_exit: | |
| mapinfo_num_list[client_idx]++; | |
| return 0; | |
| process_mapinfo_error: | |
| syslog(LOG_WARNING, "process_mapinfo: %s.\n", str_err); | |
| if (err_code) { | |
| /* send error message to the client */ | |
| send_iwpm_error_msg(req_nlh->nlmsg_seq, err_code, client_idx, nl_sock); | |
| } | |
| return ret; | |
| } | |
| /* Mapping info message count - nlmsg attributes */ | |
| static struct nla_policy mapinfo_count_policy[IWPM_NLA_MAPINFO_SEND_MAX] = { | |
| [IWPM_NLA_MAPINFO_SEQ] = { .type = NLA_U32 }, | |
| [IWPM_NLA_MAPINFO_SEND_NUM] = { .type = NLA_U32 } | |
| }; | |
| /** | |
| * process_iwpm_mapinfo_count - Process mapinfo count message | |
| * @req_nlh: netlink header of the received message from the client | |
| * @client_idx: the index of the client | |
| * @nl_sock: netlink socket to send a message to the client | |
| * | |
| * Mapinfo count message is a mechanism for the port mapper and the client to | |
| * synchronize on the number of mapinfo messages which were sucessfully exchanged and processed | |
| */ | |
| static int process_iwpm_mapinfo_count(struct nlmsghdr *req_nlh, int client_idx, int nl_sock) | |
| { | |
| struct nlattr *nltb [IWPM_NLA_MAPINFO_SEND_MAX]; | |
| struct nl_msg *resp_nlmsg = NULL; | |
| const char *msg_type = "Number of Mappings Msg"; | |
| __u32 map_count; | |
| __u16 err_code = 0; | |
| const char *str_err = ""; | |
| int ret = -EINVAL; | |
| if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_MAPINFO_SEND_MAX, | |
| mapinfo_count_policy, nltb, msg_type)) { | |
| str_err = "Received Invalid nlmsg"; | |
| err_code = IWPM_INVALID_NLMSG_ERR; | |
| goto mapinfo_count_error; | |
| } | |
| map_count = nla_get_u32(nltb[IWPM_NLA_MAPINFO_SEND_NUM]); | |
| if (map_count != mapinfo_num_list[client_idx]) | |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "get_mapinfo_count: Client (idx = %d) " | |
| "send mapinfo count = %u processed mapinfo count = %u.\n", | |
| client_idx, map_count, mapinfo_num_list[client_idx]); | |
| resp_nlmsg = create_iwpm_nlmsg(req_nlh->nlmsg_type, client_idx); | |
| if (!resp_nlmsg) { | |
| str_err = "Unable to create nlmsg response"; | |
| ret = -ENOMEM; | |
| goto mapinfo_count_error; | |
| } | |
| str_err = "Invalid nlmsg attribute"; | |
| if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_MAPINFO_SEQ, req_nlh->nlmsg_seq))) | |
| goto mapinfo_count_free_error; | |
| if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_MAPINFO_SEND_NUM, map_count))) | |
| goto mapinfo_count_free_error; | |
| if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_MAPINFO_ACK_NUM, | |
| mapinfo_num_list[client_idx]))) | |
| goto mapinfo_count_free_error; | |
| if ((ret = send_iwpm_nlmsg(nl_sock, resp_nlmsg, req_nlh->nlmsg_pid))) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto mapinfo_count_free_error; | |
| } | |
| nlmsg_free(resp_nlmsg); | |
| return 0; | |
| mapinfo_count_free_error: | |
| if (resp_nlmsg) | |
| nlmsg_free(resp_nlmsg); | |
| mapinfo_count_error: | |
| syslog(LOG_WARNING, "process_mapinfo_count: %s.\n", str_err); | |
| if (err_code) { | |
| /* send error message to the client */ | |
| send_iwpm_error_msg(req_nlh->nlmsg_seq, err_code, client_idx, nl_sock); | |
| } | |
| return ret; | |
| } | |
| /** | |
| * send_iwpm_error_msg - Send error message to the iwpm client | |
| * @seq: last received netlink message sequence | |
| * @err_code: used to differentiante between errors | |
| * @client_idx: the index of the client | |
| * @nl_sock: netlink socket to send a message to the client | |
| */ | |
| static int send_iwpm_error_msg(__u32 seq, __u16 err_code, int client_idx, int nl_sock) | |
| { | |
| struct nl_msg *resp_nlmsg; | |
| __u16 nlmsg_type; | |
| const char *str_err = ""; | |
| int ret; | |
| nlmsg_type = RDMA_NL_GET_TYPE(client_idx, RDMA_NL_IWPM_HANDLE_ERR); | |
| resp_nlmsg = create_iwpm_nlmsg(nlmsg_type, client_idx); | |
| if (!resp_nlmsg) { | |
| ret = -ENOMEM; | |
| str_err = "Unable to create nlmsg response"; | |
| goto send_error_msg_exit; | |
| } | |
| str_err = "Invalid nlmsg attribute"; | |
| if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_ERR_SEQ, seq))) | |
| goto send_error_msg_exit; | |
| if ((ret = nla_put_u16(resp_nlmsg, IWPM_NLA_ERR_CODE, err_code))) | |
| goto send_error_msg_exit; | |
| if ((ret = send_iwpm_nlmsg(nl_sock, resp_nlmsg, 0))) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto send_error_msg_exit; | |
| } | |
| nlmsg_free(resp_nlmsg); | |
| return 0; | |
| send_error_msg_exit: | |
| if (resp_nlmsg) | |
| nlmsg_free(resp_nlmsg); | |
| syslog(LOG_WARNING, "send_iwpm_error_msg: %s (ret = %d).\n", str_err, ret); | |
| return ret; | |
| } | |
| /* Hello message - nlmsg attributes */ | |
| static struct nla_policy hello_policy[IWPM_NLA_HELLO_MAX] = { | |
| [IWPM_NLA_HELLO_ABI_VERSION] = { .type = NLA_U16 } | |
| }; | |
| /** | |
| * process_iwpm_hello - Process mapinfo count message | |
| * @req_nlh: netlink header of the received message from the client | |
| * @client_idx: the index of the client | |
| * @nl_sock: netlink socket to send a message to the client | |
| * | |
| * Mapinfo count message is a mechanism for the port mapper and the client to | |
| * synchronize on the number of mapinfo messages which were sucessfully exchanged and processed | |
| */ | |
| static int process_iwpm_hello(struct nlmsghdr *req_nlh, int client_idx, int nl_sock) | |
| { | |
| struct nlattr *nltb [IWPM_NLA_HELLO_MAX]; | |
| const char *msg_type = "Hello Msg"; | |
| __u16 abi_version; | |
| __u16 err_code = 0; | |
| const char *str_err = ""; | |
| int ret = -EINVAL; | |
| if (req_nlh->nlmsg_type == NLMSG_ERROR) { | |
| abi_version = IWPM_UABI_VERSION_MIN; | |
| } else { | |
| if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_HELLO_MAX, | |
| hello_policy, nltb, msg_type)) { | |
| str_err = "Received Invalid nlmsg"; | |
| err_code = IWPM_INVALID_NLMSG_ERR; | |
| goto hello_error; | |
| } | |
| abi_version = nla_get_u16(nltb[IWPM_NLA_HELLO_ABI_VERSION]); | |
| } | |
| if (abi_version > IWPM_UABI_VERSION) { | |
| str_err = "UABI Version mismatch"; | |
| err_code = IWPM_VERSION_MISMATCH_ERR; | |
| goto hello_error; | |
| } | |
| iwpm_version = abi_version; | |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "process_iwpm_hello: using abi_version %u\n", iwpm_version); | |
| send_iwpm_mapinfo_request(nl_sock, RDMA_NL_IWCM); | |
| if (iwpm_version == 3) { | |
| /* Legacy RDMA_NL_C4IW for old kernels */ | |
| send_iwpm_mapinfo_request(nl_sock, RDMA_NL_IWCM+1); | |
| } | |
| return 0; | |
| hello_error: | |
| syslog(LOG_WARNING, "process_iwpm_hello: %s.\n", str_err); | |
| if (err_code) { | |
| /* send error message to the client */ | |
| send_iwpm_error_msg(req_nlh->nlmsg_seq, err_code, client_idx, nl_sock); | |
| } | |
| return ret; | |
| } | |
| /** | |
| * process_iwpm_netlink_msg - Dispatch received netlink messages | |
| * @nl_sock: netlink socket to read the messages from | |
| */ | |
| static int process_iwpm_netlink_msg(int nl_sock) | |
| { | |
| char *recv_buffer = NULL; | |
| struct nlmsghdr *nlh; | |
| struct sockaddr_nl src_addr; | |
| int len, type, client_idx, op; | |
| socklen_t src_addr_len; | |
| const char *str_err = ""; | |
| int ret = 0; | |
| recv_buffer = malloc(NLMSG_SPACE(IWARP_PM_RECV_PAYLOAD)); | |
| if (!recv_buffer) { | |
| ret = -ENOMEM; | |
| str_err = "Unable to allocate receive socket buffer"; | |
| goto process_netlink_msg_exit; | |
| } | |
| /* receive a new message */ | |
| nlh = (struct nlmsghdr *)recv_buffer; | |
| memset(nlh, 0, NLMSG_SPACE(IWARP_PM_RECV_PAYLOAD)); | |
| memset(&src_addr, 0, sizeof(src_addr)); | |
| src_addr_len = sizeof(src_addr); | |
| len = recvfrom(nl_sock, (void *)nlh, NLMSG_SPACE(IWARP_PM_RECV_PAYLOAD), 0, | |
| (struct sockaddr *)&src_addr, &src_addr_len); | |
| if (len <= 0) { | |
| ret = -errno; | |
| str_err = "Unable to receive data from netlink socket"; | |
| goto process_netlink_msg_exit; | |
| } | |
| /* loop for multiple netlink messages packed together */ | |
| while (NLMSG_OK(nlh, len) != 0) { | |
| if (nlh->nlmsg_type == NLMSG_DONE) { | |
| goto process_netlink_msg_exit; | |
| } | |
| type = nlh->nlmsg_type; | |
| client_idx = RDMA_NL_GET_CLIENT(type); | |
| if (type == NLMSG_ERROR) { | |
| /* RDMA_NL_IWCM HELLO error indicates V3 kernel */ | |
| if (nlh->nlmsg_seq == 0) { | |
| ret = process_iwpm_hello(nlh, client_idx, nl_sock); | |
| } else { | |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "process_netlink_msg: " | |
| "Netlink error message seq = %u\n", nlh->nlmsg_seq); | |
| } | |
| goto process_netlink_msg_exit; | |
| } | |
| op = RDMA_NL_GET_OP(type); | |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "process_netlink_msg: Received a new message: " | |
| "opcode = %u client idx = %u, client pid = %u," | |
| " msg seq = %u, type = %u, length = %u.\n", | |
| op, client_idx, nlh->nlmsg_pid, nlh->nlmsg_seq, type, len); | |
| if (client_idx >= IWARP_PM_MAX_CLIENTS) { | |
| ret = -EINVAL; | |
| str_err = "Invalid client index"; | |
| goto process_netlink_msg_exit; | |
| } | |
| switch (op) { | |
| case RDMA_NL_IWPM_REG_PID: | |
| str_err = "Register Pid request"; | |
| ret = process_iwpm_register_pid(nlh, client_idx, nl_sock); | |
| break; | |
| case RDMA_NL_IWPM_ADD_MAPPING: | |
| str_err = "Add Mapping request"; | |
| if (!client_list[client_idx].valid) { | |
| ret = -EINVAL; | |
| goto process_netlink_msg_exit; | |
| } | |
| ret = process_iwpm_add_mapping(nlh, client_idx, nl_sock); | |
| break; | |
| case RDMA_NL_IWPM_QUERY_MAPPING: | |
| str_err = "Query Mapping request"; | |
| if (!client_list[client_idx].valid) { | |
| ret = -EINVAL; | |
| goto process_netlink_msg_exit; | |
| } | |
| ret = process_iwpm_query_mapping(nlh, client_idx, nl_sock); | |
| break; | |
| case RDMA_NL_IWPM_REMOVE_MAPPING: | |
| str_err = "Remove Mapping request"; | |
| ret = process_iwpm_remove_mapping(nlh, client_idx, nl_sock); | |
| break; | |
| case RDMA_NL_IWPM_MAPINFO: | |
| ret = process_iwpm_mapinfo(nlh, client_idx, nl_sock); | |
| break; | |
| case RDMA_NL_IWPM_MAPINFO_NUM: | |
| ret = process_iwpm_mapinfo_count(nlh, client_idx, nl_sock); | |
| break; | |
| case RDMA_NL_IWPM_HELLO: | |
| ret = process_iwpm_hello(nlh, client_idx, nl_sock); | |
| break; | |
| default: | |
| str_err = "Netlink message with invalid opcode"; | |
| ret = -1; | |
| break; | |
| } | |
| nlh = NLMSG_NEXT(nlh, len); | |
| if (ret) | |
| goto process_netlink_msg_exit; | |
| } | |
| process_netlink_msg_exit: | |
| if (recv_buffer) | |
| free(recv_buffer); | |
| if (ret) | |
| syslog(LOG_WARNING, "process_netlink_msg: %s error (ret = %d).\n", str_err, ret); | |
| return ret; | |
| } | |
| /** | |
| * process_iwpm_msg - Dispatch iwpm wire messages, sent by the remote peer | |
| * @pm_sock: socket handle to read the messages from | |
| */ | |
| static int process_iwpm_msg(int pm_sock) | |
| { | |
| iwpm_msg_parms msg_parms; | |
| struct sockaddr_storage recv_addr; | |
| iwpm_wire_msg recv_buffer; /* received message */ | |
| int bytes_recv, ret = 0; | |
| int max_bytes_send = IWARP_PM_MESSAGE_SIZE + IWPM_IPADDR_SIZE; | |
| socklen_t recv_addr_len = sizeof(recv_addr); | |
| bytes_recv = recvfrom(pm_sock, &recv_buffer, max_bytes_send, 0, | |
| (struct sockaddr *)&recv_addr, &recv_addr_len); | |
| if (bytes_recv != IWARP_PM_MESSAGE_SIZE && bytes_recv != max_bytes_send) { | |
| syslog(LOG_WARNING, | |
| "process_iwpm_msg: Unable to receive data from PM socket. %s.\n", | |
| strerror(errno)); | |
| ret = -errno; | |
| goto process_iwpm_msg_exit; | |
| } | |
| ret = parse_iwpm_msg(&recv_buffer, &msg_parms); | |
| if (ret) | |
| goto process_iwpm_msg_exit; | |
| switch (msg_parms.mt) { | |
| case IWARP_PM_MT_REQ: | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_iwpm_msg: Received Request message.\n"); | |
| ret = process_iwpm_wire_request(&msg_parms, netlink_sock, &recv_addr, pm_sock); | |
| break; | |
| case IWARP_PM_MT_ACK: | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_iwpm_msg: Received Acknowledgement.\n"); | |
| ret = process_iwpm_wire_ack(&msg_parms); | |
| break; | |
| case IWARP_PM_MT_ACC: | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_iwpm_msg: Received Accept message.\n"); | |
| ret = process_iwpm_wire_accept(&msg_parms, netlink_sock, &recv_addr, pm_sock); | |
| break; | |
| case IWARP_PM_MT_REJ: | |
| iwpm_debug(IWARP_PM_WIRE_DBG, "process_iwpm_msg: Received Reject message.\n"); | |
| ret = process_iwpm_wire_reject(&msg_parms, netlink_sock); | |
| break; | |
| default: | |
| syslog(LOG_WARNING, "process_iwpm_msg: Received Invalid message type = %u.\n", | |
| msg_parms.mt); | |
| } | |
| process_iwpm_msg_exit: | |
| return ret; | |
| } | |
| /** | |
| * send_iwpm_hello - Notify the client that the V4 iwarp port mapper is available | |
| * @nl_sock: netlink socket to send a message to the client | |
| * | |
| * Send a HELLO message including the ABI_VERSION supported by iwpmd. If the | |
| * response is an ERROR message, then we know the kernel driver is < V4, so we | |
| * drop back to the V3 protocol. If the kernel is >= V4, then it will reply | |
| * with its ABI Version. The response is handled in iwarp_port_mapper(). Once | |
| * the ABI version is negotiatied, iwpmd will send a mapinfo request to get any | |
| * current mappings, using the correct ABI version. This allows working with | |
| * V3 kernels. | |
| */ | |
| static int send_iwpm_hello(int nl_sock) | |
| { | |
| struct nl_msg *req_nlmsg; | |
| const char *str_err; | |
| __u16 nlmsg_type; | |
| int ret; | |
| nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_IWCM, RDMA_NL_IWPM_HELLO); | |
| req_nlmsg = create_iwpm_nlmsg(nlmsg_type, RDMA_NL_IWCM); | |
| if (!req_nlmsg) { | |
| ret = -ENOMEM; | |
| str_err = "Unable to create nlmsg request"; | |
| goto send_hello_error; | |
| } | |
| str_err = "Invalid nlmsg attribute"; | |
| if ((ret = nla_put_u16(req_nlmsg, IWPM_NLA_HELLO_ABI_VERSION, iwpm_version))) | |
| goto send_hello_error; | |
| if ((ret = send_iwpm_nlmsg(nl_sock, req_nlmsg, 0))) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto send_hello_error; | |
| } | |
| nlmsg_free(req_nlmsg); | |
| return 0; | |
| send_hello_error: | |
| if (req_nlmsg) | |
| nlmsg_free(req_nlmsg); | |
| syslog(LOG_WARNING, "send_hello_request: %s ret = %d.\n", str_err, ret); | |
| return ret; | |
| } | |
| /** | |
| * send_iwpm_mapinfo_request - Notify the client that the iwarp port mapper is available | |
| * @nl_sock: netlink socket to send a message to the client | |
| * @client - client to receive the message | |
| */ | |
| static int send_iwpm_mapinfo_request(int nl_sock, int client) | |
| { | |
| struct nl_msg *req_nlmsg; | |
| __u16 nlmsg_type; | |
| const char *str_err; | |
| int ret; | |
| nlmsg_type = RDMA_NL_GET_TYPE(client, RDMA_NL_IWPM_MAPINFO); | |
| req_nlmsg = create_iwpm_nlmsg(nlmsg_type, client); | |
| if (!req_nlmsg) { | |
| ret = -ENOMEM; | |
| str_err = "Unable to create nlmsg request"; | |
| goto send_mapinfo_error; | |
| } | |
| str_err = "Invalid nlmsg attribute"; | |
| if ((ret = nla_put_string(req_nlmsg, IWPM_NLA_MAPINFO_ULIB_NAME, iwpm_ulib_name))) | |
| goto send_mapinfo_error; | |
| if ((ret = nla_put_u16(req_nlmsg, IWPM_NLA_MAPINFO_ULIB_VER, iwpm_version))) | |
| goto send_mapinfo_error; | |
| if ((ret = send_iwpm_nlmsg(nl_sock, req_nlmsg, 0))) { | |
| str_err = "Unable to send nlmsg response"; | |
| goto send_mapinfo_error; | |
| } | |
| nlmsg_free(req_nlmsg); | |
| return 0; | |
| send_mapinfo_error: | |
| if (req_nlmsg) | |
| nlmsg_free(req_nlmsg); | |
| syslog(LOG_WARNING, "send_mapinfo_request: %s ret = %d.\n", str_err, ret); | |
| return ret; | |
| } | |
| /** iwpm_cleanup - Close socket handles and free mapped ports */ | |
| static void iwpm_cleanup(void) | |
| { | |
| free_iwpm_mapped_ports(); | |
| destroy_iwpm_socket(netlink_sock); | |
| destroy_iwpm_socket(pmv6_client_sock); | |
| destroy_iwpm_socket(pmv6_sock); | |
| destroy_iwpm_socket(pmv4_client_sock); | |
| destroy_iwpm_socket(pmv4_sock); | |
| /* close up logging */ | |
| closelog(); | |
| } | |
| /** | |
| * iwarp_port_mapper - Distribute work orders for processing different types of iwpm messages | |
| */ | |
| static int iwarp_port_mapper(void) | |
| { | |
| fd_set select_fdset; /* read fdset */ | |
| struct timeval select_timeout; | |
| int select_rc, max_sock = 0, ret = 0; | |
| if (pmv4_sock > max_sock) | |
| max_sock = pmv4_sock; | |
| if (pmv6_sock > max_sock) | |
| max_sock = pmv6_sock; | |
| if (netlink_sock > max_sock) | |
| max_sock = netlink_sock; | |
| if (pmv4_client_sock > max_sock) | |
| max_sock = pmv4_client_sock; | |
| if (pmv6_client_sock > max_sock) | |
| max_sock = pmv6_client_sock; | |
| /* poll a set of sockets */ | |
| do { | |
| do { | |
| if (print_mappings) { | |
| print_iwpm_mapped_ports(); | |
| print_mappings = 0; | |
| } | |
| /* initialize the file sets for select */ | |
| FD_ZERO(&select_fdset); | |
| /* add the UDP and Netlink sockets to the file set */ | |
| if (pmv4_sock >= 0) { | |
| FD_SET(pmv4_sock, &select_fdset); | |
| FD_SET(pmv4_client_sock, &select_fdset); | |
| } | |
| if (pmv6_sock >= 0) { | |
| FD_SET(pmv6_sock, &select_fdset); | |
| FD_SET(pmv6_client_sock, &select_fdset); | |
| } | |
| FD_SET(netlink_sock, &select_fdset); | |
| /* set the timeout for select */ | |
| select_timeout.tv_sec = 10; | |
| select_timeout.tv_usec = 0; | |
| /* timeout is an upper bound of time elapsed before select returns */ | |
| select_rc = select(max_sock + 1, &select_fdset, NULL, NULL, &select_timeout); | |
| } while (select_rc == 0); | |
| /* select_rc is the number of fds ready for IO ( IO won't block) */ | |
| if (select_rc == -1) { | |
| if (errno == EINTR) | |
| continue; | |
| syslog(LOG_WARNING, "iwarp_port_mapper: Select failed (%s).\n", strerror(errno)); | |
| ret = -errno; | |
| goto iwarp_port_mapper_exit; | |
| } | |
| if (pmv4_sock >= 0) { | |
| if (FD_ISSET(pmv4_sock, &select_fdset)) | |
| ret = process_iwpm_msg(pmv4_sock); | |
| if (FD_ISSET(pmv4_client_sock, &select_fdset)) | |
| ret = process_iwpm_msg(pmv4_client_sock); | |
| } | |
| if (pmv6_sock >= 0) { | |
| if (FD_ISSET(pmv6_sock, &select_fdset)) | |
| ret = process_iwpm_msg(pmv6_sock); | |
| if (FD_ISSET(pmv6_client_sock, &select_fdset)) | |
| ret = process_iwpm_msg(pmv6_client_sock); | |
| } | |
| if (FD_ISSET(netlink_sock, &select_fdset)) | |
| ret = process_iwpm_netlink_msg(netlink_sock); | |
| } while (1); | |
| iwarp_port_mapper_exit: | |
| return ret; | |
| } | |
| /** | |
| * daemonize_iwpm_server - Make iwarp port mapper a daemon process | |
| */ | |
| static void daemonize_iwpm_server(void) | |
| { | |
| if (daemon(0, 0) != 0) { | |
| syslog(LOG_ERR, "Failed to daemonize\n"); | |
| exit(EXIT_FAILURE); | |
| } | |
| syslog(LOG_WARNING, "daemonize_iwpm_server: Starting iWarp Port Mapper V%d process\n", | |
| iwpm_version); | |
| } | |
| int main(int argc, char *argv[]) | |
| { | |
| FILE *fp; | |
| int c; | |
| int ret = EXIT_FAILURE; | |
| bool systemd = false; | |
| while (1) { | |
| static const struct option long_opts[] = { | |
| {"systemd", 0, NULL, 's'}, | |
| {} | |
| }; | |
| c = getopt_long(argc, argv, "fs", long_opts, NULL); | |
| if (c == -1) | |
| break; | |
| switch (c) { | |
| case 's': | |
| systemd = true; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| openlog(NULL, LOG_NDELAY | LOG_CONS | LOG_PID, LOG_DAEMON); | |
| if (!systemd) | |
| daemonize_iwpm_server(); | |
| umask(0); /* change file mode mask */ | |
| fp = fopen(IWPM_CONFIG_FILE, "r"); | |
| if (fp) { | |
| parse_iwpm_config(fp); | |
| fclose(fp); | |
| } | |
| memset(client_list, 0, sizeof(client_list)); | |
| pmv4_client_sock = -1; | |
| pmv6_sock = -1; | |
| pmv6_client_sock = pmv6_sock; | |
| pmv4_sock = create_iwpm_socket_v4(IWARP_PM_PORT); | |
| if (pmv4_sock < 0 && pmv4_sock != -EAFNOSUPPORT) | |
| goto error_exit_sock; | |
| pmv6_sock = create_iwpm_socket_v6(IWARP_PM_PORT); | |
| if (pmv6_sock < 0 && pmv6_sock != -EAFNOSUPPORT) | |
| goto error_exit_sock; | |
| /* If neither IPv4 nor IPv6 is supported, exit */ | |
| if (pmv4_sock < 0 && pmv6_sock < 0) | |
| goto error_exit_sock; | |
| if (pmv4_sock >= 0) { | |
| pmv4_client_sock = create_iwpm_socket_v4(0); | |
| if (pmv4_client_sock < 0) | |
| goto error_exit_sock; | |
| } | |
| if (pmv6_sock >= 0) { | |
| pmv6_client_sock = create_iwpm_socket_v6(0); | |
| if (pmv6_client_sock < 0) | |
| goto error_exit_sock; | |
| } | |
| netlink_sock = create_netlink_socket(); | |
| if (netlink_sock < 0) | |
| goto error_exit_sock; | |
| signal(SIGHUP, iwpm_signal_handler); | |
| signal(SIGTERM, iwpm_signal_handler); | |
| signal(SIGUSR1, iwpm_signal_handler); | |
| pthread_cond_init(&cond_req_complete, NULL); | |
| pthread_cond_init(&cond_pending_msg, NULL); | |
| ret = pthread_create(&map_req_thread, NULL, iwpm_mapping_reqs_handler, NULL); | |
| if (ret) | |
| goto error_exit; | |
| ret = pthread_create(&pending_msg_thread, NULL, iwpm_pending_msgs_handler, NULL); | |
| if (ret) | |
| goto error_exit; | |
| ret = send_iwpm_hello(netlink_sock); | |
| if (ret) | |
| goto error_exit; | |
| if (systemd) | |
| sd_notify(0, "READY=1"); | |
| iwarp_port_mapper(); /* start iwarp port mapper process */ | |
| free_iwpm_mapped_ports(); | |
| closelog(); | |
| error_exit: | |
| destroy_iwpm_socket(netlink_sock); | |
| error_exit_sock: | |
| destroy_iwpm_socket(pmv4_client_sock); | |
| destroy_iwpm_socket(pmv6_client_sock); | |
| destroy_iwpm_socket(pmv4_sock); | |
| destroy_iwpm_socket(pmv6_sock); | |
| syslog(LOG_WARNING, "main: Couldn't start iWarp Port Mapper.\n"); | |
| return ret; | |
| } |