| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "iwarp_pm.h" |
| #include <endian.h> |
| |
| |
| static const char * iwpm_param_names[IWPM_PARAM_NUM] = |
| { "nl_sock_rbuf_size" }; |
| static int iwpm_param_vals[IWPM_PARAM_NUM] = |
| { 0 }; |
| |
| |
| |
| |
| static int get_iwpm_param(char *param_name, int val) |
| { |
| int i, ret; |
| for (i = 0; i < IWPM_PARAM_NUM; i++) { |
| ret = strcmp(param_name, iwpm_param_names[i]); |
| if (!ret && val > 0) { |
| syslog(LOG_WARNING, "get_iwpm_param: Got param (name = %s val = %d)\n", param_name, val); |
| iwpm_param_vals[i] = val; |
| return ret; |
| } |
| } |
| return ret; |
| } |
| |
| |
| |
| |
| void parse_iwpm_config(FILE *fp) |
| { |
| char line_buf[128]; |
| char param_name[IWPM_PARAM_NAME_LEN]; |
| int n, val, ret; |
| char *str; |
| |
| str = fgets(line_buf, 128, fp); |
| while (str) { |
| if (line_buf[0] == '#' || line_buf[0] == '\n') |
| goto parse_next_line; |
| n = sscanf(line_buf, "%64[^= ] %*[=]%d", param_name, &val); |
| if (n != 2) { |
| syslog(LOG_WARNING, "parse_iwpm_config: Couldn't parse a line (n = %d, name = %s, val = %d\n", n, param_name, val); |
| goto parse_next_line; |
| } |
| ret = get_iwpm_param(param_name, val); |
| if (ret) |
| syslog(LOG_WARNING, "parse_iwpm_config: Couldn't find param (ret = %d)\n", ret); |
| parse_next_line: |
| str = fgets(line_buf, 128, fp); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| int create_iwpm_socket_v4(__u16 bind_port) |
| { |
| sockaddr_union bind_addr; |
| struct sockaddr_in *bind_in4; |
| int pm_sock; |
| socklen_t sockname_len; |
| char ip_address_text[INET6_ADDRSTRLEN]; |
| |
| |
| pm_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| if (pm_sock < 0) { |
| syslog(LOG_WARNING, "create_iwpm_socket_v4: Unable to create socket. %s.\n", |
| strerror(errno)); |
| pm_sock = -errno; |
| goto create_socket_v4_exit; |
| } |
| |
| memset(&bind_addr, 0, sizeof(bind_addr)); |
| bind_in4 = &bind_addr.v4_sockaddr; |
| bind_in4->sin_family = AF_INET; |
| bind_in4->sin_addr.s_addr = htobe32(INADDR_ANY); |
| bind_in4->sin_port = htobe16(bind_port); |
| |
| if (bind(pm_sock, &bind_addr.sock_addr, sizeof(struct sockaddr_in))) { |
| syslog(LOG_WARNING, "create_iwpm_socket_v4: Unable to bind socket (port = %u). %s.\n", |
| bind_port, strerror(errno)); |
| close(pm_sock); |
| pm_sock = -errno; |
| goto create_socket_v4_exit; |
| } |
| |
| |
| sockname_len = sizeof(struct sockaddr_in); |
| if (getsockname(pm_sock, &bind_addr.sock_addr, &sockname_len)) { |
| syslog(LOG_WARNING, "create_iwpm_socket_v4: Unable to get socket name. %s.\n", |
| strerror(errno)); |
| close(pm_sock); |
| pm_sock = -errno; |
| goto create_socket_v4_exit; |
| } |
| |
| iwpm_debug(IWARP_PM_WIRE_DBG, "create_iwpm_socket_v4: Socket IP address:port %s:%u\n", |
| inet_ntop(bind_in4->sin_family, &bind_in4->sin_addr.s_addr, ip_address_text, |
| INET6_ADDRSTRLEN), be16toh(bind_in4->sin_port)); |
| create_socket_v4_exit: |
| return pm_sock; |
| } |
| |
| |
| |
| |
| |
| |
| |
| int create_iwpm_socket_v6(__u16 bind_port) |
| { |
| sockaddr_union bind_addr; |
| struct sockaddr_in6 *bind_in6; |
| int pm_sock, ret_value, ipv6_only; |
| socklen_t sockname_len; |
| char ip_address_text[INET6_ADDRSTRLEN]; |
| |
| |
| pm_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
| if (pm_sock < 0) { |
| syslog(LOG_WARNING, "create_iwpm_socket_v6: Unable to create socket. %s.\n", |
| strerror(errno)); |
| pm_sock = -errno; |
| goto create_socket_v6_exit; |
| } |
| |
| ipv6_only = 1; |
| ret_value = setsockopt(pm_sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)); |
| if (ret_value < 0) { |
| syslog(LOG_WARNING, "create_iwpm_socket_v6: Unable to set sock options. %s.\n", |
| strerror(errno)); |
| close(pm_sock); |
| pm_sock = -errno; |
| goto create_socket_v6_exit; |
| } |
| |
| |
| memset(&bind_addr, 0, sizeof(bind_addr)); |
| bind_in6 = &bind_addr.v6_sockaddr; |
| bind_in6->sin6_family = AF_INET6; |
| bind_in6->sin6_addr = in6addr_any; |
| bind_in6->sin6_port = htobe16(bind_port); |
| |
| if (bind(pm_sock, &bind_addr.sock_addr, sizeof(struct sockaddr_in6))) { |
| syslog(LOG_WARNING, "create_iwpm_socket_v6: Unable to bind socket (port = %u). %s.\n", |
| bind_port, strerror(errno)); |
| close(pm_sock); |
| pm_sock = -errno; |
| goto create_socket_v6_exit; |
| } |
| |
| |
| sockname_len = sizeof(struct sockaddr_in6); |
| if (getsockname(pm_sock, &bind_addr.sock_addr, &sockname_len)) { |
| syslog(LOG_WARNING, "create_iwpm_socket_v6: Unable to get socket name. %s.\n", |
| strerror(errno)); |
| close(pm_sock); |
| pm_sock = -errno; |
| goto create_socket_v6_exit; |
| } |
| |
| iwpm_debug(IWARP_PM_WIRE_DBG, "create_iwpm_socket_v6: Socket IP address:port %s:%04X\n", |
| inet_ntop(bind_in6->sin6_family, &bind_in6->sin6_addr, ip_address_text, |
| INET6_ADDRSTRLEN), be16toh(bind_in6->sin6_port)); |
| create_socket_v6_exit: |
| return pm_sock; |
| } |
| |
| |
| |
| |
| int create_netlink_socket(void) |
| { |
| sockaddr_union bind_addr; |
| struct sockaddr_nl *bind_nl; |
| int nl_sock; |
| __u32 rbuf_size, opt_len; |
| |
| |
| nl_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_RDMA); |
| if (nl_sock < 0) { |
| syslog(LOG_WARNING, "create_netlink_socket: Unable to create socket. %s.\n", |
| strerror(errno)); |
| nl_sock = -errno; |
| goto create_nl_socket_exit; |
| } |
| |
| |
| memset(&bind_addr, 0, sizeof(bind_addr)); |
| bind_nl = &bind_addr.nl_sockaddr; |
| bind_nl->nl_family = AF_NETLINK; |
| bind_nl->nl_pid = getpid(); |
| bind_nl->nl_groups = 3; |
| |
| if (bind(nl_sock, &bind_addr.sock_addr, sizeof(struct sockaddr_nl))) { |
| syslog(LOG_WARNING, "create_netlink_socket: Unable to bind socket. %s.\n", |
| strerror(errno)); |
| close(nl_sock); |
| nl_sock = -errno; |
| goto create_nl_socket_exit; |
| } |
| if (iwpm_param_vals[NL_SOCK_RBUF_SIZE] > 0) { |
| rbuf_size = iwpm_param_vals[NL_SOCK_RBUF_SIZE]; |
| |
| if (setsockopt(nl_sock, SOL_SOCKET, SO_RCVBUFFORCE, &rbuf_size, sizeof rbuf_size)) { |
| syslog(LOG_WARNING, "create_netlink_socket: Unable to set sock option " |
| "(rbuf_size = %u). %s.\n", rbuf_size, strerror(errno)); |
| if (setsockopt(nl_sock, SOL_SOCKET, SO_RCVBUF, |
| &rbuf_size, sizeof rbuf_size)) { |
| syslog(LOG_WARNING, "create_netlink_socket: " |
| "Unable to set sock option %s. Closing socket\n", strerror(errno)); |
| close(nl_sock); |
| nl_sock = -errno; |
| goto create_nl_socket_exit; |
| } |
| } |
| } |
| getsockopt(nl_sock, SOL_SOCKET, SO_RCVBUF, &rbuf_size, &opt_len); |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "create_netlink_socket: Setting a sock option (rbuf_size = %u).\n", rbuf_size); |
| |
| create_nl_socket_exit: |
| return nl_sock; |
| } |
| |
| |
| |
| |
| void destroy_iwpm_socket(int pm_sock) |
| { |
| if (pm_sock > 0) |
| close(pm_sock); |
| pm_sock = -1; |
| } |
| |
| |
| |
| |
| static int check_iwpm_nlattr(struct nlattr *nltb[], int nla_count) |
| { |
| int i, ret = 0; |
| for (i = 1; i < nla_count; i++) { |
| if (!nltb[i]) { |
| iwpm_debug(IWARP_PM_NETLINK_DBG, "check_iwpm_nlattr: NULL (attr idx = %d)\n", i); |
| ret = -EINVAL; |
| } |
| } |
| return ret; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int parse_iwpm_nlmsg(struct nlmsghdr *req_nlh, int policy_max, |
| struct nla_policy *nlmsg_policy, struct nlattr *nltb [], |
| const char *msg_type) |
| { |
| const char *str_err; |
| int ret; |
| |
| if ((ret = nlmsg_validate(req_nlh, 0, policy_max-1, nlmsg_policy))) { |
| str_err = "nlmsg_validate error"; |
| goto parse_nlmsg_error; |
| } |
| if ((ret = nlmsg_parse(req_nlh, 0, nltb, policy_max-1, nlmsg_policy))) { |
| str_err = "nlmsg_parse error"; |
| goto parse_nlmsg_error; |
| } |
| if (check_iwpm_nlattr(nltb, policy_max)) { |
| ret = -EINVAL; |
| str_err = "NULL nlmsg attribute"; |
| goto parse_nlmsg_error; |
| } |
| return 0; |
| parse_nlmsg_error: |
| syslog(LOG_WARNING, "parse_iwpm_nlmsg: msg type = %s (%s ret = %d)\n", |
| msg_type, str_err, ret); |
| return ret; |
| } |
| |
| |
| |
| |
| |
| |
| |
| int send_iwpm_nlmsg(int nl_sock, struct nl_msg *nlmsg, int dest_pid) |
| { |
| struct sockaddr_nl dest_addr; |
| struct nlmsghdr *nlh = nlmsg_hdr(nlmsg); |
| __u32 nlmsg_len = nlh->nlmsg_len; |
| int len; |
| |
| |
| memset(&dest_addr, 0, sizeof(dest_addr)); |
| dest_addr.nl_groups = 0; |
| dest_addr.nl_family = AF_NETLINK; |
| dest_addr.nl_pid = dest_pid; |
| |
| |
| len = sendto(nl_sock, (char *)nlh, nlmsg_len, 0, |
| (struct sockaddr *)&dest_addr, sizeof(dest_addr)); |
| if (len != nlmsg_len) |
| return -errno; |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| struct nl_msg *create_iwpm_nlmsg(__u16 nlmsg_type, int client_idx) |
| { |
| struct nl_msg *nlmsg; |
| struct nlmsghdr *nlh; |
| __u32 seq = 0; |
| |
| nlmsg = nlmsg_alloc(); |
| if (!nlmsg) |
| return NULL; |
| if (client_idx > 0) |
| seq = client_list[client_idx].nl_seq++; |
| |
| nlh = nlmsg_put(nlmsg, getpid(), seq, nlmsg_type, 0, NLM_F_REQUEST); |
| if (!nlh) { |
| nlmsg_free(nlmsg); |
| return NULL; |
| } |
| return nlmsg; |
| } |
| |
| |
| |
| |
| |
| |
| int parse_iwpm_msg(iwpm_wire_msg *pm_msg, iwpm_msg_parms *msg_parms) |
| { |
| int ret_value = 0; |
| |
| msg_parms->pmtime = pm_msg->pmtime; |
| msg_parms->assochandle = be64toh(pm_msg->assochandle); |
| msg_parms->ip_ver = (pm_msg->magic & IWARP_PM_IPVER_MASK) >> IWARP_PM_IPVER_SHIFT; |
| switch (msg_parms->ip_ver) { |
| case 4: |
| msg_parms->address_family = AF_INET; |
| break; |
| case 6: |
| msg_parms->address_family = AF_INET6; |
| break; |
| default: |
| syslog(LOG_WARNING, "parse_iwpm_msg: Invalid IP version = %d.\n", |
| msg_parms->ip_ver); |
| return -EINVAL; |
| } |
| |
| msg_parms->ver = (pm_msg->magic & IWARP_PM_VER_MASK) >> IWARP_PM_VER_SHIFT; |
| |
| msg_parms->mt = (pm_msg->magic & IWARP_PM_MT_MASK) >> IWARP_PM_MT_SHIFT; |
| msg_parms->apport = pm_msg->apport; |
| msg_parms->cpport = pm_msg->cpport; |
| |
| memcpy(&msg_parms->apipaddr, &pm_msg->apipaddr, IWPM_IPADDR_SIZE); |
| |
| memcpy(&msg_parms->cpipaddr, &pm_msg->cpipaddr, IWPM_IPADDR_SIZE); |
| if (msg_parms->mt == IWARP_PM_MT_REQ) { |
| msg_parms->mapped_cpport = pm_msg->reserved; |
| memcpy(&msg_parms->mapped_cpipaddr, &pm_msg->mapped_cpipaddr, IWPM_IPADDR_SIZE); |
| } |
| return ret_value; |
| } |
| |
| |
| |
| |
| |
| |
| static void form_iwpm_msg(iwpm_wire_msg *pm_msg, iwpm_msg_parms *msg_parms) |
| { |
| memset(pm_msg, 0, sizeof(struct iwpm_wire_msg)); |
| pm_msg->pmtime = msg_parms->pmtime; |
| pm_msg->assochandle = htobe64(msg_parms->assochandle); |
| |
| pm_msg->magic = (msg_parms->ip_ver << IWARP_PM_IPVER_SHIFT) & IWARP_PM_IPVER_MASK; |
| pm_msg->magic |= (msg_parms->ver << IWARP_PM_VER_SHIFT) & IWARP_PM_VER_MASK; |
| pm_msg->magic |= (msg_parms->mt << IWARP_PM_MT_SHIFT) & IWARP_PM_MT_MASK; |
| |
| pm_msg->apport = msg_parms->apport; |
| pm_msg->cpport = msg_parms->cpport; |
| memcpy(&pm_msg->apipaddr, &msg_parms->apipaddr, IWPM_IPADDR_SIZE); |
| memcpy(&pm_msg->cpipaddr, &msg_parms->cpipaddr, IWPM_IPADDR_SIZE); |
| if (msg_parms->mt == IWARP_PM_MT_REQ) { |
| pm_msg->reserved = msg_parms->mapped_cpport; |
| memcpy(&pm_msg->mapped_cpipaddr, &msg_parms->mapped_cpipaddr, IWPM_IPADDR_SIZE); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| void form_iwpm_request(struct iwpm_wire_msg *pm_msg, |
| struct iwpm_msg_parms *msg_parms) |
| { |
| msg_parms->mt = IWARP_PM_MT_REQ; |
| msg_parms->msize = IWARP_PM_MESSAGE_SIZE + IWPM_IPADDR_SIZE; |
| form_iwpm_msg(pm_msg, msg_parms); |
| } |
| |
| |
| |
| |
| |
| |
| void form_iwpm_accept(struct iwpm_wire_msg *pm_msg, |
| struct iwpm_msg_parms *msg_parms) |
| { |
| msg_parms->mt = IWARP_PM_MT_ACC; |
| msg_parms->msize = IWARP_PM_MESSAGE_SIZE; |
| form_iwpm_msg(pm_msg, msg_parms); |
| } |
| |
| |
| |
| |
| |
| |
| void form_iwpm_ack(struct iwpm_wire_msg *pm_msg, |
| struct iwpm_msg_parms *msg_parms) |
| { |
| msg_parms->mt = IWARP_PM_MT_ACK; |
| msg_parms->msize = IWARP_PM_MESSAGE_SIZE; |
| form_iwpm_msg(pm_msg, msg_parms); |
| } |
| |
| |
| |
| |
| |
| |
| void form_iwpm_reject(struct iwpm_wire_msg *pm_msg, |
| struct iwpm_msg_parms *msg_parms) |
| { |
| msg_parms->mt = IWARP_PM_MT_REJ; |
| msg_parms->msize = IWARP_PM_MESSAGE_SIZE; |
| form_iwpm_msg(pm_msg, msg_parms); |
| } |
| |
| |
| |
| |
| |
| __be16 get_sockaddr_port(struct sockaddr_storage *sockaddr) |
| { |
| struct sockaddr_in *sockaddr_v4; |
| struct sockaddr_in6 *sockaddr_v6; |
| __be16 port = 0; |
| |
| switch (sockaddr->ss_family) { |
| case AF_INET: |
| sockaddr_v4 = (struct sockaddr_in *)sockaddr; |
| port = sockaddr_v4->sin_port; |
| break; |
| case AF_INET6: |
| sockaddr_v6 = (struct sockaddr_in6 *)sockaddr; |
| port = sockaddr_v6->sin6_port; |
| break; |
| default: |
| syslog(LOG_WARNING, "get_sockaddr_port: Invalid sockaddr family.\n"); |
| break; |
| } |
| return port; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void copy_iwpm_sockaddr(__u16 addr_family, struct sockaddr_storage *src_sockaddr, |
| struct sockaddr_storage *dst_sockaddr, |
| char *src_addr, char *dst_addr, __be16 *src_port) |
| { |
| switch (addr_family) { |
| case AF_INET: { |
| const struct in_addr *src = (void *)src_addr; |
| struct in_addr *dst = (void *)dst_addr; |
| const struct sockaddr_in *src_sockaddr_in; |
| struct sockaddr_in *dst_sockaddr_in; |
| |
| if (src_sockaddr) { |
| src_sockaddr_in = (const void *)src_sockaddr; |
| src = &src_sockaddr_in->sin_addr; |
| *src_port = src_sockaddr_in->sin_port; |
| } |
| if (dst_sockaddr) { |
| dst_sockaddr_in = (void *)dst_sockaddr; |
| dst = &dst_sockaddr_in->sin_addr; |
| dst_sockaddr_in->sin_port = *src_port; |
| dst_sockaddr_in->sin_family = AF_INET; |
| } |
| *dst = *src; |
| break; |
| } |
| case AF_INET6: { |
| const struct in6_addr *src = (void *)src_addr; |
| struct in6_addr *dst = (void *)dst_addr; |
| const struct sockaddr_in6 *src_sockaddr_in6; |
| struct sockaddr_in6 *dst_sockaddr_in6; |
| |
| if (src_sockaddr) { |
| src_sockaddr_in6 = (const void *)src_sockaddr; |
| src = &src_sockaddr_in6->sin6_addr; |
| *src_port = src_sockaddr_in6->sin6_port; |
| } |
| if (dst_sockaddr) { |
| dst_sockaddr_in6 = (void *)dst_sockaddr; |
| dst = &dst_sockaddr_in6->sin6_addr; |
| dst_sockaddr_in6->sin6_port = *src_port; |
| dst_sockaddr_in6->sin6_family = AF_INET6; |
| } |
| *dst = *src; |
| break; |
| } |
| } |
| } |
| |
| |
| |
| |
| int is_wcard_ipaddr(struct sockaddr_storage *search_addr) |
| { |
| int ret = 0; |
| |
| switch (search_addr->ss_family) { |
| case AF_INET: { |
| struct sockaddr_in wcard_addr; |
| struct sockaddr_in *in4addr = (struct sockaddr_in *)search_addr; |
| inet_pton(AF_INET, "0.0.0.0", &wcard_addr.sin_addr); |
| |
| if (in4addr->sin_addr.s_addr == wcard_addr.sin_addr.s_addr) |
| ret = 1; |
| break; |
| } |
| case AF_INET6: { |
| struct sockaddr_in6 wcard_addr; |
| struct sockaddr_in6 *in6addr = (struct sockaddr_in6 *)search_addr; |
| inet_pton(AF_INET6, "::", &wcard_addr.sin6_addr); |
| |
| if (!memcmp(in6addr->sin6_addr.s6_addr, |
| wcard_addr.sin6_addr.s6_addr, IWPM_IPADDR_SIZE)) |
| ret = 1; |
| break; |
| } |
| default: |
| syslog(LOG_WARNING, "check_same_sockaddr: Invalid addr family 0x%02X\n", |
| search_addr->ss_family); |
| break; |
| } |
| return ret; |
| } |
| |
| |
| |
| |
| |
| |
| void print_iwpm_sockaddr(struct sockaddr_storage *sockaddr, const char *msg, |
| __u32 dbg_flag) |
| { |
| struct sockaddr_in6 *sockaddr_v6; |
| struct sockaddr_in *sockaddr_v4; |
| char ip_address_text[INET6_ADDRSTRLEN]; |
| |
| switch (sockaddr->ss_family) { |
| case AF_INET: |
| sockaddr_v4 = (struct sockaddr_in *)sockaddr; |
| iwpm_debug(dbg_flag, "%s IPV4 %s:%u(0x%04X)\n", msg, |
| inet_ntop(AF_INET, &sockaddr_v4->sin_addr, ip_address_text, INET6_ADDRSTRLEN), |
| be16toh(sockaddr_v4->sin_port), be16toh(sockaddr_v4->sin_port)); |
| break; |
| case AF_INET6: |
| sockaddr_v6 = (struct sockaddr_in6 *)sockaddr; |
| iwpm_debug(dbg_flag, "%s IPV6 %s:%u(0x%04X)\n", msg, |
| inet_ntop(AF_INET6, &sockaddr_v6->sin6_addr, ip_address_text, INET6_ADDRSTRLEN), |
| be16toh(sockaddr_v6->sin6_port), be16toh(sockaddr_v6->sin6_port)); |
| break; |
| default: |
| break; |
| } |
| } |