Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 082eaa50 authored by Doug Ledford's avatar Doug Ledford
Browse files

Merge branches 'nes', 'cxgb4' and 'iwpm' into k.o/for-4.6

Loading
Loading
Loading
Loading
+164 −26
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@

#include <rdma/iw_cm.h>
#include <rdma/ib_addr.h>
#include <rdma/iw_portmap.h>
#include <rdma/rdma_netlink.h>

#include "iwcm.h"

@@ -57,6 +59,16 @@ MODULE_AUTHOR("Tom Tucker");
MODULE_DESCRIPTION("iWARP CM");
MODULE_LICENSE("Dual BSD/GPL");

static struct ibnl_client_cbs iwcm_nl_cb_table[] = {
	[RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
	[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
	[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
	[RDMA_NL_IWPM_REMOTE_INFO] = {.dump = iwpm_remote_info_cb},
	[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb},
	[RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb},
	[RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb}
};

static struct workqueue_struct *iwcm_wq;
struct iwcm_work {
	struct work_struct work;
@@ -402,6 +414,11 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
	}
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);

	if (cm_id->mapped) {
		iwpm_remove_mapinfo(&cm_id->local_addr, &cm_id->m_local_addr);
		iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM);
	}

	(void)iwcm_deref_id(cm_id_priv);
}

@@ -426,6 +443,97 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id)
}
EXPORT_SYMBOL(iw_destroy_cm_id);

/**
 * iw_cm_check_wildcard - If IP address is 0 then use original
 * @pm_addr: sockaddr containing the ip to check for wildcard
 * @cm_addr: sockaddr containing the actual IP address
 * @cm_outaddr: sockaddr to set IP addr which leaving port
 *
 *  Checks the pm_addr for wildcard and then sets cm_outaddr's
 *  IP to the actual (cm_addr).
 */
static void iw_cm_check_wildcard(struct sockaddr_storage *pm_addr,
				 struct sockaddr_storage *cm_addr,
				 struct sockaddr_storage *cm_outaddr)
{
	if (pm_addr->ss_family == AF_INET) {
		struct sockaddr_in *pm4_addr = (struct sockaddr_in *)pm_addr;

		if (pm4_addr->sin_addr.s_addr == INADDR_ANY) {
			struct sockaddr_in *cm4_addr =
				(struct sockaddr_in *)cm_addr;
			struct sockaddr_in *cm4_outaddr =
				(struct sockaddr_in *)cm_outaddr;

			cm4_outaddr->sin_addr = cm4_addr->sin_addr;
		}
	} else {
		struct sockaddr_in6 *pm6_addr = (struct sockaddr_in6 *)pm_addr;

		if (ipv6_addr_type(&pm6_addr->sin6_addr) == IPV6_ADDR_ANY) {
			struct sockaddr_in6 *cm6_addr =
				(struct sockaddr_in6 *)cm_addr;
			struct sockaddr_in6 *cm6_outaddr =
				(struct sockaddr_in6 *)cm_outaddr;

			cm6_outaddr->sin6_addr = cm6_addr->sin6_addr;
		}
	}
}

/**
 * iw_cm_map - Use portmapper to map the ports
 * @cm_id: connection manager pointer
 * @active: Indicates the active side when true
 * returns nonzero for error only if iwpm_create_mapinfo() fails
 *
 * Tries to add a mapping for a port using the Portmapper. If
 * successful in mapping the IP/Port it will check the remote
 * mapped IP address for a wildcard IP address and replace the
 * zero IP address with the remote_addr.
 */
static int iw_cm_map(struct iw_cm_id *cm_id, bool active)
{
	struct iwpm_dev_data pm_reg_msg;
	struct iwpm_sa_data pm_msg;
	int status;

	cm_id->m_local_addr = cm_id->local_addr;
	cm_id->m_remote_addr = cm_id->remote_addr;

	memcpy(pm_reg_msg.dev_name, cm_id->device->name,
	       sizeof(pm_reg_msg.dev_name));
	memcpy(pm_reg_msg.if_name, cm_id->device->iwcm->ifname,
	       sizeof(pm_reg_msg.if_name));

	if (iwpm_register_pid(&pm_reg_msg, RDMA_NL_IWCM) ||
	    !iwpm_valid_pid())
		return 0;

	cm_id->mapped = true;
	pm_msg.loc_addr = cm_id->local_addr;
	pm_msg.rem_addr = cm_id->remote_addr;
	if (active)
		status = iwpm_add_and_query_mapping(&pm_msg,
						    RDMA_NL_IWCM);
	else
		status = iwpm_add_mapping(&pm_msg, RDMA_NL_IWCM);

	if (!status) {
		cm_id->m_local_addr = pm_msg.mapped_loc_addr;
		if (active) {
			cm_id->m_remote_addr = pm_msg.mapped_rem_addr;
			iw_cm_check_wildcard(&pm_msg.mapped_rem_addr,
					     &cm_id->remote_addr,
					     &cm_id->m_remote_addr);
		}
	}

	return iwpm_create_mapinfo(&cm_id->local_addr,
				   &cm_id->m_local_addr,
				   RDMA_NL_IWCM);
}

