net: ipc_router: Add snapshot of IPC Router
This snapshot is taken as of msm-4.4 'commit <d2afad6a903b>
("Merge "ext4 crypto: enable HW based encryption with ICE"")'.
Additionally fix the code style warnings and errors.
CRs-Fixed: 1079350
Change-Id: I0972e0a42d12659fc854dce2491df3016704d756
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
This commit is contained in:
parent
d579d924fd
commit
6a116d66c5
15 changed files with 6683 additions and 0 deletions
404
Documentation/arm/msm/msm_ipc_router.txt
Normal file
404
Documentation/arm/msm/msm_ipc_router.txt
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
Introduction
|
||||
============
|
||||
|
||||
Inter Process Communication(IPC) Message Router
|
||||
|
||||
IPC Router provides a connectionless message routing service between
|
||||
multiple processes in a MSM setup. The communicating processes can
|
||||
run either in the same processor or in a different processor within
|
||||
the MSM setup. The IPC Router has been designed to
|
||||
1) Route messages of any types
|
||||
2) Support a broader network of processors
|
||||
The IPC Router follows the same protocol as the existing RPC Router
|
||||
in the kernel while communicating with its peer IPC Routers.
|
||||
|
||||
Hardware description
|
||||
====================
|
||||
|
||||
The IPC Router doesn't implement any specific hardware driver.
|
||||
The IPC Router uses the existing hardware drivers to transport messages
|
||||
across to the peer router. IPC Router contains a XPRT interface layer to
|
||||
handle the different types of transports/links. This interface layer
|
||||
abstracts the underlying transport complexities from the router and
|
||||
provides a packet/message interface with the transports.
|
||||
|
||||
Software description
|
||||
====================
|
||||
|
||||
The IPC Router is designed to support a client-server model. The
|
||||
clients and servers communicate with one another by exchanging data
|
||||
units known as messages. A message is a byte string from 1 to 64K bytes
|
||||
long. The IPC Router provides a connectionless message routing service
|
||||
between the clients and servers i.e. any client/server can communicate
|
||||
with any other client/server in the network of processors.
|
||||
|
||||
Network Topology Overview:
|
||||
--------------------------
|
||||
|
||||
The system is organized as a network of nodes. Each processor in the
|
||||
network is the most fundamental element called node. The complete
|
||||
network is hierarchically structured i.e. the network is divided into
|
||||
tiers and each tier is fully-meshed. The following figure shows an
|
||||
example network topology.
|
||||
|
||||
|
||||
---N1--- ---N4---
|
||||
| | | |
|
||||
| | | |
|
||||
N2----N3-------N5-----N6
|
||||
| |
|
||||
| |
|
||||
---N7----
|
||||
| |
|
||||
| |
|
||||
N8------N9
|
||||
|
||||
Each node in the complete network is identified using a unique node id
|
||||
(Nx in the example network). In the example network, nodes N1, N2 & N3
|
||||
are fully-meshed to form a tier 1 network. Similarly nodes N4, N5 & N6
|
||||
form another tier 1 network and nodes N7, N8 & N9 form third tier 1
|
||||
network. These three tier 1 networks are fully-meshed to form a tier 2
|
||||
network.
|
||||
|
||||
Each transport/link in the network is identified using a unique name/id
|
||||
called XPRT id. This XPRT id is used by the nodes to identify the
|
||||
link to be used while sending message to a specific destination.
|
||||
In addition, each transport/link in the network is assigned a link id.
|
||||
This link id is used to identify the tier to which the link belongs to.
|
||||
This link marking is used to avoid the routing loops while forwarding
|
||||
the broadcast messages. The incoming messages are only forwarded onto an
|
||||
egress link which has a link id different from that of an ingress link.
|
||||
|
||||
IPC Router Addressing Overview:
|
||||
-------------------------------
|
||||
|
||||
Each client/server in the network is identified using a unique
|
||||
<Node_id:Port_id> combination. Node_id identifies the processor on which
|
||||
a client/server is running. Port_id is a unique id within a node. This
|
||||
Port_id is assigned by the IPC Router in that node when a client/server
|
||||
comes up. The Node_id & Port_id are 32 bits each.
|
||||
|
||||
Port_id 0xFFFFFFFE is reserved for Router &
|
||||
0xFFFFFFFF is reserved for broadcast messages.
|
||||
|
||||
Each server in the network can also be addressed using a service name.
|
||||
The service name is of the form <service(32 bits):instance(32 bits)>.
|
||||
When a server comes up, it binds itself with a service name. This name
|
||||
information along with the <Node_id:Port_id> is broadcast onto the
|
||||
entire network.
|
||||
|
||||
Control Path:
|
||||
-------------
|
||||
|
||||
IPC Router uses the control messages to communicate and propagate the
|
||||
system wide events to the other routers in the system. Some of the
|
||||
events include:
|
||||
1) Node Status
|
||||
2) Server Status
|
||||
3) Client Status
|
||||
4) Flow Control Request/Confirmation
|
||||
|
||||
Message Header:
|
||||
---------------
|
||||
|
||||
IPC Router prepends a header to every message that it communicates with
|
||||
other IPC Router. The receiving IPC Routers use the header to identify
|
||||
the source and destination of the message, size of the message, type
|
||||
of the message and handle any flow control requests. The IPC Router
|
||||
header format is as follows:
|
||||
|
||||
0 31
|
||||
-------------------------------------------------
|
||||
| Version |
|
||||
-------------------------------------------------
|
||||
| Message Type |
|
||||
-------------------------------------------------
|
||||
| Source Node ID |
|
||||
-------------------------------------------------
|
||||
| Source Port ID |
|
||||
-------------------------------------------------
|
||||
| Confirm RX |
|
||||
-------------------------------------------------
|
||||
| Payload Length |
|
||||
-------------------------------------------------
|
||||
| Destination Node ID |
|
||||
-------------------------------------------------
|
||||
| Destination Port ID |
|
||||
-------------------------------------------------
|
||||
|
||||
Message Header v2(Optimized):
|
||||
-----------------------------
|
||||
|
||||
The following optimization has been done to the IPC Router header to
|
||||
make it concise, align with the system requirement and enable future
|
||||
expansion:
|
||||
|
||||
0 8 16 24 31
|
||||
-----------------------------------------------------------------
|
||||
| Version | Message Type | Control Flag |
|
||||
-----------------------------------------------------------------
|
||||
| Payload Length |
|
||||
-----------------------------------------------------------------
|
||||
| Source Node ID | Source Port ID |
|
||||
-----------------------------------------------------------------
|
||||
| Destination Node ID | Destination Port ID |
|
||||
-----------------------------------------------------------------
|
||||
|
||||
Control Flag:
|
||||
|
||||
0 14 15
|
||||
------------------------------------------------------------------
|
||||
| Reserved | Opt. Hdr. | Confirm RX |
|
||||
------------------------------------------------------------------
|
||||
|
||||
IPC Router identifies and processes the header depending on the version
|
||||
field. The Confirm RX field in message header v1 becomes part of the
|
||||
control flag. All the other fields are reduced in size to align with the
|
||||
system requirement.
|
||||
|
||||
Optional Header:
|
||||
An optional header bit field is introduced in the control flag to handle
|
||||
any unforeseen future requirement that this header cannot handle. When
|
||||
that bit is set, an optional header follows the current header. The
|
||||
optional header format is as follows:
|
||||
|
||||
0 8 16 31
|
||||
-----------------------------------------------------------------
|
||||
| Length(words) | Type | Control Flag |
|
||||
-----------------------------------------------------------------
|
||||
| |
|
||||
| Optional Header Contents |
|
||||
| |
|
||||
-----------------------------------------------------------------
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
The IPC Router is organized into 2 layers:
|
||||
1) Router Core layer
|
||||
2) Router - XPRT Interface layer
|
||||
|
||||
|
||||
This organization allows the router to abstract the XPRT's complexities
|
||||
from that of the core router functionalities. The Router Core layer
|
||||
performs the following core functions:
|
||||
1) Message Routing
|
||||
2) Distributed name service
|
||||
3) Flow control between ports
|
||||
The Router core layer contains the following important data structures
|
||||
to perform the core functions in their respective order:
|
||||
1) Routing Table
|
||||
2) Table of Active Servers
|
||||
3) Table of Active Remote ports
|
||||
All these data structures get updated based on the events passed through
|
||||
the control path.
|
||||
|
||||
|
||||
The Router - XPRT Interface layer hides the underlying transport
|
||||
complexities and provides and abstracted packet interface to the
|
||||
Router Core layer. The Router - XPRT Interface layer registers itself
|
||||
with the Router Core layer upon complete initialization of the XPRT.
|
||||
The Router - XPRT Interface layer upon registration exports the
|
||||
following functionalities to the Router Core:
|
||||
1) Read from the XPRT
|
||||
2) # of bytes of data available to read
|
||||
3) Write to the XPRT
|
||||
4) Space available to write to the XPRT
|
||||
5) Close the XPRT
|
||||
|
||||
|
||||
The user behavioral model of the IPC Router should be
|
||||
1) Create a port
|
||||
2) If server, register a name to the port
|
||||
3) If remote port not known, lookup through the name
|
||||
4) Send messages over the port to the remote port
|
||||
5) Receive messages along with the source info from the port
|
||||
6) Repeat steps 3, 4 & 5 as required
|
||||
7) If server, unregister the name from the port
|
||||
8) Close the port
|
||||
|
||||
Power Management
|
||||
================
|
||||
|
||||
IPC Message Router uses wakelocks to ensure that the system does not go
|
||||
into suspend mode while there are pending messages to be handled. Once all
|
||||
the messages are handled, IPC Message Router releases the wakelocks to
|
||||
allow the system to go into suspend mode and comply with the system power
|
||||
management requirement.
|
||||
|
||||
SMP/multi-core
|
||||
==============
|
||||
|
||||
The IPC Router uses mutexes & spinlocks to protect the shared data
|
||||
structures to be SMP/multi-core safe.
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
None
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
None
|
||||
|
||||
Interface
|
||||
=========
|
||||
|
||||
Kernel-space APIs:
|
||||
------------------
|
||||
|
||||
/*
|
||||
* msm_ipc_router_create_port - Create a IPC Router port
|
||||
*
|
||||
* @msm_ipc_port_notify: notification function which will notify events
|
||||
* like READ_DATA_AVAIL, WRITE_DONE etc.
|
||||
* @priv: caller private context pointer, passed to the notify callback.
|
||||
*
|
||||
* @return: a valid port pointer on success, NULL on failure
|
||||
*
|
||||
*/
|
||||
struct msm_ipc_port * msm_ipc_router_create_port(
|
||||
void (*msm_ipc_port_notify)(unsigned event, void *data,
|
||||
void *addr, void *priv),
|
||||
void *priv)
|
||||
|
||||
|
||||
/*
|
||||
* msm_ipc_router_close_port - Close down the port
|
||||
*
|
||||
* @port: Port to be closed
|
||||
*
|
||||
* @return: 0 on success, -ve value on failure
|
||||
*
|
||||
*/
|
||||
int msm_ipc_router_close_port(struct msm_ipc_port *port)
|
||||
|
||||
|
||||
/*
|
||||
* msm_ipc_router_send_to - Send data to a remote port
|
||||
*
|
||||
* @from_port: Source port of the message
|
||||
* @data: Data to be sent
|
||||
* @to_addr: Destination port name or address
|
||||
*
|
||||
* @return: number of bytes sent on success, -ve value on failure
|
||||
*
|
||||
*/
|
||||
int msm_ipc_router_send_to(struct msm_ipc_port *from_port,
|
||||
struct sk_buff_head *data,
|
||||
struct msm_ipc_addr *to_addr)
|
||||
|
||||
|
||||
/*
|
||||
* msm_ipc_router_recv_from - Receive data over a port
|
||||
*
|
||||
* @port: Port from which the data has to be read
|
||||
* @data: Pointer to the data
|
||||
* @src_addr: If valid, filled with the source address of the data
|
||||
* @timeout: Time to wait for the data, if already not present
|
||||
*
|
||||
* @return: number of bytes received on success, -ve value on failure
|
||||
*
|
||||
*/
|
||||
int msm_ipc_router_recv_from(struct msm_ipc_port *port,
|
||||
struct sk_buff_head **data,
|
||||
struct msm_ipc_addr *src_addr,
|
||||
unsigned long timeout)
|
||||
|
||||
/*
|
||||
* msm_ipc_router_register_server - Bind a local port with a service
|
||||
* name
|
||||
*
|
||||
* @server_port: Port to be bound with a service name
|
||||
* @name: Name to bind with the port
|
||||
*
|
||||
* @return: 0 on success, -ve value on failure
|
||||
*
|
||||
*/
|
||||
int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
|
||||
struct msm_ipc_addr *name)
|
||||
|
||||
|
||||
/*
|
||||
* msm_ipc_router_unregister_server - Unbind the local port from its
|
||||
* service name
|
||||
*
|
||||
* @server_port: Port to be unbound from its service name
|
||||
*
|
||||
* @return: 0 on success, -ve value on failure
|
||||
*
|
||||
*/
|
||||
int msm_ipc_router_unregister_server(struct msm_ipc_port *server_port)
|
||||
|
||||
|
||||
/*
|
||||
* msm_ipc_router_lookup_server - Lookup port address for the port name
|
||||
*
|
||||
* @name: Name to be looked up for
|
||||
*
|
||||
* @return: Port address corresponding to the service name on success,
|
||||
* NULL on failure
|
||||
*
|
||||
*/
|
||||
struct msm_ipc_addr * msm_ipc_router_lookup_server(
|
||||
struct msm_ipc_addr *name)
|
||||
|
||||
|
||||
User-space APIs:
|
||||
----------------
|
||||
|
||||
User-space applications/utilities can use the socket APIs to interface
|
||||
with the IPC Router. IPC Router, in order to support the socket APIs,
|
||||
will register a new socket Address/Protocol Family with the kernel
|
||||
Socket layer. The identity of the new Address/Protocol Family will be
|
||||
defined using the macro AF_MSM_IPC/PF_MSM_IPC (hardcoded to 38) in
|
||||
include/linux/socket.h file. Since IPC Router supports only message
|
||||
oriented transfer, only SOCK_DGRAM type of sockets will be supported
|
||||
by the IPC Router.
|
||||
|
||||
Driver parameters
|
||||
=================
|
||||
|
||||
debug_mask - This module parameter is used to enable/disable Router
|
||||
log messages in the kernel logs. This parameter can take any value
|
||||
from 0 to 255.
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
Drivers in this project:
|
||||
-----------------------
|
||||
|
||||
The following drivers are present in this project, listed in the
|
||||
bottom - up order of the stack.
|
||||
|
||||
1a) Router - SMD XPRT Interface driver. This driver is used to interface
|
||||
the Router with the SMD transport.
|
||||
1b) Router - HSIC XPRT Interface driver. This driver is used to interface
|
||||
the Router with the HSIC_IPC Bridge transport for off-chip communication.
|
||||
2) Core Router driver. This driver performs the core functionalities
|
||||
3) Socket - Router Interface driver. This driver enables the socket
|
||||
interface to be used with the IPC Router.
|
||||
|
||||
In the write/send direction, these drivers interact by invoking the
|
||||
exported APIs from the underlying drivers. In the read/receive
|
||||
directions, these drivers interact by passing messages/events.
|
||||
|
||||
Drivers Needed:
|
||||
---------------
|
||||
|
||||
1) SMD
|
||||
2) Kernel Socket Layer
|
||||
3) Platform Driver
|
||||
4) HSIC IPC Bridge Driver
|
||||
|
||||
To do
|
||||
=====
|
||||
Improvements:
|
||||
-------------
|
||||
|
||||
The IPC Router is designed to route any messages, as long as the system
|
||||
follows the network architecture and addressing schemes. But the
|
||||
implementation in progress will route only QMI messages. With few
|
||||
additional enhancements, it can route existing RPC messages too.
|
||||
16
Documentation/devicetree/bindings/arm/msm/msm_ipc_router.txt
Normal file
16
Documentation/devicetree/bindings/arm/msm/msm_ipc_router.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
Qualcomm Technologies, Inc. IPC Router
|
||||
|
||||
Required properties:
|
||||
-compatible: should be "qcom,ipc_router"
|
||||
-qcom,node-id: unique ID to identify the node in network
|
||||
|
||||
Optional properties:
|
||||
-qcom,default-peripheral: String property to indicate the default peripheral
|
||||
to communicate
|
||||
|
||||
Example:
|
||||
qcom,ipc_router {
|
||||
compatible = "qcom,ipc_router";
|
||||
qcom,node-id = <1>;
|
||||
qcom,default-peripheral = "modem";
|
||||
};
|
||||
346
include/linux/ipc_router.h
Normal file
346
include/linux/ipc_router.h
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _IPC_ROUTER_H
|
||||
#define _IPC_ROUTER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/msm_ipc.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kref.h>
|
||||
|
||||
/* Maximum Wakeup Source Name Size */
|
||||
#define MAX_WS_NAME_SZ 32
|
||||
|
||||
#define IPC_RTR_ERR(buf, ...) \
|
||||
pr_err("IPC_RTR: " buf, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* enum msm_ipc_router_event - Events that will be generated by IPC Router
|
||||
*/
|
||||
enum msm_ipc_router_event {
|
||||
IPC_ROUTER_CTRL_CMD_DATA = 1,
|
||||
IPC_ROUTER_CTRL_CMD_HELLO,
|
||||
IPC_ROUTER_CTRL_CMD_BYE,
|
||||
IPC_ROUTER_CTRL_CMD_NEW_SERVER,
|
||||
IPC_ROUTER_CTRL_CMD_REMOVE_SERVER,
|
||||
IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT,
|
||||
IPC_ROUTER_CTRL_CMD_RESUME_TX,
|
||||
};
|
||||
|
||||
/**
|
||||
* rr_control_msg - Control message structure
|
||||
* @cmd: Command identifier for HELLO message in Version 1.
|
||||
* @hello: Message structure for HELLO message in Version 2.
|
||||
* @srv: Message structure for NEW_SERVER/REMOVE_SERVER events.
|
||||
* @cli: Message structure for REMOVE_CLIENT event.
|
||||
*/
|
||||
union rr_control_msg {
|
||||
uint32_t cmd;
|
||||
struct {
|
||||
uint32_t cmd;
|
||||
uint32_t checksum;
|
||||
uint32_t versions;
|
||||
uint32_t capability;
|
||||
uint32_t reserved;
|
||||
} hello;
|
||||
struct {
|
||||
uint32_t cmd;
|
||||
uint32_t service;
|
||||
uint32_t instance;
|
||||
uint32_t node_id;
|
||||
uint32_t port_id;
|
||||
} srv;
|
||||
struct {
|
||||
uint32_t cmd;
|
||||
uint32_t node_id;
|
||||
uint32_t port_id;
|
||||
} cli;
|
||||
};
|
||||
|
||||
struct comm_mode_info {
|
||||
int mode;
|
||||
void *xprt_info;
|
||||
};
|
||||
|
||||
enum ipc_rtr_af_event_type {
|
||||
IPCRTR_AF_INIT = 1,
|
||||
IPCRTR_AF_DEINIT,
|
||||
};
|
||||
|
||||
/**
|
||||
* msm_ipc_port - Definition of IPC Router port
|
||||
* @list: List(local/control ports) in which this port is present.
|
||||
* @ref: Reference count for this port.
|
||||
* @this_port: Contains port's node_id and port_id information.
|
||||
* @port_name: Contains service & instance info if the port hosts a service.
|
||||
* @type: Type of the port - Client, Service, Control or Security Config.
|
||||
* @flags: Flags to identify the port state.
|
||||
* @port_lock_lhc3: Lock to protect access to the port information.
|
||||
* @mode_info: Communication mode of the port owner.
|
||||
* @port_rx_q: Receive queue where incoming messages are queued.
|
||||
* @port_rx_q_lock_lhc3: Lock to protect access to the port's rx_q.
|
||||
* @rx_ws_name: Name of the receive wakeup source.
|
||||
* @port_rx_ws: Wakeup source to prevent suspend until the rx_q is empty.
|
||||
* @port_rx_wait_q: Wait queue to wait for the incoming messages.
|
||||
* @restart_state: Flag to hold the restart state information.
|
||||
* @restart_lock: Lock to protect access to the restart_state.
|
||||
* @restart_wait: Wait Queue to wait for any restart events.
|
||||
* @endpoint: Contains the information related to user-space interface.
|
||||
* @notify: Function to notify the incoming events on the port.
|
||||
* @check_send_permissions: Function to check access control from this port.
|
||||
* @num_tx: Number of packets transmitted.
|
||||
* @num_rx: Number of packets received.
|
||||
* @num_tx_bytes: Number of bytes transmitted.
|
||||
* @num_rx_bytes: Number of bytes received.
|
||||
* @priv: Private information registered by the port owner.
|
||||
*/
|
||||
struct msm_ipc_port {
|
||||
struct list_head list;
|
||||
struct kref ref;
|
||||
|
||||
struct msm_ipc_port_addr this_port;
|
||||
struct msm_ipc_port_name port_name;
|
||||
uint32_t type;
|
||||
unsigned int flags;
|
||||
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];
|
||||
struct wakeup_source *port_rx_ws;
|
||||
wait_queue_head_t port_rx_wait_q;
|
||||
wait_queue_head_t port_tx_wait_q;
|
||||
|
||||
int restart_state;
|
||||
spinlock_t restart_lock;
|
||||
wait_queue_head_t restart_wait;
|
||||
|
||||
void *rport_info;
|
||||
void *endpoint;
|
||||
void (*notify)(unsigned int event, void *oob_data,
|
||||
size_t oob_data_len, void *priv);
|
||||
int (*check_send_permissions)(void *data);
|
||||
|
||||
uint32_t num_tx;
|
||||
uint32_t num_rx;
|
||||
unsigned long num_tx_bytes;
|
||||
unsigned long num_rx_bytes;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IPC_ROUTER
|
||||
/**
|
||||
* msm_ipc_router_create_port() - Create a IPC Router port/endpoint
|
||||
* @notify: Callback function to notify any event on the port.
|
||||
* @event: Event ID to be handled.
|
||||
* @oob_data: Any out-of-band data associated with the event.
|
||||
* @oob_data_len: Size of the out-of-band data, if valid.
|
||||
* @priv: Private data registered during the port creation.
|
||||
* @priv: Private info to be passed while the notification is generated.
|
||||
*
|
||||
* @return: Pointer to the port on success, NULL on error.
|
||||
*/
|
||||
struct msm_ipc_port *msm_ipc_router_create_port(
|
||||
void (*notify)(unsigned int event, void *oob_data,
|
||||
size_t oob_data_len, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_bind_control_port() - Bind a port as a control port
|
||||
* @port_ptr: Port which needs to be marked as a control port.
|
||||
*
|
||||
* @return: 0 on success, standard Linux error codes on error.
|
||||
*/
|
||||
int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_lookup_server_name() - Resolve server address
|
||||
* @srv_name: Name<service:instance> of the server to be resolved.
|
||||
* @srv_info: Buffer to hold the resolved address.
|
||||
* @num_entries_in_array: Number of server info the buffer can hold.
|
||||
* @lookup_mask: Mask to specify the range of instances to be resolved.
|
||||
*
|
||||
* @return: Number of server addresses resolved on success, < 0 on error.
|
||||
*/
|
||||
int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
|
||||
struct msm_ipc_server_info *srv_info,
|
||||
int num_entries_in_array,
|
||||
uint32_t lookup_mask);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_send_msg() - Send a message/packet
|
||||
* @src: Sender's address/port.
|
||||
* @dest: Destination address.
|
||||
* @data: Pointer to the data to be sent.
|
||||
* @data_len: Length of the data to be sent.
|
||||
*
|
||||
* @return: 0 on success, < 0 on error.
|
||||
*/
|
||||
int msm_ipc_router_send_msg(struct msm_ipc_port *src,
|
||||
struct msm_ipc_addr *dest,
|
||||
void *data, unsigned int data_len);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_get_curr_pkt_size() - Get the packet size of the first
|
||||
* packet in the rx queue
|
||||
* @port_ptr: Port which owns the rx queue.
|
||||
*
|
||||
* @return: Returns the size of the first packet, if available.
|
||||
* 0 if no packets available, < 0 on error.
|
||||
*/
|
||||
int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_read_msg() - Read a message/packet
|
||||
* @port_ptr: Receiver's port/address.
|
||||
* @data: Pointer containing the address of the received data.
|
||||
* @src: Address of the sender/source.
|
||||
* @len: Length of the data being read.
|
||||
*
|
||||
* @return: 0 on success, < 0 on error.
|
||||
*/
|
||||
int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
|
||||
struct msm_ipc_addr *src,
|
||||
unsigned char **data,
|
||||
unsigned int *len);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_close_port() - Close the port
|
||||
* @port_ptr: Pointer to the port to be closed.
|
||||
*
|
||||
* @return: 0 on success, < 0 on error.
|
||||
*/
|
||||
int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_register_server() - Register a service on a port
|
||||
* @server_port: IPC Router port with which a service is registered.
|
||||
* @name: Service name <service_id:instance_id> that gets registered.
|
||||
*
|
||||
* @return: 0 on success, standard Linux error codes on error.
|
||||
*/
|
||||
int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
|
||||
struct msm_ipc_addr *name);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_unregister_server() - Unregister a service from a port
|
||||
* @server_port: Port with with a service is already registered.
|
||||
*
|
||||
* @return: 0 on success, standard Linux error codes on error.
|
||||
*/
|
||||
int msm_ipc_router_unregister_server(struct msm_ipc_port *server_port);
|
||||
|
||||
/**
|
||||
* register_ipcrtr_af_init_notifier() - Register for ipc router socket
|
||||
* address family initialization callback
|
||||
* @nb: Notifier block which will be notified once address family is
|
||||
* initialized.
|
||||
*
|
||||
* Return: 0 on success, standard error code otherwise.
|
||||
*/
|
||||
int register_ipcrtr_af_init_notifier(struct notifier_block *nb);
|
||||
|
||||
/**
|
||||
* unregister_ipcrtr_af_init_notifier() - Unregister for ipc router socket
|
||||
* address family initialization callback
|
||||
* @nb: Notifier block which will be notified once address family is
|
||||
* initialized.
|
||||
*
|
||||
* Return: 0 on success, standard error code otherwise.
|
||||
*/
|
||||
int unregister_ipcrtr_af_init_notifier(struct notifier_block *nb);
|
||||
|
||||
#else
|
||||
|
||||
struct msm_ipc_port *msm_ipc_router_create_port(
|
||||
void (*notify)(unsigned int event, void *oob_data,
|
||||
size_t oob_data_len, void *priv),
|
||||
void *priv)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int msm_ipc_router_bind_control_port(
|
||||
struct msm_ipc_port *port_ptr)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
|
||||
struct msm_ipc_server_info *srv_info,
|
||||
int num_entries_in_array,
|
||||
uint32_t lookup_mask)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int msm_ipc_router_send_msg(struct msm_ipc_port *src,
|
||||
struct msm_ipc_addr *dest,
|
||||
void *data, unsigned int data_len)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
|
||||
struct msm_ipc_addr *src,
|
||||
unsigned char **data,
|
||||
unsigned int *len)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int msm_ipc_router_register_server(
|
||||
struct msm_ipc_port *server_port,
|
||||
struct msm_ipc_addr *name)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int msm_ipc_router_unregister_server(
|
||||
struct msm_ipc_port *server_port)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int register_ipcrtr_af_init_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int unregister_ipcrtr_af_init_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
175
include/linux/ipc_router_xprt.h
Normal file
175
include/linux/ipc_router_xprt.h
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _IPC_ROUTER_XPRT_H
|
||||
#define _IPC_ROUTER_XPRT_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/msm_ipc.h>
|
||||
#include <linux/ipc_router.h>
|
||||
#include <linux/kref.h>
|
||||
|
||||
#define IPC_ROUTER_XPRT_EVENT_DATA 1
|
||||
#define IPC_ROUTER_XPRT_EVENT_OPEN 2
|
||||
#define IPC_ROUTER_XPRT_EVENT_CLOSE 3
|
||||
|
||||
#define FRAG_PKT_WRITE_ENABLE 0x1
|
||||
|
||||
/**
|
||||
* rr_header_v1 - IPC Router header version 1
|
||||
* @version: Version information.
|
||||
* @type: IPC Router Message Type.
|
||||
* @src_node_id: Source Node ID of the message.
|
||||
* @src_port_id: Source Port ID of the message.
|
||||
* @control_flag: Flag to indicate flow control.
|
||||
* @size: Size of the IPC Router payload.
|
||||
* @dst_node_id: Destination Node ID of the message.
|
||||
* @dst_port_id: Destination Port ID of the message.
|
||||
*/
|
||||
struct rr_header_v1 {
|
||||
uint32_t version;
|
||||
uint32_t type;
|
||||
uint32_t src_node_id;
|
||||
uint32_t src_port_id;
|
||||
uint32_t control_flag;
|
||||
uint32_t size;
|
||||
uint32_t dst_node_id;
|
||||
uint32_t dst_port_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* rr_header_v2 - IPC Router header version 2
|
||||
* @version: Version information.
|
||||
* @type: IPC Router Message Type.
|
||||
* @control_flag: Flags to indicate flow control, optional header etc.
|
||||
* @opt_len: Combined size of the all optional headers in units of words.
|
||||
* @size: Size of the IPC Router payload.
|
||||
* @src_node_id: Source Node ID of the message.
|
||||
* @src_port_id: Source Port ID of the message.
|
||||
* @dst_node_id: Destination Node ID of the message.
|
||||
* @dst_port_id: Destination Port ID of the message.
|
||||
*/
|
||||
struct rr_header_v2 {
|
||||
uint8_t version;
|
||||
uint8_t type;
|
||||
uint8_t control_flag;
|
||||
uint8_t opt_len;
|
||||
uint32_t size;
|
||||
uint16_t src_node_id;
|
||||
uint16_t src_port_id;
|
||||
uint16_t dst_node_id;
|
||||
uint16_t dst_port_id;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
union rr_header {
|
||||
struct rr_header_v1 hdr_v1;
|
||||
struct rr_header_v2 hdr_v2;
|
||||
};
|
||||
|
||||
/**
|
||||
* rr_opt_hdr - Optional header for IPC Router header version 2
|
||||
* @len: Total length of the optional header.
|
||||
* @data: Pointer to the actual optional header.
|
||||
*/
|
||||
struct rr_opt_hdr {
|
||||
size_t len;
|
||||
unsigned char *data;
|
||||
};
|
||||
|
||||
#define IPC_ROUTER_HDR_SIZE sizeof(union rr_header)
|
||||
#define IPCR_WORD_SIZE 4
|
||||
|
||||
/**
|
||||
* rr_packet - Router to Router packet structure
|
||||
* @list: Pointer to prev & next packets in a port's rx list.
|
||||
* @hdr: Header information extracted from or prepended to a packet.
|
||||
* @opt_hdr: Optinal header information.
|
||||
* @pkt_fragment_q: Queue of SKBs containing payload.
|
||||
* @length: Length of data in the chain of SKBs
|
||||
* @ref: Reference count for the packet.
|
||||
*/
|
||||
struct rr_packet {
|
||||
struct list_head list;
|
||||
struct rr_header_v1 hdr;
|
||||
struct rr_opt_hdr opt_hdr;
|
||||
struct sk_buff_head *pkt_fragment_q;
|
||||
uint32_t length;
|
||||
struct kref ref;
|
||||
};
|
||||
|
||||
/**
|
||||
* msm_ipc_router_xprt - Structure to hold XPRT specific information
|
||||
* @name: Name of the XPRT.
|
||||
* @link_id: Network cluster ID to which the XPRT belongs to.
|
||||
* @priv: XPRT's private data.
|
||||
* @get_version: Method to get header version supported by the XPRT.
|
||||
* @set_version: Method to set header version in XPRT.
|
||||
* @get_option: Method to get XPRT specific options.
|
||||
* @read_avail: Method to get data size available to be read from the XPRT.
|
||||
* @read: Method to read data from the XPRT.
|
||||
* @write_avail: Method to get write space available in the XPRT.
|
||||
* @write: Method to write data to the XPRT.
|
||||
* @close: Method to close the XPRT.
|
||||
* @sft_close_done: Method to indicate to the XPRT that handling of reset
|
||||
* event is complete.
|
||||
*/
|
||||
struct msm_ipc_router_xprt {
|
||||
char *name;
|
||||
uint32_t link_id;
|
||||
void *priv;
|
||||
|
||||
int (*get_version)(struct msm_ipc_router_xprt *xprt);
|
||||
int (*get_option)(struct msm_ipc_router_xprt *xprt);
|
||||
void (*set_version)(struct msm_ipc_router_xprt *xprt,
|
||||
unsigned int version);
|
||||
int (*read_avail)(struct msm_ipc_router_xprt *xprt);
|
||||
int (*read)(void *data, uint32_t len,
|
||||
struct msm_ipc_router_xprt *xprt);
|
||||
int (*write_avail)(struct msm_ipc_router_xprt *xprt);
|
||||
int (*write)(void *data, uint32_t len,
|
||||
struct msm_ipc_router_xprt *xprt);
|
||||
int (*close)(struct msm_ipc_router_xprt *xprt);
|
||||
void (*sft_close_done)(struct msm_ipc_router_xprt *xprt);
|
||||
};
|
||||
|
||||
void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
|
||||
unsigned int event,
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* create_pkt() - Create a Router packet
|
||||
* @data: SKB queue to be contained inside the packet.
|
||||
*
|
||||
* @return: pointer to packet on success, NULL on failure.
|
||||
*/
|
||||
struct rr_packet *create_pkt(struct sk_buff_head *data);
|
||||
struct rr_packet *clone_pkt(struct rr_packet *pkt);
|
||||
void release_pkt(struct rr_packet *pkt);
|
||||
|
||||
/**
|
||||
* ipc_router_peek_pkt_size() - Peek into the packet header to get potential
|
||||
* packet size
|
||||
* @data: Starting address of the packet which points to router header.
|
||||
*
|
||||
* @returns: potential packet size on success, < 0 on error.
|
||||
*
|
||||
* This function is used by the underlying transport abstraction layer to
|
||||
* peek into the potential packet size of an incoming packet. This information
|
||||
* is used to perform link layer fragmentation and re-assembly
|
||||
*/
|
||||
int ipc_router_peek_pkt_size(char *data);
|
||||
|
||||
#endif
|
||||
|
|
@ -281,6 +281,7 @@ header-y += mroute.h
|
|||
header-y += msdos_fs.h
|
||||
header-y += msg.h
|
||||
header-y += msm_ion.h
|
||||
header-y += msm_ipc.h
|
||||
header-y += msm_rmnet.h
|
||||
header-y += mtio.h
|
||||
header-y += nbd.h
|
||||
|
|
|
|||
91
include/uapi/linux/msm_ipc.h
Normal file
91
include/uapi/linux/msm_ipc.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#ifndef _UAPI_MSM_IPC_H_
|
||||
#define _UAPI_MSM_IPC_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
struct msm_ipc_port_addr {
|
||||
uint32_t node_id;
|
||||
uint32_t port_id;
|
||||
};
|
||||
|
||||
struct msm_ipc_port_name {
|
||||
uint32_t service;
|
||||
uint32_t instance;
|
||||
};
|
||||
|
||||
struct msm_ipc_addr {
|
||||
unsigned char addrtype;
|
||||
union {
|
||||
struct msm_ipc_port_addr port_addr;
|
||||
struct msm_ipc_port_name port_name;
|
||||
} addr;
|
||||
};
|
||||
|
||||
#define MSM_IPC_WAIT_FOREVER (~0) /* timeout for permanent subscription */
|
||||
|
||||
/*
|
||||
* Socket API
|
||||
*/
|
||||
|
||||
#ifndef AF_MSM_IPC
|
||||
#define AF_MSM_IPC 27
|
||||
#endif
|
||||
|
||||
#ifndef PF_MSM_IPC
|
||||
#define PF_MSM_IPC AF_MSM_IPC
|
||||
#endif
|
||||
|
||||
#define MSM_IPC_ADDR_NAME 1
|
||||
#define MSM_IPC_ADDR_ID 2
|
||||
|
||||
struct sockaddr_msm_ipc {
|
||||
unsigned short family;
|
||||
struct msm_ipc_addr address;
|
||||
unsigned char reserved;
|
||||
};
|
||||
|
||||
struct config_sec_rules_args {
|
||||
int num_group_info;
|
||||
uint32_t service_id;
|
||||
uint32_t instance_id;
|
||||
unsigned int reserved;
|
||||
gid_t group_id[0];
|
||||
};
|
||||
|
||||
#define IPC_ROUTER_IOCTL_MAGIC (0xC3)
|
||||
|
||||
#define IPC_ROUTER_IOCTL_GET_VERSION \
|
||||
_IOR(IPC_ROUTER_IOCTL_MAGIC, 0, unsigned int)
|
||||
|
||||
#define IPC_ROUTER_IOCTL_GET_MTU \
|
||||
_IOR(IPC_ROUTER_IOCTL_MAGIC, 1, unsigned int)
|
||||
|
||||
#define IPC_ROUTER_IOCTL_LOOKUP_SERVER \
|
||||
_IOWR(IPC_ROUTER_IOCTL_MAGIC, 2, struct sockaddr_msm_ipc)
|
||||
|
||||
#define IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE \
|
||||
_IOR(IPC_ROUTER_IOCTL_MAGIC, 3, unsigned int)
|
||||
|
||||
#define IPC_ROUTER_IOCTL_BIND_CONTROL_PORT \
|
||||
_IOR(IPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
|
||||
|
||||
#define IPC_ROUTER_IOCTL_CONFIG_SEC_RULES \
|
||||
_IOR(IPC_ROUTER_IOCTL_MAGIC, 5, struct config_sec_rules_args)
|
||||
|
||||
struct msm_ipc_server_info {
|
||||
uint32_t node_id;
|
||||
uint32_t port_id;
|
||||
uint32_t service;
|
||||
uint32_t instance;
|
||||
};
|
||||
|
||||
struct server_lookup_args {
|
||||
struct msm_ipc_port_name port_name;
|
||||
int num_entries_in_array;
|
||||
int num_entries_found;
|
||||
uint32_t lookup_mask;
|
||||
struct msm_ipc_server_info srv_info[0];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -429,6 +429,8 @@ config MAY_USE_DEVLINK
|
|||
on MAY_USE_DEVLINK to ensure they do not cause link errors when
|
||||
devlink is a loadable module and the driver using it is built-in.
|
||||
|
||||
source "net/ipc_router/Kconfig"
|
||||
|
||||
endif # if NET
|
||||
|
||||
# Used by archs to tell that they support BPF JIT compiler plus which flavour.
|
||||
|
|
|
|||
|
|
@ -82,3 +82,4 @@ endif
|
|||
obj-$(CONFIG_QRTR) += qrtr/
|
||||
obj-$(CONFIG_NET_NCSI) += ncsi/
|
||||
obj-$(CONFIG_RMNET_DATA) += rmnet_data/
|
||||
obj-$(CONFIG_IPC_ROUTER) += ipc_router/
|
||||
|
|
|
|||
25
net/ipc_router/Kconfig
Normal file
25
net/ipc_router/Kconfig
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
# IPC_ROUTER Configuration
|
||||
#
|
||||
|
||||
menuconfig IPC_ROUTER
|
||||
bool "IPC Router support"
|
||||
help
|
||||
IPC Router provides a connectionless message routing service
|
||||
between multiple modules within a System-on-Chip(SoC). The
|
||||
communicating entities can run either in the same processor or
|
||||
in a different processor within the SoC. The IPC Router has been
|
||||
designed to route messages of any types and support a broader
|
||||
network of processors.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config IPC_ROUTER_SECURITY
|
||||
depends on IPC_ROUTER
|
||||
bool "IPC Router Security support"
|
||||
help
|
||||
This feature of IPC Router will enforce security rules
|
||||
configured by a security script from the user-space. IPC Router
|
||||
once configured with the security rules will ensure that the
|
||||
sender of the message to a service belongs to the relevant
|
||||
Linux group as configured by the security script.
|
||||
7
net/ipc_router/Makefile
Normal file
7
net/ipc_router/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# Makefile for the Linux IPC_ROUTER
|
||||
#
|
||||
|
||||
obj-$(CONFIG_IPC_ROUTER) := ipc_router_core.o
|
||||
obj-$(CONFIG_IPC_ROUTER) += ipc_router_socket.o
|
||||
obj-$(CONFIG_IPC_ROUTER_SECURITY) += ipc_router_security.o
|
||||
4334
net/ipc_router/ipc_router_core.c
Normal file
4334
net/ipc_router/ipc_router_core.c
Normal file
File diff suppressed because it is too large
Load diff
150
net/ipc_router/ipc_router_private.h
Normal file
150
net/ipc_router/ipc_router_private.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _IPC_ROUTER_PRIVATE_H
|
||||
#define _IPC_ROUTER_PRIVATE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/msm_ipc.h>
|
||||
#include <linux/ipc_router.h>
|
||||
#include <linux/ipc_router_xprt.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
/* definitions for the R2R wire protocol */
|
||||
#define IPC_ROUTER_V1 1
|
||||
/* Ambiguous definition but will enable multiplexing IPC_ROUTER_V2 packets
|
||||
* with an existing alternate transport in user-space, if needed.
|
||||
*/
|
||||
#define IPC_ROUTER_V2 3
|
||||
#define IPC_ROUTER_VER_BITMASK ((BIT(IPC_ROUTER_V1)) | (BIT(IPC_ROUTER_V2)))
|
||||
#define IPC_ROUTER_HELLO_MAGIC 0xE110
|
||||
#define IPC_ROUTER_CHECKSUM_MASK 0xFFFF
|
||||
|
||||
#define IPC_ROUTER_ADDRESS 0x0000FFFF
|
||||
|
||||
#define IPC_ROUTER_NID_LOCAL 1
|
||||
#define MAX_IPC_PKT_SIZE 66000
|
||||
|
||||
#define IPC_ROUTER_LOW_RX_QUOTA 5
|
||||
#define IPC_ROUTER_HIGH_RX_QUOTA 10
|
||||
|
||||
#define IPC_ROUTER_INFINITY -1
|
||||
#define DEFAULT_RCV_TIMEO IPC_ROUTER_INFINITY
|
||||
#define DEFAULT_SND_TIMEO IPC_ROUTER_INFINITY
|
||||
|
||||
#define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
|
||||
|
||||
#define ALL_SERVICE 0xFFFFFFFF
|
||||
#define ALL_INSTANCE 0xFFFFFFFF
|
||||
|
||||
#define CONTROL_FLAG_CONFIRM_RX 0x1
|
||||
#define CONTROL_FLAG_OPT_HDR 0x2
|
||||
|
||||
enum {
|
||||
CLIENT_PORT,
|
||||
SERVER_PORT,
|
||||
CONTROL_PORT,
|
||||
IRSC_PORT,
|
||||
};
|
||||
|
||||
enum {
|
||||
NULL_MODE,
|
||||
SINGLE_LINK_MODE,
|
||||
MULTI_LINK_MODE,
|
||||
};
|
||||
|
||||
enum {
|
||||
CONNECTION_RESET = -1,
|
||||
NOT_CONNECTED,
|
||||
CONNECTED,
|
||||
};
|
||||
|
||||
struct msm_ipc_sock {
|
||||
struct sock sk;
|
||||
struct msm_ipc_port *port;
|
||||
void *default_node_vote_info;
|
||||
};
|
||||
|
||||
/**
|
||||
* msm_ipc_router_create_raw_port() - Create an IPC Router port
|
||||
* @endpoint: User-space space socket information to be cached.
|
||||
* @notify: Function to notify incoming events on the port.
|
||||
* @event: Event ID to be handled.
|
||||
* @oob_data: Any out-of-band data associated with the event.
|
||||
* @oob_data_len: Size of the out-of-band data, if valid.
|
||||
* @priv: Private data registered during the port creation.
|
||||
* @priv: Private Data to be passed during the event notification.
|
||||
*
|
||||
* @return: Valid pointer to port on success, NULL on failure.
|
||||
*
|
||||
* This function is used to create an IPC Router port. The port is used for
|
||||
* communication locally or outside the subsystem.
|
||||
*/
|
||||
struct msm_ipc_port *
|
||||
msm_ipc_router_create_raw_port(void *endpoint,
|
||||
void (*notify)(unsigned int event,
|
||||
void *oob_data,
|
||||
size_t oob_data_len, void *priv),
|
||||
void *priv);
|
||||
int msm_ipc_router_send_to(struct msm_ipc_port *src,
|
||||
struct sk_buff_head *data,
|
||||
struct msm_ipc_addr *dest,
|
||||
long timeout);
|
||||
int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
|
||||
struct rr_packet **pkt,
|
||||
size_t buf_len);
|
||||
|
||||
int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
|
||||
struct rr_packet **pkt,
|
||||
struct msm_ipc_addr *src_addr, long timeout);
|
||||
int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
|
||||
struct msm_ipc_addr *name);
|
||||
int msm_ipc_router_unregister_server(struct msm_ipc_port *server_port);
|
||||
|
||||
int msm_ipc_router_init_sockets(void);
|
||||
void msm_ipc_router_exit_sockets(void);
|
||||
|
||||
void msm_ipc_sync_sec_rule(u32 service, u32 instance, void *rule);
|
||||
|
||||
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);
|
||||
|
||||
void *msm_ipc_load_default_node(void);
|
||||
|
||||
void msm_ipc_unload_default_node(void *pil);
|
||||
|
||||
/**
|
||||
* ipc_router_dummy_write_space() - Dummy write space available callback
|
||||
* @sk: Socket pointer for which the callback is called.
|
||||
*/
|
||||
void ipc_router_dummy_write_space(struct sock *sk);
|
||||
|
||||
#endif
|
||||
330
net/ipc_router/ipc_router_security.c
Normal file
330
net/ipc_router/ipc_router_security.c
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
/* Copyright (c) 2012-2014,2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/msm_ipc.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include "ipc_router_private.h"
|
||||
#include "ipc_router_security.h"
|
||||
|
||||
#define IRSC_COMPLETION_TIMEOUT_MS 30000
|
||||
#define SEC_RULES_HASH_SZ 32
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#endif
|
||||
|
||||
struct security_rule {
|
||||
struct list_head list;
|
||||
u32 service_id;
|
||||
u32 instance_id;
|
||||
unsigned int reserved;
|
||||
int num_group_info;
|
||||
kgid_t *group_id;
|
||||
};
|
||||
|
||||
static DECLARE_RWSEM(security_rules_lock_lha4);
|
||||
static struct list_head security_rules[SEC_RULES_HASH_SZ];
|
||||
static DECLARE_COMPLETION(irsc_completion);
|
||||
|
||||
/**
|
||||
* wait_for_irsc_completion() - Wait for IPC Router Security Configuration
|
||||
* (IRSC) to complete
|
||||
*/
|
||||
void wait_for_irsc_completion(void)
|
||||
{
|
||||
unsigned long rem_jiffies;
|
||||
|
||||
do {
|
||||
rem_jiffies = wait_for_completion_timeout
|
||||
(&irsc_completion,
|
||||
msecs_to_jiffies(IRSC_COMPLETION_TIMEOUT_MS));
|
||||
if (rem_jiffies)
|
||||
return;
|
||||
pr_err("%s: waiting for IPC Security Conf.\n", __func__);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/**
|
||||
* signal_irsc_completion() - Signal the completion of IRSC
|
||||
*/
|
||||
void signal_irsc_completion(void)
|
||||
{
|
||||
complete_all(&irsc_completion);
|
||||
}
|
||||
|
||||
/**
|
||||
* check_permisions() - Check whether the process has permissions to
|
||||
* create an interface handle with IPC Router
|
||||
*
|
||||
* @return: true if the process has permissions, else false.
|
||||
*/
|
||||
int check_permissions(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (capable(CAP_NET_RAW) || capable(CAP_NET_BIND_SERVICE))
|
||||
rc = 1;
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(check_permissions);
|
||||
|
||||
/**
|
||||
* msm_ipc_config_sec_rules() - Add a security rule to the database
|
||||
* @arg: Pointer to the buffer containing the rule.
|
||||
*
|
||||
* @return: 0 if successfully added, < 0 for error.
|
||||
*
|
||||
* A security rule is defined using <Service_ID: Group_ID> tuple. The rule
|
||||
* implies that a user-space process in order to send a QMI message to
|
||||
* service Service_ID should belong to the Linux group Group_ID.
|
||||
*/
|
||||
int msm_ipc_config_sec_rules(void *arg)
|
||||
{
|
||||
struct config_sec_rules_args sec_rules_arg;
|
||||
struct security_rule *rule, *temp_rule;
|
||||
int key;
|
||||
size_t kgroup_info_sz;
|
||||
int ret;
|
||||
size_t group_info_sz;
|
||||
gid_t *group_id = NULL;
|
||||
int loop;
|
||||
|
||||
if (!uid_eq(current_euid(), GLOBAL_ROOT_UID))
|
||||
return -EPERM;
|
||||
|
||||
ret = copy_from_user(&sec_rules_arg, (void *)arg,
|
||||
sizeof(sec_rules_arg));
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
if (sec_rules_arg.num_group_info <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (sec_rules_arg.num_group_info > (SIZE_MAX / sizeof(gid_t))) {
|
||||
pr_err("%s: Integer Overflow %zu * %d\n", __func__,
|
||||
sizeof(gid_t), sec_rules_arg.num_group_info);
|
||||
return -EINVAL;
|
||||
}
|
||||
group_info_sz = sec_rules_arg.num_group_info * sizeof(gid_t);
|
||||
|
||||
if (sec_rules_arg.num_group_info > (SIZE_MAX / sizeof(kgid_t))) {
|
||||
pr_err("%s: Integer Overflow %zu * %d\n", __func__,
|
||||
sizeof(kgid_t), sec_rules_arg.num_group_info);
|
||||
return -EINVAL;
|
||||
}
|
||||
kgroup_info_sz = sec_rules_arg.num_group_info * sizeof(kgid_t);
|
||||
|
||||
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
|
||||
if (!rule)
|
||||
return -ENOMEM;
|
||||
|
||||
rule->group_id = kzalloc(kgroup_info_sz, GFP_KERNEL);
|
||||
if (!rule->group_id) {
|
||||
kfree(rule);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
group_id = kzalloc(group_info_sz, GFP_KERNEL);
|
||||
if (!group_id) {
|
||||
kfree(rule->group_id);
|
||||
kfree(rule);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rule->service_id = sec_rules_arg.service_id;
|
||||
rule->instance_id = sec_rules_arg.instance_id;
|
||||
rule->reserved = sec_rules_arg.reserved;
|
||||
rule->num_group_info = sec_rules_arg.num_group_info;
|
||||
ret = copy_from_user(group_id, ((void *)(arg + sizeof(sec_rules_arg))),
|
||||
group_info_sz);
|
||||
if (ret) {
|
||||
kfree(group_id);
|
||||
kfree(rule->group_id);
|
||||
kfree(rule);
|
||||
return -EFAULT;
|
||||
}
|
||||
for (loop = 0; loop < rule->num_group_info; loop++)
|
||||
rule->group_id[loop] = make_kgid(current_user_ns(),
|
||||
group_id[loop]);
|
||||
kfree(group_id);
|
||||
|
||||
key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
|
||||
down_write(&security_rules_lock_lha4);
|
||||
if (rule->service_id == ALL_SERVICE) {
|
||||
temp_rule = list_first_entry(&security_rules[key],
|
||||
struct security_rule, list);
|
||||
list_del(&temp_rule->list);
|
||||
kfree(temp_rule->group_id);
|
||||
kfree(temp_rule);
|
||||
}
|
||||
list_add_tail(&rule->list, &security_rules[key]);
|
||||
up_write(&security_rules_lock_lha4);
|
||||
|
||||
if (rule->service_id == ALL_SERVICE)
|
||||
msm_ipc_sync_default_sec_rule((void *)rule);
|
||||
else
|
||||
msm_ipc_sync_sec_rule(rule->service_id, rule->instance_id,
|
||||
(void *)rule);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_ipc_config_sec_rules);
|
||||
|
||||
/**
|
||||
* msm_ipc_add_default_rule() - Add default security rule
|
||||
*
|
||||
* @return: 0 on success, < 0 on error/
|
||||
*
|
||||
* This function is used to ensure the basic security, if there is no
|
||||
* security rule defined for a service. It can be overwritten by the
|
||||
* default security rule from user-space script.
|
||||
*/
|
||||
static int msm_ipc_add_default_rule(void)
|
||||
{
|
||||
struct security_rule *rule;
|
||||
int key;
|
||||
|
||||
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
|
||||
if (!rule)
|
||||
return -ENOMEM;
|
||||
|
||||
rule->group_id = kzalloc(sizeof(*rule->group_id), GFP_KERNEL);
|
||||
if (!rule->group_id) {
|
||||
kfree(rule);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rule->service_id = ALL_SERVICE;
|
||||
rule->instance_id = ALL_INSTANCE;
|
||||
rule->num_group_info = 1;
|
||||
*rule->group_id = AID_NET_RAW;
|
||||
down_write(&security_rules_lock_lha4);
|
||||
key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
|
||||
list_add_tail(&rule->list, &security_rules[key]);
|
||||
up_write(&security_rules_lock_lha4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* msm_ipc_get_security_rule() - Get the security rule corresponding to a
|
||||
* service
|
||||
* @service_id: Service ID for which the rule has to be got.
|
||||
* @instance_id: Instance ID for which the rule has to be got.
|
||||
*
|
||||
* @return: Returns the rule info on success, NULL on error.
|
||||
*
|
||||
* This function is used when the service comes up and gets registered with
|
||||
* the IPC Router.
|
||||
*/
|
||||
void *msm_ipc_get_security_rule(u32 service_id, u32 instance_id)
|
||||
{
|
||||
int key;
|
||||
struct security_rule *rule;
|
||||
|
||||
key = (service_id & (SEC_RULES_HASH_SZ - 1));
|
||||
down_read(&security_rules_lock_lha4);
|
||||
/* Return the rule for a specific <service:instance>, if found. */
|
||||
list_for_each_entry(rule, &security_rules[key], list) {
|
||||
if ((rule->service_id == service_id) &&
|
||||
(rule->instance_id == instance_id)) {
|
||||
up_read(&security_rules_lock_lha4);
|
||||
return (void *)rule;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the rule for a specific service, if found. */
|
||||
list_for_each_entry(rule, &security_rules[key], list) {
|
||||
if ((rule->service_id == service_id) &&
|
||||
(rule->instance_id == ALL_INSTANCE)) {
|
||||
up_read(&security_rules_lock_lha4);
|
||||
return (void *)rule;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the default rule, if no rule defined for a service. */
|
||||
key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
|
||||
list_for_each_entry(rule, &security_rules[key], list) {
|
||||
if ((rule->service_id == ALL_SERVICE) &&
|
||||
(rule->instance_id == ALL_INSTANCE)) {
|
||||
up_read(&security_rules_lock_lha4);
|
||||
return (void *)rule;
|
||||
}
|
||||
}
|
||||
up_read(&security_rules_lock_lha4);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_ipc_get_security_rule);
|
||||
|
||||
/**
|
||||
* msm_ipc_check_send_permissions() - Check if the sendng process has
|
||||
* permissions specified as per the rule
|
||||
* @data: Security rule to be checked.
|
||||
*
|
||||
* @return: true if the process has permissions, else false.
|
||||
*
|
||||
* This function is used to check if the current executing process has
|
||||
* permissions to send message to the remote entity. The security rule
|
||||
* corresponding to the remote entity is specified by "data" parameter
|
||||
*/
|
||||
int msm_ipc_check_send_permissions(void *data)
|
||||
{
|
||||
int i;
|
||||
struct security_rule *rule = (struct security_rule *)data;
|
||||
|
||||
/* Source/Sender is Root user */
|
||||
if (uid_eq(current_euid(), GLOBAL_ROOT_UID))
|
||||
return 1;
|
||||
|
||||
/* Destination has no rules defined, possibly a client. */
|
||||
if (!rule)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < rule->num_group_info; i++) {
|
||||
if (!gid_valid(rule->group_id[i]))
|
||||
continue;
|
||||
if (in_egroup_p(rule->group_id[i]))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_ipc_check_send_permissions);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_security_init() - Initialize the security rule database
|
||||
*
|
||||
* @return: 0 if successful, < 0 for error.
|
||||
*/
|
||||
int msm_ipc_router_security_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SEC_RULES_HASH_SZ; i++)
|
||||
INIT_LIST_HEAD(&security_rules[i]);
|
||||
|
||||
msm_ipc_add_default_rule();
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_ipc_router_security_init);
|
||||
120
net/ipc_router/ipc_router_security.h
Normal file
120
net/ipc_router/ipc_router_security.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/* Copyright (c) 2012-2014,2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _IPC_ROUTER_SECURITY_H
|
||||
#define _IPC_ROUTER_SECURITY_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#ifdef CONFIG_IPC_ROUTER_SECURITY
|
||||
#include <linux/android_aid.h>
|
||||
|
||||
/**
|
||||
* check_permisions() - Check whether the process has permissions to
|
||||
* create an interface handle with IPC Router
|
||||
*
|
||||
* @return: true if the process has permissions, else false.
|
||||
*/
|
||||
int check_permissions(void);
|
||||
|
||||
/**
|
||||
* msm_ipc_config_sec_rules() - Add a security rule to the database
|
||||
* @arg: Pointer to the buffer containing the rule.
|
||||
*
|
||||
* @return: 0 if successfully added, < 0 for error.
|
||||
*
|
||||
* A security rule is defined using <Service_ID: Group_ID> tuple. The rule
|
||||
* implies that a user-space process in order to send a QMI message to
|
||||
* service Service_ID should belong to the Linux group Group_ID.
|
||||
*/
|
||||
int msm_ipc_config_sec_rules(void *arg);
|
||||
|
||||
/**
|
||||
* msm_ipc_get_security_rule() - Get the security rule corresponding to a
|
||||
* service
|
||||
* @service_id: Service ID for which the rule has to be got.
|
||||
* @instance_id: Instance ID for which the rule has to be got.
|
||||
*
|
||||
* @return: Returns the rule info on success, NULL on error.
|
||||
*
|
||||
* This function is used when the service comes up and gets registered with
|
||||
* the IPC Router.
|
||||
*/
|
||||
void *msm_ipc_get_security_rule(u32 service_id, u32 instance_id);
|
||||
|
||||
/**
|
||||
* msm_ipc_check_send_permissions() - Check if the sendng process has
|
||||
* permissions specified as per the rule
|
||||
* @data: Security rule to be checked.
|
||||
*
|
||||
* @return: true if the process has permissions, else false.
|
||||
*
|
||||
* This function is used to check if the current executing process has
|
||||
* permissions to send message to the remote entity. The security rule
|
||||
* corresponding to the remote entity is specified by "data" parameter
|
||||
*/
|
||||
int msm_ipc_check_send_permissions(void *data);
|
||||
|
||||
/**
|
||||
* msm_ipc_router_security_init() - Initialize the security rule database
|
||||
*
|
||||
* @return: 0 if successful, < 0 for error.
|
||||
*/
|
||||
int msm_ipc_router_security_init(void);
|
||||
|
||||
/**
|
||||
* wait_for_irsc_completion() - Wait for IPC Router Security Configuration
|
||||
* (IRSC) to complete
|
||||
*/
|
||||
void wait_for_irsc_completion(void);
|
||||
|
||||
/**
|
||||
* signal_irsc_completion() - Signal the completion of IRSC
|
||||
*/
|
||||
void signal_irsc_completion(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline int check_permissions(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int msm_ipc_config_sec_rules(void *arg)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void *msm_ipc_get_security_rule(u32 service_id,
|
||||
u32 instance_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int msm_ipc_check_send_permissions(void *data)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int msm_ipc_router_security_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void wait_for_irsc_completion(void) { }
|
||||
|
||||
static inline void signal_irsc_completion(void) { }
|
||||
|
||||
#endif
|
||||
#endif
|
||||
681
net/ipc_router/ipc_router_socket.c
Normal file
681
net/ipc_router/ipc_router_socket.c
Normal file
|
|
@ -0,0 +1,681 @@
|
|||
/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/msm_ipc.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kmemleak.h>
|
||||
#include <linux/ipc_logging.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/ipc_router.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
#include "ipc_router_private.h"
|
||||
#include "ipc_router_security.h"
|
||||
|
||||
#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
|
||||
#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#endif
|
||||
|
||||
static int sockets_enabled;
|
||||
static struct proto msm_ipc_proto;
|
||||
static const struct proto_ops msm_ipc_proto_ops;
|
||||
static RAW_NOTIFIER_HEAD(ipcrtr_af_init_chain);
|
||||
static DEFINE_MUTEX(ipcrtr_af_init_lock);
|
||||
|
||||
static struct sk_buff_head *msm_ipc_router_build_msg(struct msghdr *m,
|
||||
size_t total_len)
|
||||
{
|
||||
struct sk_buff_head *msg_head;
|
||||
struct sk_buff *msg;
|
||||
int first = 1;
|
||||
int last = 1;
|
||||
size_t data_size = 0;
|
||||
size_t alloc_size, align_size;
|
||||
void *data;
|
||||
size_t total_copied_size = 0, copied_size;
|
||||
|
||||
if (iov_iter_count(&m->msg_iter) == total_len)
|
||||
data_size = total_len;
|
||||
|
||||
if (!data_size)
|
||||
return NULL;
|
||||
align_size = ALIGN_SIZE(data_size);
|
||||
|
||||
msg_head = kmalloc(sizeof(*msg_head), GFP_KERNEL);
|
||||
if (!msg_head) {
|
||||
IPC_RTR_ERR("%s: cannot allocate skb_head\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
skb_queue_head_init(msg_head);
|
||||
|
||||
while (total_copied_size < total_len) {
|
||||
alloc_size = data_size;
|
||||
if (first)
|
||||
alloc_size += IPC_ROUTER_HDR_SIZE;
|
||||
if (last)
|
||||
alloc_size += align_size;
|
||||
|
||||
msg = alloc_skb(alloc_size, GFP_KERNEL);
|
||||
if (!msg) {
|
||||
if (alloc_size <= (PAGE_SIZE / 2)) {
|
||||
IPC_RTR_ERR("%s: cannot allocated skb\n",
|
||||
__func__);
|
||||
goto msg_build_failure;
|
||||
}
|
||||
data_size = data_size / 2;
|
||||
last = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
skb_reserve(msg, IPC_ROUTER_HDR_SIZE);
|
||||
first = 0;
|
||||
}
|
||||
|
||||
data = skb_put(msg, data_size);
|
||||
copied_size = copy_from_iter(msg->data, data_size,
|
||||
&m->msg_iter);
|
||||
if (copied_size != data_size) {
|
||||
IPC_RTR_ERR("%s: copy_from_iter failed %zu %zu %zu\n",
|
||||
__func__, alloc_size, data_size,
|
||||
copied_size);
|
||||
kfree_skb(msg);
|
||||
goto msg_build_failure;
|
||||
}
|
||||
skb_queue_tail(msg_head, msg);
|
||||
total_copied_size += data_size;
|
||||
data_size = total_len - total_copied_size;
|
||||
last = 1;
|
||||
}
|
||||
return msg_head;
|
||||
|
||||
msg_build_failure:
|
||||
while (!skb_queue_empty(msg_head)) {
|
||||
msg = skb_dequeue(msg_head);
|
||||
kfree_skb(msg);
|
||||
}
|
||||
kfree(msg_head);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int msm_ipc_router_extract_msg(struct msghdr *m,
|
||||
struct rr_packet *pkt)
|
||||
{
|
||||
struct sockaddr_msm_ipc *addr;
|
||||
struct rr_header_v1 *hdr;
|
||||
struct sk_buff *temp;
|
||||
union rr_control_msg *ctl_msg;
|
||||
int offset = 0, data_len = 0, copy_len, copied_len;
|
||||
|
||||
if (!m || !pkt) {
|
||||
IPC_RTR_ERR("%s: Invalid pointers passed\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
addr = (struct sockaddr_msm_ipc *)m->msg_name;
|
||||
|
||||
hdr = &pkt->hdr;
|
||||
if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
|
||||
temp = skb_peek(pkt->pkt_fragment_q);
|
||||
ctl_msg = (union rr_control_msg *)(temp->data);
|
||||
addr->family = AF_MSM_IPC;
|
||||
addr->address.addrtype = MSM_IPC_ADDR_ID;
|
||||
addr->address.addr.port_addr.node_id = ctl_msg->cli.node_id;
|
||||
addr->address.addr.port_addr.port_id = ctl_msg->cli.port_id;
|
||||
m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
|
||||
return offset;
|
||||
}
|
||||
if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) {
|
||||
addr->family = AF_MSM_IPC;
|
||||
addr->address.addrtype = MSM_IPC_ADDR_ID;
|
||||
addr->address.addr.port_addr.node_id = hdr->src_node_id;
|
||||
addr->address.addr.port_addr.port_id = hdr->src_port_id;
|
||||
m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
|
||||
}
|
||||
|
||||
data_len = hdr->size;
|
||||
skb_queue_walk(pkt->pkt_fragment_q, temp) {
|
||||
copy_len = data_len < temp->len ? data_len : temp->len;
|
||||
copied_len = copy_to_iter(temp->data, copy_len, &m->msg_iter);
|
||||
if (copy_len != copied_len) {
|
||||
IPC_RTR_ERR("%s: Copy to user failed\n", __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
offset += copy_len;
|
||||
data_len -= copy_len;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int msm_ipc_router_create(struct net *net,
|
||||
struct socket *sock,
|
||||
int protocol,
|
||||
int kern)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct msm_ipc_port *port_ptr;
|
||||
|
||||
if (unlikely(protocol != 0)) {
|
||||
IPC_RTR_ERR("%s: Protocol not supported\n", __func__);
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
switch (sock->type) {
|
||||
case SOCK_DGRAM:
|
||||
break;
|
||||
default:
|
||||
IPC_RTR_ERR("%s: Protocol type not supported\n", __func__);
|
||||
return -EPROTOTYPE;
|
||||
}
|
||||
|
||||
sk = sk_alloc(net, AF_MSM_IPC, GFP_KERNEL, &msm_ipc_proto, kern);
|
||||
if (!sk) {
|
||||
IPC_RTR_ERR("%s: sk_alloc failed\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sock->ops = &msm_ipc_proto_ops;
|
||||
sock_init_data(sock, sk);
|
||||
sk->sk_data_ready = NULL;
|
||||
sk->sk_write_space = ipc_router_dummy_write_space;
|
||||
sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
|
||||
sk->sk_sndtimeo = DEFAULT_SND_TIMEO;
|
||||
|
||||
port_ptr = msm_ipc_router_create_raw_port(sk, NULL, NULL);
|
||||
if (!port_ptr) {
|
||||
IPC_RTR_ERR("%s: port_ptr alloc failed\n", __func__);
|
||||
sock_put(sk);
|
||||
sock->sk = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
port_ptr->check_send_permissions = msm_ipc_check_send_permissions;
|
||||
msm_ipc_sk(sk)->port = port_ptr;
|
||||
msm_ipc_sk(sk)->default_node_vote_info = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msm_ipc_router_bind(struct socket *sock, struct sockaddr *uaddr,
|
||||
int uaddr_len)
|
||||
{
|
||||
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 (!check_permissions()) {
|
||||
IPC_RTR_ERR("%s: %s Do not have permissions\n",
|
||||
__func__, current->comm);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (!uaddr_len) {
|
||||
IPC_RTR_ERR("%s: Invalid address length\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (addr->family != AF_MSM_IPC) {
|
||||
IPC_RTR_ERR("%s: Address family is incorrect\n", __func__);
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
if (addr->address.addrtype != MSM_IPC_ADDR_NAME) {
|
||||
IPC_RTR_ERR("%s: Address type is incorrect\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port_ptr = msm_ipc_sk_port(sk);
|
||||
if (!port_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
if (!msm_ipc_sk(sk)->default_node_vote_info)
|
||||
msm_ipc_sk(sk)->default_node_vote_info =
|
||||
msm_ipc_load_default_node();
|
||||
lock_sock(sk);
|
||||
|
||||
ret = msm_ipc_router_register_server(port_ptr, &addr->address);
|
||||
|
||||
release_sock(sk);
|
||||
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 socket *sock,
|
||||
struct msghdr *m, size_t total_len)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
|
||||
struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
|
||||
struct sk_buff_head *msg;
|
||||
int ret;
|
||||
struct msm_ipc_addr dest_addr = {0};
|
||||
long timeout;
|
||||
|
||||
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;
|
||||
if (port_ptr->conn_status < CONNECTION_RESET)
|
||||
return -ENETRESET;
|
||||
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;
|
||||
|
||||
lock_sock(sk);
|
||||
timeout = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
|
||||
msg = msm_ipc_router_build_msg(m, total_len);
|
||||
if (!msg) {
|
||||
IPC_RTR_ERR("%s: Msg build failure\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto out_sendmsg;
|
||||
}
|
||||
kmemleak_not_leak(msg);
|
||||
|
||||
if (port_ptr->type == CLIENT_PORT)
|
||||
wait_for_irsc_completion();
|
||||
ret = msm_ipc_router_send_to(port_ptr, msg, &dest_addr, timeout);
|
||||
if (ret != total_len) {
|
||||
if (ret < 0) {
|
||||
if (ret != -EAGAIN)
|
||||
IPC_RTR_ERR("%s: Send_to failure %d\n",
|
||||
__func__, ret);
|
||||
msm_ipc_router_free_skb(msg);
|
||||
} else if (ret >= 0) {
|
||||
ret = -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
out_sendmsg:
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_ipc_router_recvmsg(struct socket *sock,
|
||||
struct msghdr *m, size_t buf_len, int flags)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
|
||||
struct rr_packet *pkt;
|
||||
long timeout;
|
||||
int ret;
|
||||
|
||||
lock_sock(sk);
|
||||
if (!buf_len) {
|
||||
if (flags & MSG_PEEK)
|
||||
ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
||||
|
||||
ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
|
||||
if (ret) {
|
||||
release_sock(sk);
|
||||
if (ret == -ENOMSG)
|
||||
m->msg_namelen = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = msm_ipc_router_read(port_ptr, &pkt, buf_len);
|
||||
if (ret <= 0 || !pkt) {
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = msm_ipc_router_extract_msg(m, pkt);
|
||||
release_pkt(pkt);
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_ipc_router_ioctl(struct socket *sock,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct msm_ipc_port *port_ptr;
|
||||
struct server_lookup_args server_arg;
|
||||
struct msm_ipc_server_info *srv_info = NULL;
|
||||
unsigned int n;
|
||||
size_t srv_info_sz = 0;
|
||||
int ret;
|
||||
|
||||
if (!sk)
|
||||
return -EINVAL;
|
||||
|
||||
lock_sock(sk);
|
||||
port_ptr = msm_ipc_sk_port(sock->sk);
|
||||
if (!port_ptr) {
|
||||
release_sock(sk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case IPC_ROUTER_IOCTL_GET_VERSION:
|
||||
n = IPC_ROUTER_V1;
|
||||
ret = put_user(n, (unsigned int *)arg);
|
||||
break;
|
||||
|
||||
case IPC_ROUTER_IOCTL_GET_MTU:
|
||||
n = (MAX_IPC_PKT_SIZE - IPC_ROUTER_HDR_SIZE);
|
||||
ret = put_user(n, (unsigned int *)arg);
|
||||
break;
|
||||
|
||||
case IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
|
||||
ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
|
||||
break;
|
||||
|
||||
case IPC_ROUTER_IOCTL_LOOKUP_SERVER:
|
||||
if (!msm_ipc_sk(sk)->default_node_vote_info)
|
||||
msm_ipc_sk(sk)->default_node_vote_info =
|
||||
msm_ipc_load_default_node();
|
||||
|
||||
ret = copy_from_user(&server_arg, (void *)arg,
|
||||
sizeof(server_arg));
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (server_arg.num_entries_in_array < 0) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (server_arg.num_entries_in_array) {
|
||||
if (server_arg.num_entries_in_array >
|
||||
(SIZE_MAX / sizeof(*srv_info))) {
|
||||
IPC_RTR_ERR("%s: Integer Overflow %zu * %d\n",
|
||||
__func__, sizeof(*srv_info),
|
||||
server_arg.num_entries_in_array);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
srv_info_sz = server_arg.num_entries_in_array *
|
||||
sizeof(*srv_info);
|
||||
srv_info = kmalloc(srv_info_sz, GFP_KERNEL);
|
||||
if (!srv_info) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = msm_ipc_router_lookup_server_name
|
||||
(&server_arg.port_name, srv_info,
|
||||
server_arg.num_entries_in_array,
|
||||
server_arg.lookup_mask);
|
||||
if (ret < 0) {
|
||||
IPC_RTR_ERR("%s: Server not found\n", __func__);
|
||||
ret = -ENODEV;
|
||||
kfree(srv_info);
|
||||
break;
|
||||
}
|
||||
server_arg.num_entries_found = ret;
|
||||
|
||||
ret = copy_to_user((void *)arg, &server_arg,
|
||||
sizeof(server_arg));
|
||||
|
||||
n = min(server_arg.num_entries_found,
|
||||
server_arg.num_entries_in_array);
|
||||
|
||||
if (ret == 0 && n) {
|
||||
ret = copy_to_user((void *)(arg + sizeof(server_arg)),
|
||||
srv_info, n * sizeof(*srv_info));
|
||||
}
|
||||
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
kfree(srv_info);
|
||||
break;
|
||||
|
||||
case IPC_ROUTER_IOCTL_BIND_CONTROL_PORT:
|
||||
ret = msm_ipc_router_bind_control_port(port_ptr);
|
||||
break;
|
||||
|
||||
case IPC_ROUTER_IOCTL_CONFIG_SEC_RULES:
|
||||
ret = msm_ipc_config_sec_rules((void *)arg);
|
||||
if (ret != -EPERM)
|
||||
port_ptr->type = IRSC_PORT;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int msm_ipc_router_poll(struct file *file, struct socket *sock,
|
||||
poll_table *wait)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct msm_ipc_port *port_ptr;
|
||||
u32 mask = 0;
|
||||
|
||||
if (!sk)
|
||||
return -EINVAL;
|
||||
|
||||
port_ptr = msm_ipc_sk_port(sk);
|
||||
if (!port_ptr)
|
||||
return -EINVAL;
|
||||
|
||||
poll_wait(file, &port_ptr->port_rx_wait_q, wait);
|
||||
|
||||
if (!list_empty(&port_ptr->port_rx_q))
|
||||
mask |= (POLLRDNORM | POLLIN);
|
||||
|
||||
if (port_ptr->conn_status == CONNECTION_RESET)
|
||||
mask |= (POLLHUP | POLLERR);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int msm_ipc_router_close(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
|
||||
int ret;
|
||||
|
||||
lock_sock(sk);
|
||||
ret = msm_ipc_router_close_port(port_ptr);
|
||||
msm_ipc_unload_default_node(msm_ipc_sk(sk)->default_node_vote_info);
|
||||
release_sock(sk);
|
||||
sock_put(sk);
|
||||
sock->sk = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* register_ipcrtr_af_init_notifier() - Register for ipc router socket
|
||||
* address family initialization callback
|
||||
* @nb: Notifier block which will be notified when address family is
|
||||
* initialized.
|
||||
*
|
||||
* Return: 0 on success, standard error code otherwise.
|
||||
*/
|
||||
int register_ipcrtr_af_init_notifier(struct notifier_block *nb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!nb)
|
||||
return -EINVAL;
|
||||
mutex_lock(&ipcrtr_af_init_lock);
|
||||
if (sockets_enabled)
|
||||
nb->notifier_call(nb, IPCRTR_AF_INIT, NULL);
|
||||
ret = raw_notifier_chain_register(&ipcrtr_af_init_chain, nb);
|
||||
mutex_unlock(&ipcrtr_af_init_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(register_ipcrtr_af_init_notifier);
|
||||
|
||||
/**
|
||||
* unregister_ipcrtr_af_init_notifier() - Unregister for ipc router socket
|
||||
* address family initialization callback
|
||||
* @nb: Notifier block which will be notified once address family is
|
||||
* initialized.
|
||||
*
|
||||
* Return: 0 on success, standard error code otherwise.
|
||||
*/
|
||||
int unregister_ipcrtr_af_init_notifier(struct notifier_block *nb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!nb)
|
||||
return -EINVAL;
|
||||
ret = raw_notifier_chain_unregister(&ipcrtr_af_init_chain, nb);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_ipcrtr_af_init_notifier);
|
||||
|
||||
static const struct net_proto_family msm_ipc_family_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.family = AF_MSM_IPC,
|
||||
.create = msm_ipc_router_create
|
||||
};
|
||||
|
||||
static const struct proto_ops msm_ipc_proto_ops = {
|
||||
.family = AF_MSM_IPC,
|
||||
.owner = THIS_MODULE,
|
||||
.release = msm_ipc_router_close,
|
||||
.bind = msm_ipc_router_bind,
|
||||
.connect = ipc_router_connect,
|
||||
.socketpair = sock_no_socketpair,
|
||||
.accept = sock_no_accept,
|
||||
.getname = sock_no_getname,
|
||||
.poll = msm_ipc_router_poll,
|
||||
.ioctl = msm_ipc_router_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = msm_ipc_router_ioctl,
|
||||
#endif
|
||||
.listen = sock_no_listen,
|
||||
.shutdown = sock_no_shutdown,
|
||||
.setsockopt = sock_no_setsockopt,
|
||||
.getsockopt = sock_no_getsockopt,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_setsockopt = sock_no_setsockopt,
|
||||
.compat_getsockopt = sock_no_getsockopt,
|
||||
#endif
|
||||
.sendmsg = msm_ipc_router_sendmsg,
|
||||
.recvmsg = msm_ipc_router_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
.sendpage = sock_no_sendpage,
|
||||
};
|
||||
|
||||
static struct proto msm_ipc_proto = {
|
||||
.name = "MSM_IPC",
|
||||
.owner = THIS_MODULE,
|
||||
.obj_size = sizeof(struct msm_ipc_sock),
|
||||
};
|
||||
|
||||
int msm_ipc_router_init_sockets(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = proto_register(&msm_ipc_proto, 1);
|
||||
if (ret) {
|
||||
IPC_RTR_ERR("%s: Failed to register MSM_IPC protocol type\n",
|
||||
__func__);
|
||||
goto out_init_sockets;
|
||||
}
|
||||
|
||||
ret = sock_register(&msm_ipc_family_ops);
|
||||
if (ret) {
|
||||
IPC_RTR_ERR("%s: Failed to register MSM_IPC socket type\n",
|
||||
__func__);
|
||||
proto_unregister(&msm_ipc_proto);
|
||||
goto out_init_sockets;
|
||||
}
|
||||
|
||||
mutex_lock(&ipcrtr_af_init_lock);
|
||||
sockets_enabled = 1;
|
||||
raw_notifier_call_chain(&ipcrtr_af_init_chain,
|
||||
IPCRTR_AF_INIT, NULL);
|
||||
mutex_unlock(&ipcrtr_af_init_lock);
|
||||
out_init_sockets:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void msm_ipc_router_exit_sockets(void)
|
||||
{
|
||||
if (!sockets_enabled)
|
||||
return;
|
||||
|
||||
sock_unregister(msm_ipc_family_ops.family);
|
||||
proto_unregister(&msm_ipc_proto);
|
||||
mutex_lock(&ipcrtr_af_init_lock);
|
||||
sockets_enabled = 0;
|
||||
raw_notifier_call_chain(&ipcrtr_af_init_chain,
|
||||
IPCRTR_AF_DEINIT, NULL);
|
||||
mutex_unlock(&ipcrtr_af_init_lock);
|
||||
}
|
||||
Loading…
Reference in a new issue