Loading include/linux/ipc_router.h +3 −0 Original line number Diff line number Diff line Loading @@ -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]; Loading net/ipc_router/ipc_router_core.c +117 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; }; Loading Loading @@ -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, Loading Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading net/ipc_router/ipc_router_private.h +16 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 net/ipc_router/ipc_router_socket.c +59 −8 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; Loading @@ -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) Loading Loading @@ -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; } Loading Loading @@ -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 Loading
include/linux/ipc_router.h +3 −0 Original line number Diff line number Diff line Loading @@ -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]; Loading
net/ipc_router/ipc_router_core.c +117 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; }; Loading Loading @@ -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, Loading Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading
net/ipc_router/ipc_router_private.h +16 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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
net/ipc_router/ipc_router_socket.c +59 −8 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; Loading @@ -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) Loading Loading @@ -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; } Loading Loading @@ -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