/*
 * CM_ID <-- LISTEN
 *
@@ -452,6 +560,8 @@ int iw_cm_listen(struct iw_cm_id *cm_id, int backlog)
	case IW_CM_STATE_IDLE:
		cm_id_priv->state = IW_CM_STATE_LISTEN;
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
		ret = iw_cm_map(cm_id, false);
		if (!ret)
			ret = cm_id->device->iwcm->create_listen(cm_id, backlog);
		if (ret)
			cm_id_priv->state = IW_CM_STATE_IDLE;
@@ -582,39 +692,37 @@ int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
	spin_lock_irqsave(&cm_id_priv->lock, flags);

	if (cm_id_priv->state != IW_CM_STATE_IDLE) {
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
		clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
		wake_up_all(&cm_id_priv->connect_wait);
		return -EINVAL;
		ret = -EINVAL;
		goto err;
	}

	/* Get the ib_qp given the QPN */
	qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
	if (!qp) {
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
		clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
		wake_up_all(&cm_id_priv->connect_wait);
		return -EINVAL;
		ret = -EINVAL;
		goto err;
	}
	cm_id->device->iwcm->add_ref(qp);
	cm_id_priv->qp = qp;
	cm_id_priv->state = IW_CM_STATE_CONN_SENT;
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);

	ret = iw_cm_map(cm_id, true);
	if (!ret)
		ret = cm_id->device->iwcm->connect(cm_id, iw_param);
	if (ret) {
	if (!ret)
		return 0;	/* success */

	spin_lock_irqsave(&cm_id_priv->lock, flags);
	if (cm_id_priv->qp) {
		cm_id->device->iwcm->rem_ref(qp);
		cm_id_priv->qp = NULL;
	}
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
		BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
	cm_id_priv->state = IW_CM_STATE_IDLE;
err:
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
	clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
	wake_up_all(&cm_id_priv->connect_wait);
	}

	return ret;
}
EXPORT_SYMBOL(iw_cm_connect);
@@ -656,8 +764,23 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv,
		goto out;

	cm_id->provider_data = iw_event->provider_data;
	cm_id->local_addr = iw_event->local_addr;
	cm_id->m_local_addr = iw_event->local_addr;
	cm_id->m_remote_addr = iw_event->remote_addr;
	cm_id->local_addr = listen_id_priv->id.local_addr;

	ret = iwpm_get_remote_info(&listen_id_priv->id.m_local_addr,
				   &iw_event->remote_addr,
				   &cm_id->remote_addr,
				   RDMA_NL_IWCM);
	if (ret) {
		cm_id->remote_addr = iw_event->remote_addr;
	} else {
		iw_cm_check_wildcard(&listen_id_priv->id.m_local_addr,
				     &iw_event->local_addr,
				     &cm_id->local_addr);
		iw_event->local_addr = cm_id->local_addr;
		iw_event->remote_addr = cm_id->remote_addr;
	}

	cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
	cm_id_priv->state = IW_CM_STATE_CONN_RECV;
