Merge "net: ipc_router: Add support for connect system call"
This commit is contained in:
commit
9a12539569
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
return -EINVAL;
|
||||
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,
|
||||
|
|
Loading…
Reference in New Issue