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

Commit 9a125395 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "net: ipc_router: Add support for connect system call"

parents 65f462d6 225f4ea2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -113,6 +113,9 @@ struct msm_ipc_port {
	struct mutex port_lock_lhc3;
	struct comm_mode_info mode_info;

	struct msm_ipc_port_addr dest_addr;
	int conn_status;

	struct list_head port_rx_q;
	struct mutex port_rx_q_lock_lhc3;
	char rx_ws_name[MAX_WS_NAME_SZ];
+117 −0
Original line number Diff line number Diff line
@@ -141,6 +141,11 @@ struct msm_ipc_resume_tx_port {
	uint32_t node_id;
};

struct ipc_router_conn_info {
	struct list_head list;
	uint32_t port_id;
};

#define RP_HASH_SIZE 32
struct msm_ipc_router_remote_port {
	struct list_head list;
@@ -150,6 +155,7 @@ struct msm_ipc_router_remote_port {
	uint32_t port_id;
	uint32_t tx_quota_cnt;
	struct list_head resume_tx_port_list;
	struct list_head conn_info_list;
	void *sec_rule;
	struct msm_ipc_server *server;
};
@@ -202,6 +208,7 @@ static struct workqueue_struct *msm_ipc_router_workqueue;

static int process_resume_tx_msg(union rr_control_msg *msg,
				 struct rr_packet *pkt);
static void ipc_router_reset_conn(struct msm_ipc_router_remote_port *rport_ptr);

enum {
	DOWN,
@@ -1188,6 +1195,7 @@ static struct msm_ipc_router_remote_port *ipc_router_create_rport(
	kref_init(&rport_ptr->ref);
	mutex_init(&rport_ptr->rport_lock_lhb2);
	INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
	INIT_LIST_HEAD(&rport_ptr->conn_info_list);
	list_add_tail(&rport_ptr->list,
		      &rt_entry->remote_port_list[key]);
out_create_rmt_port1:
@@ -1854,6 +1862,7 @@ static void cleanup_rmt_server(struct msm_ipc_router_xprt_info *xprt_info,
	D("Remove server %08x:%08x - %08x:%08x",
	   server->name.service, server->name.instance,
	   rport_ptr->node_id, rport_ptr->port_id);
	ipc_router_reset_conn(rport_ptr);
	memset(&ctl, 0, sizeof(ctl));
	ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
	ctl.srv.service = server->name.service;
@@ -2022,6 +2031,97 @@ void msm_ipc_sync_default_sec_rule(void *rule)
	up_write(&server_list_lock_lha2);
}

/**
 * ipc_router_reset_conn() - Reset the connection to remote port
 * @rport_ptr: Pointer to the remote port to be disconnected.
 *
 * This function is used to reset all the local ports that are connected to
 * the remote port being passed.
 */
static void ipc_router_reset_conn(struct msm_ipc_router_remote_port *rport_ptr)
{
	struct msm_ipc_port *port_ptr;
	struct ipc_router_conn_info *conn_info, *tmp_conn_info;

	mutex_lock(&rport_ptr->rport_lock_lhb2);
	list_for_each_entry_safe(conn_info, tmp_conn_info,
				&rport_ptr->conn_info_list, list) {
		port_ptr = ipc_router_get_port_ref(conn_info->port_id);
		if (!port_ptr)
			continue;
		mutex_lock(&port_ptr->port_lock_lhc3);
		port_ptr->conn_status = CONNECTION_RESET;
		mutex_unlock(&port_ptr->port_lock_lhc3);
		wake_up(&port_ptr->port_rx_wait_q);
		kref_put(&port_ptr->ref, ipc_router_release_port);

		list_del(&conn_info->list);
		kfree(conn_info);
	}
	mutex_unlock(&rport_ptr->rport_lock_lhb2);
}

/**
 * ipc_router_set_conn() - Set the connection by initializing dest address
 * @port_ptr: Local port in which the connection has to be set.
 * @addr: Destination address of the connection.
 *
 * @return: 0 on success, standard Linux error codes on failure.
 */
int ipc_router_set_conn(struct msm_ipc_port *port_ptr,
			struct msm_ipc_addr *addr)
{
	struct msm_ipc_router_remote_port *rport_ptr;
	struct ipc_router_conn_info *conn_info;

	if (unlikely(!port_ptr || !addr))
		return -EINVAL;

	if (addr->addrtype != MSM_IPC_ADDR_ID) {
		IPC_RTR_ERR("%s: Invalid Address type\n", __func__);
		return -EINVAL;
	}

	if (port_ptr->type == SERVER_PORT) {
		IPC_RTR_ERR("%s: Connection refused on a server port\n",
			    __func__);
		return -ECONNREFUSED;
	}

	if (port_ptr->conn_status == CONNECTED) {
		IPC_RTR_ERR("%s: Port %08x already connected\n",
			    __func__, port_ptr->this_port.port_id);
		return -EISCONN;
	}

	conn_info = kzalloc(sizeof(struct ipc_router_conn_info), GFP_KERNEL);
	if (!conn_info) {
		IPC_RTR_ERR("%s: Error allocating conn_info\n", __func__);
		return -ENOMEM;
	}
	INIT_LIST_HEAD(&conn_info->list);
	conn_info->port_id = port_ptr->this_port.port_id;

	rport_ptr = ipc_router_get_rport_ref(addr->addr.port_addr.node_id,
					     addr->addr.port_addr.port_id);
	if (!rport_ptr) {
		IPC_RTR_ERR("%s: Invalid remote endpoint\n", __func__);
		kfree(conn_info);
		return -ENODEV;
	}
	mutex_lock(&rport_ptr->rport_lock_lhb2);
	list_add_tail(&conn_info->list, &rport_ptr->conn_info_list);
	mutex_unlock(&rport_ptr->rport_lock_lhb2);

	mutex_lock(&port_ptr->port_lock_lhc3);
	memcpy(&port_ptr->dest_addr, &addr->addr.port_addr,
	       sizeof(struct msm_ipc_port_addr));
	port_ptr->conn_status = CONNECTED;
	mutex_unlock(&port_ptr->port_lock_lhc3);
	kref_put(&rport_ptr->ref, ipc_router_release_rport);
	return 0;
}

static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
			     struct rr_header_v1 *hdr)
{
@@ -2411,6 +2511,7 @@ int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
{
	struct msm_ipc_server *server;
	union rr_control_msg ctl;
	struct msm_ipc_router_remote_port *rport_ptr;

	if (!port_ptr)
		return -EINVAL;
@@ -2437,6 +2538,12 @@ int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
		return -ENODEV;
	}

	mutex_lock(&port_ptr->port_lock_lhc3);
	port_ptr->type = CLIENT_PORT;
	rport_ptr = (struct msm_ipc_router_remote_port *)port_ptr->rport_info;
	mutex_unlock(&port_ptr->port_lock_lhc3);
	if (rport_ptr)
		ipc_router_reset_conn(rport_ptr);
	memset(&ctl, 0, sizeof(ctl));
	ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
	ctl.srv.service = server->name.service;
@@ -2968,6 +3075,16 @@ int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
		list_del(&port_ptr->list);
		up_write(&local_ports_lock_lhc2);

		mutex_lock(&port_ptr->port_lock_lhc3);
		rport_ptr = (struct msm_ipc_router_remote_port *)
						port_ptr->rport_info;
		port_ptr->rport_info = NULL;
		mutex_unlock(&port_ptr->port_lock_lhc3);
		if (rport_ptr) {
			ipc_router_reset_conn(rport_ptr);
			ipc_router_destroy_rport(rport_ptr);
		}

		if (port_ptr->type == SERVER_PORT) {
			memset(&msg, 0, sizeof(msg));
			msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
+16 −0
Original line number Diff line number Diff line
@@ -64,6 +64,12 @@ enum {
	MULTI_LINK_MODE,
};

enum {
	CONNECTION_RESET = -1,
	NOT_CONNECTED,
	CONNECTED,
};

struct msm_ipc_sock {
	struct sock sk;
	struct msm_ipc_port *port;
@@ -114,4 +120,14 @@ void msm_ipc_sync_default_sec_rule(void *rule);
int msm_ipc_router_rx_data_wait(struct msm_ipc_port *port_ptr, long timeout);

void msm_ipc_router_free_skb(struct sk_buff_head *skb_head);

/**
 * ipc_router_set_conn() - Set the connection by initializing dest address
 * @port_ptr: Local port in which the connection has to be set.
 * @addr: Destination address of the connection.
 *
 * @return: 0 on success, standard Linux error codes on failure.
 */
int ipc_router_set_conn(struct msm_ipc_port *port_ptr,
			struct msm_ipc_addr *addr);
#endif
+59 −8
Original line number Diff line number Diff line
@@ -345,6 +345,42 @@ int msm_ipc_router_bind(struct socket *sock, struct sockaddr *uaddr,
	return ret;
}

static int ipc_router_connect(struct socket *sock, struct sockaddr *uaddr,
			      int uaddr_len, int flags)
{
	struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)uaddr;
	struct sock *sk = sock->sk;
	struct msm_ipc_port *port_ptr;
	int ret;

	if (!sk)
		return -EINVAL;

	if (uaddr_len <= 0) {
		IPC_RTR_ERR("%s: Invalid address length\n", __func__);
		return -EINVAL;
	}

	if (!addr) {
		IPC_RTR_ERR("%s: Invalid address\n", __func__);
		return -EINVAL;
	}

	if (addr->family != AF_MSM_IPC) {
		IPC_RTR_ERR("%s: Address family is incorrect\n", __func__);
		return -EAFNOSUPPORT;
	}

	port_ptr = msm_ipc_sk_port(sk);
	if (!port_ptr)
		return -ENODEV;

	lock_sock(sk);
	ret = ipc_router_set_conn(port_ptr, &addr->address);
	release_sock(sk);
	return ret;
}

static int msm_ipc_router_sendmsg(struct kiocb *iocb, struct socket *sock,
				  struct msghdr *m, size_t total_len)
{
@@ -354,12 +390,24 @@ static int msm_ipc_router_sendmsg(struct kiocb *iocb, struct socket *sock,
	struct sk_buff_head *msg;
	struct sk_buff *ipc_buf;
	int ret;
	struct msm_ipc_addr dest_addr = {0};

	if (!dest)
		return -EDESTADDRREQ;

	if (m->msg_namelen < sizeof(*dest) || dest->family != AF_MSM_IPC)
	if (dest) {
		if (m->msg_namelen < sizeof(*dest) ||
		    dest->family != AF_MSM_IPC)
			return -EINVAL;
		memcpy(&dest_addr, &dest->address, sizeof(dest_addr));
	} else {
		if (port_ptr->conn_status == NOT_CONNECTED) {
			return -EDESTADDRREQ;
		} else if (port_ptr->conn_status < CONNECTION_RESET) {
			return -ENETRESET;
		} else {
			memcpy(&dest_addr.addr.port_addr, &port_ptr->dest_addr,
				sizeof(struct msm_ipc_port_addr));
			dest_addr.addrtype = MSM_IPC_ADDR_ID;
		}
	}

	if (total_len > MAX_IPC_PKT_SIZE)
		return -EINVAL;
@@ -378,7 +426,7 @@ static int msm_ipc_router_sendmsg(struct kiocb *iocb, struct socket *sock,
	ipc_buf = skb_peek(msg);
	if (ipc_buf)
		msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
	ret = msm_ipc_router_send_to(port_ptr, msg, &dest_addr);
	if (ret != total_len) {
		if (ret < 0) {
			if (ret != -EAGAIN)
@@ -564,6 +612,9 @@ static unsigned int msm_ipc_router_poll(struct file *file,
	if (!list_empty(&port_ptr->port_rx_q))
		mask |= (POLLRDNORM | POLLIN);

	if (port_ptr->conn_status == CONNECTION_RESET)
		mask |= (POLLHUP | POLLERR);

	return mask;
}

@@ -594,7 +645,7 @@ static const struct proto_ops msm_ipc_proto_ops = {
	.owner			= THIS_MODULE,
	.release		= msm_ipc_router_close,
	.bind			= msm_ipc_router_bind,
	.connect		= sock_no_connect,
	.connect		= ipc_router_connect,
	.socketpair		= sock_no_socketpair,
	.accept			= sock_no_accept,
	.getname		= sock_no_getname,