@@ -753,8 +876,10 @@ static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
	clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
	BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
	if (iw_event->status == 0) {
		cm_id_priv->id.local_addr = iw_event->local_addr;
		cm_id_priv->id.remote_addr = iw_event->remote_addr;
		cm_id_priv->id.m_local_addr = iw_event->local_addr;
		cm_id_priv->id.m_remote_addr = iw_event->remote_addr;
		iw_event->local_addr = cm_id_priv->id.local_addr;
		iw_event->remote_addr = cm_id_priv->id.remote_addr;
		cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
	} else {
		/* REJECTED or RESET */
@@ -1044,6 +1169,17 @@ EXPORT_SYMBOL(iw_cm_init_qp_attr);

static int __init iw_cm_init(void)
{
	int ret;

	ret = iwpm_init(RDMA_NL_IWCM);
	if (ret)
		pr_err("iw_cm: couldn't init iwpm\n");

	ret = ibnl_add_client(RDMA_NL_IWCM, RDMA_NL_IWPM_NUM_OPS,
			      iwcm_nl_cb_table);
	if (ret)
		pr_err("iw_cm: couldn't register netlink callbacks\n");

	iwcm_wq = create_singlethread_workqueue("iw_cm_wq");
	if (!iwcm_wq)
		return -ENOMEM;
@@ -1063,6 +1199,8 @@ static void __exit iw_cm_cleanup(void)
{
	unregister_net_sysctl_table(iwcm_ctl_table_hdr);
	destroy_workqueue(iwcm_wq);
	ibnl_remove_client(RDMA_NL_IWCM);
	iwpm_exit(RDMA_NL_IWCM);
}

module_init(iw_cm_init);
+6 −6
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_REG_PID_SEQ);
	if (ret)
		goto pid_query_error;
	ret = ibnl_put_attr(skb, nlh, IWPM_IFNAME_SIZE,
	ret = ibnl_put_attr(skb, nlh, IFNAMSIZ,
			    pm_msg->if_name, IWPM_NLA_REG_IF_NAME);
	if (ret)
		goto pid_query_error;
@@ -394,7 +394,7 @@ int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
	/* always for found nlmsg_request */
	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
	barrier();
	wake_up(&nlmsg_request->waitq);
	up(&nlmsg_request->sem);
	return 0;
}
EXPORT_SYMBOL(iwpm_register_pid_cb);
@@ -463,7 +463,7 @@ int iwpm_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
	/* always for found request */
	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
	barrier();
	wake_up(&nlmsg_request->waitq);
	up(&nlmsg_request->sem);
	return 0;
}
EXPORT_SYMBOL(iwpm_add_mapping_cb);
@@ -555,7 +555,7 @@ int iwpm_add_and_query_mapping_cb(struct sk_buff *skb,
	/* always for found request */
	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
	barrier();
	wake_up(&nlmsg_request->waitq);
	up(&nlmsg_request->sem);
	return 0;
}
EXPORT_SYMBOL(iwpm_add_and_query_mapping_cb);
@@ -749,7 +749,7 @@ int iwpm_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb)
	/* always for found request */
	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
	barrier();
	wake_up(&nlmsg_request->waitq);
	up(&nlmsg_request->sem);
	return 0;
}
EXPORT_SYMBOL(iwpm_mapping_error_cb);
+7 −7
Original line number Diff line number Diff line
@@ -322,6 +322,8 @@ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
	nlmsg_request->nl_client = nl_client;
	nlmsg_request->request_done = 0;
	nlmsg_request->err_code = 0;
	sema_init(&nlmsg_request->sem, 1);
	down(&nlmsg_request->sem);
	return nlmsg_request;
}

@@ -364,11 +366,9 @@ struct iwpm_nlmsg_request *iwpm_find_nlmsg_request(__u32 echo_seq)
int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request)
{
	int ret;
	init_waitqueue_head(&nlmsg_request->waitq);

	ret = wait_event_timeout(nlmsg_request->waitq,
			(nlmsg_request->request_done != 0), IWPM_NL_TIMEOUT);
	if (!ret) {
	ret = down_timeout(&nlmsg_request->sem, IWPM_NL_TIMEOUT);
	if (ret) {
		ret = -EINVAL;
		pr_info("%s: Timeout %d sec for netlink request (seq = %u)\n",
			__func__, (IWPM_NL_TIMEOUT/HZ), nlmsg_request->nlmsg_seq);
+1 −1
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ struct iwpm_nlmsg_request {
	u8	            nl_client;
	u8                  request_done;
	u16                 err_code;
	wait_queue_head_t   waitq;
	struct semaphore    sem;
	struct kref         kref;
};

+8 −8
Original line number Diff line number Diff line
@@ -1877,7 +1877,7 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
static int is_loopback_dst(struct iw_cm_id *cm_id)
{
	struct net_device *dev;
	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr;
	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;

	dev = ip_dev_find(&init_net, raddr->sin_addr.s_addr);
	if (!dev)
@@ -1892,10 +1892,10 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
	struct iwch_ep *ep;
	struct rtable *rt;
	int err = 0;
	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr;
	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr;
	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;

	if (cm_id->remote_addr.ss_family != PF_INET) {
	if (cm_id->m_remote_addr.ss_family != PF_INET) {
		err = -ENOSYS;
		goto out;
	}
@@ -1961,9 +1961,9 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)

	state_set(&ep->com, CONNECTING);
	ep->tos = IPTOS_LOWDELAY;
	memcpy(&ep->com.local_addr, &cm_id->local_addr,
	memcpy(&ep->com.local_addr, &cm_id->m_local_addr,
	       sizeof(ep->com.local_addr));
	memcpy(&ep->com.remote_addr, &cm_id->remote_addr,
	memcpy(&ep->com.remote_addr, &cm_id->m_remote_addr,
	       sizeof(ep->com.remote_addr));

	/* send connect request to rnic */
@@ -1992,7 +1992,7 @@ int iwch_create_listen(struct iw_cm_id *cm_id, int backlog)

	might_sleep();

	if (cm_id->local_addr.ss_family != PF_INET) {
	if (cm_id->m_local_addr.ss_family != PF_INET) {
		err = -ENOSYS;
		goto fail1;
	}
@@ -2008,7 +2008,7 @@ int iwch_create_listen(struct iw_cm_id *cm_id, int backlog)
	cm_id->add_ref(cm_id);
	ep->com.cm_id = cm_id;
	ep->backlog = backlog;
	memcpy(&ep->com.local_addr, &cm_id->local_addr,
	memcpy(&ep->com.local_addr, &cm_id->m_local_addr,
	       sizeof(ep->com.local_addr));

	/*
Loading