1231 lines
42 KiB
HTML
1231 lines
42 KiB
HTML
<html devsite>
|
|
<head>
|
|
<title>Trusty API Reference</title>
|
|
<meta name="project_path" value="/_project.yaml" />
|
|
<meta name="book_path" value="/_book.yaml" />
|
|
</head>
|
|
<body>
|
|
<!--
|
|
Copyright 2017 The Android Open Source Project
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
-->
|
|
|
|
|
|
|
|
<p>The <a href="index.html">Trusty</a> API generally describes the
|
|
Trusty inter-process communication (IPC)
|
|
system, including communications with the non-secure world. This page defines the
|
|
relevant terms and provides a reference for the API
|
|
calls.</p>
|
|
|
|
<h2 id=ports_and_channels>Ports and channels</h2>
|
|
|
|
<p>Ports are used by Trusty applications to expose service end-points in the form
|
|
of a named path to which clients connect. This gives a simple, string-based
|
|
service ID for clients to use. The naming convention is reverse-DNS-style
|
|
naming, e.g. <code>com.google.servicename</code>.</p>
|
|
|
|
<p>When a client connects to a port, the client receives a channel for interacting
|
|
with a service. The service must accept an incoming connection, and when it
|
|
does, it too receives a channel. In essence, ports are used to look up services
|
|
and then communication occurs over a pair of connected channels (i.e.,
|
|
connection instances on a port). When a client connects to a port, a symmetric,
|
|
bi-directional connection is established. Using this full-duplex path, clients
|
|
and servers can exchange arbitrary messages until either side decides to tear
|
|
down the connection.</p>
|
|
|
|
<p>Only secure-side trusted applications or Trusty kernel modules can create
|
|
ports. Applications running on the non-secure side (in the normal world) can
|
|
only connect to services published by the secure side.</p>
|
|
|
|
<p>Depending on requirements, a trusted application can be both a client and a
|
|
server at the same time. A trusted application that publishes a service (as a
|
|
server) might need to connect to other services (as a client).</p>
|
|
|
|
<h2 id=handle_api>Handle API</h2>
|
|
|
|
<p>Handles are unsigned integers representing resources such as ports and
|
|
channels, similar to file descriptors in UNIX. After handles are created, they
|
|
are placed into an application-specific handle table and can be referenced
|
|
later.</p>
|
|
|
|
<p>A caller can associate private data with a handle by using
|
|
the <code>set_cookie()</code> method.</p>
|
|
|
|
<h3 id=methods_handle_api>Methods in the Handle API</h3>
|
|
|
|
<p>Handles are only valid in the context of an application. An application should
|
|
not pass the value of a handle to other applications unless explicitly
|
|
specified. A handle value only should be interpreted by comparing it with
|
|
the <code>INVALID_IPC_HANDLE #define,</code> which an application can use as an
|
|
indication that a handle is invalid or unset.</p>
|
|
|
|
<h4 id=set_cookie>set_cookie()</h4>
|
|
|
|
<p>Associates the caller-provided private data with a specified handle.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long set_cookie(uint32_t handle, void *cookie)
|
|
</pre>
|
|
|
|
<p>[in] <code>handle</code>: Any handle returned by one of the API calls</p>
|
|
|
|
<p>[in] <code>cookie</code>: Pointer to arbitrary user-space data in the Trusty application</p>
|
|
|
|
<p>[retval]: <code>NO_ERROR</code> on success, <code>< 0</code> error code otherwise</p>
|
|
|
|
<p>This call is useful for handling events when they occur at a later time after
|
|
the handle has been created. The event-handling mechanism supplies the handle
|
|
and its cookie back to the event handler.</p>
|
|
|
|
<p>Handles can be waited upon for events by using the <code>wait()</code>
|
|
or <code>wait_any()</code> calls.</p>
|
|
|
|
<h4 id=wait>wait()</h4>
|
|
|
|
<p>Waits for an event to occur on a given handle for specified period of time.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long wait(uint32_t handle_id, uevent_t *event, unsigned long timeout_msecs)
|
|
</pre>
|
|
|
|
<p>[in] <code>handle_id</code>: Any handle returned by one of the API calls</p>
|
|
|
|
<p>[out] <code>event</code>: A pointer to the structure representing
|
|
an event that occurred on this handle</p>
|
|
|
|
<p>[in] <code>timeout_msecs</code>: A timeout value in milliseconds; a
|
|
value of -1 is an infinite timeout</p>
|
|
|
|
<p>[retval]: <code>NO_ERROR</code> if a valid event occurred within a
|
|
specified timeout interval; <code>ERR_TIMED_OUT</code> if a specified timeout elapsed but no
|
|
event has occurred; <code>< 0</code> for other errors</p>
|
|
|
|
<h4 id=wait_any>wait_any()</h4>
|
|
|
|
<p>Waits for any event to occur on any handle in the application handle table for
|
|
the specified period of time.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long wait_any(uevent_t *event, unsigned long timeout_msecs);
|
|
</pre>
|
|
|
|
<p>[out] <code>event</code>: A pointer to the structure representing an
|
|
event that occurred on this handle</p>
|
|
|
|
<p>[in] <code>timeout_msecs</code>: A timeout value in milliseconds.
|
|
A value of -1 is an infinite timeout</p>
|
|
|
|
<p>[retval]: <code>NO_ERROR</code> if a valid event occurred within a
|
|
specified timeout interval; <code>ERR_TIMED_OUT</code> if a specified timeout elapsed but no
|
|
event has occurred; <code>< 0</code> for other errors</p>
|
|
|
|
<p>Upon success (<code>retval == NO_ERROR</code>), the <code>wait()</code>
|
|
and <code>wait_any()</code> calls
|
|
fill a specified <code>uevent_t</code> structure with information about
|
|
the event that occurred.</p>
|
|
|
|
<pre class="prettyprint">
|
|
typedef struct uevent {
|
|
uint32_t handle; /* handle this event is related to */
|
|
uint32_t event; /* combination of IPC_HANDLE_POLL_XXX flags */
|
|
void *cookie; /* cookie associated with this handle */
|
|
} uevent_t;
|
|
</pre>
|
|
|
|
<p>The <code>event</code> field contains a combination of the following values:</p>
|
|
|
|
<pre class="prettyprint">
|
|
enum {
|
|
IPC_HANDLE_POLL_NONE = 0x0,
|
|
IPC_HANDLE_POLL_READY = 0x1,
|
|
IPC_HANDLE_POLL_ERROR = 0x2,
|
|
IPC_HANDLE_POLL_HUP = 0x4,
|
|
IPC_HANDLE_POLL_MSG = 0x8,
|
|
IPC_HANDLE_POLL_SEND_UNBLOCKED = 0x10,
|
|
… more values[TBD]
|
|
};
|
|
</pre>
|
|
|
|
<p><code>IPC_HANDLE_POLL_NONE</code> - no events are actually pending,
|
|
caller should restart the wait</p>
|
|
|
|
<p><code>IPC_HANDLE_POLL_ERROR</code> - an unspecified internal error has occurred</p>
|
|
|
|
<p><code>IPC_HANDLE_POLL_READY</code> - depends on the handle type, as follows:</p>
|
|
|
|
<ul>
|
|
<li>For ports, this value indicates that there is a pending connection
|
|
<li>For channels, this value indicates that an asynchronous connection
|
|
(see <code>connect()</code>) was established
|
|
</ul>
|
|
|
|
<p>The following events are only relevant for channels:</p>
|
|
|
|
<ul>
|
|
<li><code>IPC_HANDLE_POLL_HUP</code> - indicates that a channel has been closed by a peer
|
|
<li><code>IPC_HANDLE_POLL_MSG</code> - indicates that there is a pending message for this channel
|
|
<li><code>IPC_HANDLE_POLL_SEND_UNBLOCKED</code> - indicates that a previously
|
|
send-blocked caller may attempt to send a
|
|
message again (see the description of <code>send_msg()</code> for details)
|
|
</ul>
|
|
|
|
<p>An event handler should be prepared to handle a combination of specified
|
|
events, as multiple bits might be set at the same time. For example, for a
|
|
channel, it is possible to have pending messages, and a connection closed by a
|
|
peer at the same time.</p>
|
|
|
|
<p>Most events are sticky. They persist as long as the underlying condition
|
|
persists (for example all pending messages are received and pending connection
|
|
requests are handled). The exception is the case of
|
|
the <code>IPC_HANDLE_POLL_SEND_UNBLOCKED</code> event, which
|
|
is cleared upon a read and the application has only one chance to
|
|
handle it.</p>
|
|
|
|
<p>Handles can be destroyed by calling the <code>close()</code> method.</p>
|
|
|
|
<h4 id=close>close()</h4>
|
|
|
|
<p>Destroys the resource associated with the specified handle and removes it from
|
|
the handle table.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long close(uint32_t handle_id);
|
|
</pre>
|
|
|
|
<p>[in] <code>handle_id</code>: Handle to destroy</p>
|
|
|
|
<p>[retval]: 0 if success; a negative error otherwise</p>
|
|
|
|
<h2 id=server_api>Server API</h2>
|
|
|
|
<p>A server begins by creating one or more <strong>named ports</strong> representing
|
|
its service end-points. Each port is represented by a handle.</p>
|
|
|
|
<h3 id=methods_server_api>Methods in the Server API</h3>
|
|
|
|
<h4 id=port_create>port_create()</h4>
|
|
|
|
<p>Creates a named service port.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long port_create (const char *path, uint num_recv_bufs, size_t recv_buf_size,
|
|
uint32_t flags)
|
|
</pre>
|
|
|
|
<p>[in] <code>path</code>: The string name of the port (as described above). This
|
|
name should be unique across the system; attempts to create a duplicate will fail.</p>
|
|
|
|
<p>[in] <code>num_recv_bufs</code>: The maximum number of buffers that a channel on
|
|
this port can pre-allocate to facilitate the exchange of data with the client. Buffers are counted
|
|
separately for data going in both directions, so specifying 1 here would mean 1
|
|
send and 1 receive buffer are preallocated. In general, the number of buffers
|
|
required depends on the higher-level protocol agreement between the client and
|
|
server. The number can be as little as 1 in case of a very synchronous protocol
|
|
(send message, receive reply before sending another). But the number can be
|
|
more if the client expects to send more than one message before a reply can
|
|
appear (e.g, one message as a prologue and another as the actual command). The
|
|
allocated buffer sets are per channel, so two separate connections (channels)
|
|
would have separate buffer sets.</p>
|
|
|
|
<p>[in] <code>recv_buf_size</code>: Maximum size of each individual buffer in the
|
|
above buffer set. This value is
|
|
protocol-dependent and effectively limits maximum message size you can exchange
|
|
with peer</p>
|
|
|
|
<p>[in] <code>flags</code>: A combination of flags that specifies additional port behavior</p>
|
|
|
|
<p>This value should be a combination of the following values:</p>
|
|
|
|
<p><code>IPC_PORT_ALLOW_TA_CONNECT</code> - allows a connection from other secure apps</p>
|
|
|
|
<p><code>IPC_PORT_ALLOW_NS_CONNECT</code> - allows a connection from the non-secure world</p>
|
|
|
|
<p>[retval]: Handle to the port created if non-negative or a specific error if
|
|
negative</p>
|
|
|
|
<p>The server then polls the list of port handles for incoming connections
|
|
using <code>wait()</code> or <code>wait_any()</code> calls. Upon receiving a connection
|
|
request indicated by the <code>IPC_HANDLE_POLL_READY</code> bit set in
|
|
the <code>event</code> field of the <code>uevent_t</code> structure, the
|
|
server should call <code>accept()</code> to finish establishing a connection and create a
|
|
channel (represented by
|
|
another handle) that can then be polled for incoming messages.</p>
|
|
|
|
<h4 id=accept>accept()</h4>
|
|
|
|
<p>Accepts an incoming connection and gets a handle to a channel.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long accept(uint32_t handle_id, uuid_t *peer_uuid);
|
|
</pre>
|
|
|
|
<p>[in] <code>handle_id</code>: Handle representing the port to which a client has connected</p>
|
|
|
|
<p>[out] <code>peer_uuid</code>: Pointer to a <code>uuud_t</code> structure to be
|
|
filled with the UUID of the connecting client application. It
|
|
will be set to all zeros if the connection originated from the non-secure world</p>
|
|
|
|
<p>[retval]: Handle to a channel (if non-negative) on which the server can
|
|
exchange messages with the client (or an error code otherwise)</p>
|
|
|
|
<h2 id=client_api>Client API</h2>
|
|
|
|
<p>This section contains the methods in the Client API.</p>
|
|
|
|
<h3 id=methods_client_api>Methods in the Client API</h3>
|
|
|
|
<h4 id=connect>connect()</h4>
|
|
|
|
<p>Initiates a connection to a port specified by name.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long connect(const char *path, uint flags);
|
|
</pre>
|
|
|
|
<p>[in] <code>path</code>: Name of a port published by a Trusty application</p>
|
|
|
|
<p>[in] <code>flags</code>: Specifies additional, optional behavior</p>
|
|
|
|
<p>[retval]: Handle to a channel over which messages can be exchanged with the
|
|
server; error if negative</p>
|
|
|
|
<p>If no <code>flags</code> are specified (the <code>flags</code> parameter
|
|
is set to 0), calling <code>connect()</code> initiates a synchronous connection
|
|
to a specified port that immediately
|
|
returns an error if the port does not exist, and creates a block until the
|
|
server otherwise accepts a connection.</p>
|
|
|
|
<p>This behavior can be altered by specifying a combination of two values,
|
|
described below:</p>
|
|
|
|
<pre class="prettyprint">
|
|
enum {
|
|
IPC_CONNECT_WAIT_FOR_PORT = 0x1,
|
|
IPC_CONNECT_ASYNC = 0x2,
|
|
};
|
|
</pre>
|
|
|
|
<p><code>IPC_CONNECT_WAIT_FOR_PORT</code> - forces a <code>connect()</code>
|
|
call to wait if the specified port does not immediately exist at execution,
|
|
instead of failing immediately.</p>
|
|
|
|
<p><code>IPC_CONNECT_ASYNC</code> - if set, initiates an asynchronous connection. An
|
|
application has to poll for
|
|
the returned handle (by calling <code>wait()</code> or <code>wait_any()</code>) for
|
|
a connection completion event indicated by the <code>IPC_HANDLE_POLL_READY</code>
|
|
bit set in the event field of the <code>uevent_t</code> structure before starting
|
|
normal operation.</p>
|
|
|
|
<h2 id=messaging_api>Messaging API</h2>
|
|
|
|
<p>The Messaging API calls enable the sending and reading of messages over a
|
|
previously established connection (channel). The Messaging API calls are the
|
|
same for servers and clients.</p>
|
|
|
|
<p>A client receives a handle to a channel by issuing a <code>connect()</code>
|
|
call, and a server gets a channel handle from an <code>accept()</code> call,
|
|
described above.</p>
|
|
|
|
<h4 id=structure_of_a_trusty_message>Structure of a Trusty message</h4>
|
|
|
|
<p>As shown in the following, messages exchanged by the Trusty API have a minimal
|
|
structure, leaving it to the server and client to agree on the semantics of the
|
|
actual contents:</p>
|
|
|
|
<pre class="prettyprint">
|
|
/*
|
|
* IPC message
|
|
*/
|
|
typedef struct iovec {
|
|
void *base;
|
|
size_t len;
|
|
} iovec_t;
|
|
|
|
typedef struct ipc_msg {
|
|
uint num_iov; /* number of iovs in this message */
|
|
iovec_t *iov; /* pointer to iov array */
|
|
|
|
uint num_handles; /* reserved, currently not supported */
|
|
handle_t *handles; /* reserved, currently not supported */
|
|
} ipc_msg_t;
|
|
</pre>
|
|
|
|
<p>A message can be composed of one or more non-contiguous buffers represented by
|
|
an array of <code>iovec_t</code> structures. Trusty performs scatter-gather
|
|
reads and writes to these blocks
|
|
using the <code>iov</code> array. The content of buffers that can be described
|
|
by the <code>iov</code> array is completely arbitrary.</p>
|
|
|
|
<h3 id=methods_messaging_api>Methods in the Messaging API</h3>
|
|
|
|
<h4 id=send_msg>send_msg()</h4>
|
|
|
|
<p>Sends a message over a specified channel.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long send_msg(uint32_t handle, ipc_msg_t *msg);
|
|
</pre>
|
|
|
|
<p>[in] <code>handle</code>: Handle to the channel over which to send the message</p>
|
|
|
|
<p>[in] <code>msg</code>: Pointer to the <code>ipc_msg_t structure</code> describing the message</p>
|
|
|
|
<p>[retval]: Total number of bytes sent on success; a negative error otherwise</p>
|
|
|
|
<p>If the client (or server) is trying to send a message over the channel and
|
|
there is no space in the destination peer message queue, the channel might
|
|
enter a send-blocked state (this should never happen for a simple synchronous
|
|
request/reply protocol but might happen in more complicated cases) that is
|
|
indicated by returning an <code>ERR_NOT_ENOUGH_BUFFER</code> error code.
|
|
In such a case the caller must wait until the peer frees some
|
|
space in its receive queue by retrieving the handling and retiring messages,
|
|
indicated by the <code>IPC_HANDLE_POLL_SEND_UNBLOCKED</code> bit set in
|
|
the <code>event</code> field of the <code>uevent_t</code> structure
|
|
returned by the <code>wait()</code> or <code>wait_any()</code> call.</p>
|
|
|
|
<h4 id=get_msg>get_msg()</h4>
|
|
|
|
<p>Gets meta-information about the next message in an incoming message queue</p>
|
|
|
|
<p>of a specified channel.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long get_msg(uint32_t handle, ipc_msg_info_t *msg_info);
|
|
</pre>
|
|
|
|
<p>[in] <code>handle</code>: Handle of the channel on which a new message must be retrieved</p>
|
|
|
|
<p>[out] <code>msg_info</code>: Message information structure described as follows:</p>
|
|
|
|
<pre class="prettyprint">
|
|
typedef struct ipc_msg_info {
|
|
size_t len; /* total message length */
|
|
uint32_t id; /* message id */
|
|
} ipc_msg_info_t;
|
|
</pre>
|
|
|
|
<p>Each message is assigned a unique ID across the set of outstanding messages,
|
|
and the total length of each message is filled in. If configured and allowed by the
|
|
protocol, there can be multiple outstanding (opened) messages at once for a
|
|
particular channel.</p>
|
|
|
|
<p>[retval]: <code>NO_ERROR</code> on success; a negative error otherwise</p>
|
|
|
|
<h4 id=read_msg>read_msg()</h4>
|
|
|
|
<p>Reads the content of the message with the specified ID starting from the
|
|
specified offset.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long read_msg(uint32_t handle, uint32_t msg_id, uint32_t offset, ipc_msg_t
|
|
*msg);
|
|
</pre>
|
|
|
|
<p>[in] <code>handle</code>: Handle of the channel from which to read the message</p>
|
|
|
|
<p>[in] <code>msg_id</code>: ID of the message to read</p>
|
|
|
|
<p>[in] <code>offset</code>: Offset into the message from which to start reading</p>
|
|
|
|
<p>[in] <code>msg</code>: Pointer to the <code>ipc_msg_t</code> structure describing
|
|
a set of buffers into which to store incoming message
|
|
data</p>
|
|
|
|
<p>[retval]: Total number of bytes stored in the <code>dst</code> buffers on
|
|
success; a negative error otherwise</p>
|
|
|
|
<p>The <code>read_msg</code> method can be called multiple times starting at
|
|
a different (not necessarily
|
|
sequential) offset as needed.</p>
|
|
|
|
<h4 id=put_msg>put_msg()</h4>
|
|
|
|
<p>Retires a message with a specified ID.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long put_msg(uint32_t handle, uint32_t msg_id);
|
|
</pre>
|
|
|
|
<p>[in] <code>handle</code>: Handle of the channel on which the message has arrived</p>
|
|
|
|
<p>[in] <code>msg_id</code>: ID of message being retired</p>
|
|
|
|
<p>[retval]: <code>NO_ERROR</code> on success; a negative error otherwise</p>
|
|
|
|
<p>Message content cannot be accessed after a message has been retired and the
|
|
buffer it occupied has been freed.</p>
|
|
|
|
<h2 id=file_descriptor_api>File Descriptor API</h2>
|
|
|
|
<p>The File Descriptor API includes <code>read()</code>, <code>write()</code>,
|
|
and <code>ioctl()</code> calls. All of these calls can operate on a predefined (static) set of file
|
|
descriptors traditionally represented by small numbers. In the current
|
|
implementation, the file descriptor space is separate from the IPC handle
|
|
space. The File Descriptor API in Trusty is
|
|
similar to a traditional file descriptor-based API.</p>
|
|
|
|
<p>By default, there are 3 predefined (standard and well-known) file descriptors:</p>
|
|
|
|
<ul>
|
|
<li>0 - standard input. The default implementation of standard input <code>fd</code>
|
|
is a no-op (as trusted applications are not expected to have an interactive
|
|
console) so reading, writing or invoking <code>ioctl()</code> on <code>fd</code> 0
|
|
should return an <code>ERR_NOT_SUPPORTED</code> error.
|
|
<li>1 - standard output. Data written to standard output can be routed (depending
|
|
on the LK debug level) to UART and/or a memory log available on the non-secure
|
|
side, depending on the platform and configuration. Non-critical debug logs and
|
|
messages should go in standard output. The <code>read()</code> and <code>ioctl()</code>
|
|
methods are no-ops and should return an <code>ERR_NOT_SUPPORTED</code> error.
|
|
<li>2 - standard error. Data written to standard error should be routed to the UART
|
|
or memory log available on the non-secure side, depending on the platform and
|
|
configuration. It is recommended to write only critical messages to standard
|
|
error, as this stream is very likely to be unthrottled. The <code>read()</code> and
|
|
<code>ioctl()</code> methods are no-ops and should return an <code>ERR_NOT_SUPPORTED</code> error.
|
|
</ul>
|
|
|
|
<p>Even though this set of file descriptors can be extended to implement more
|
|
<code>fds</code> (to implement platform-specific extensions), extending file descriptors needs
|
|
to be exercised with caution. Extending file descriptors is prone to create
|
|
conflicts and is not generally recommended.</p>
|
|
|
|
<h3 id=methods_file_descriptor_api>Methods in the File Descriptor API</h3>
|
|
|
|
<h4 id=read>read()</h4>
|
|
|
|
<p>Attempts to read up to <code>count</code> bytes of data from a specified file descriptor.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long read(uint32_t fd, void *buf, uint32_t count);
|
|
</pre>
|
|
|
|
<p>[in] <code>fd</code>: File descriptor from which to read</p>
|
|
|
|
<p>[out] <code>buf</code>: Pointer to a buffer into which to store data</p>
|
|
|
|
<p>[in] <code>count</code>: Maximum number of bytes to read</p>
|
|
|
|
<p>[retval]: Returned number of bytes read; a negative error otherwise</p>
|
|
|
|
<h4 id=write>write()</h4>
|
|
|
|
<p>Writes up to <code>count</code> bytes of data to specified file descriptor.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long write(uint32_t fd, void *buf, uint32_t count);
|
|
</pre>
|
|
|
|
<p>[in] <code>fd</code>: File descriptor to which to write</p>
|
|
|
|
<p>[out] <code>buf</code>: Pointer to data to write</p>
|
|
|
|
<p>[in] <code>count</code>: Maximum number of bytes to write</p>
|
|
|
|
<p>[retval]: Returned number of bytes written; a negative error otherwise</p>
|
|
|
|
<h4 id=ioctl>ioctl()</h4>
|
|
|
|
<p>Invokes a specified <code>ioctl</code> command for a given file descriptor.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long ioctl(uint32_t fd, uint32_t cmd, void *args);
|
|
</pre>
|
|
|
|
<p>[in] <code>fd</code>: File descriptor on which to invoke <code>ioctl()</code></p>
|
|
|
|
<p>[in] <code>cmd</code>: The <code>ioctl</code> command</p>
|
|
|
|
<p>[in/out] <code>args</code>: Pointer to <code>ioctl()</code> arguments</p>
|
|
|
|
<h2 id=miscellaneous_api>Miscellaneous API</h2>
|
|
|
|
<h3 id=methods_misc_api>Methods in the Miscellaneous API</h3>
|
|
|
|
<h4 id=gettime>gettime()</h4>
|
|
|
|
<p>Returns the current system time (in nanoseconds).</p>
|
|
|
|
<pre class="prettyprint">
|
|
long gettime(uint32_t clock_id, uint32_t flags, uint64_t *time);
|
|
</pre>
|
|
|
|
<p>[in] <code>clock_id</code>: Platform-dependent; pass zero for default</p>
|
|
|
|
<p>[in] <code>flags</code>: Reserved, should be zero</p>
|
|
|
|
<p>[in] <code>time</code>: Pointer to an <code>int64_t</code> value to which to store the current time</p>
|
|
|
|
<p>[retval]: <code>NO_ERROR</code> on success; a negative error otherwise</p>
|
|
|
|
<h4 id=nanosleep>nanosleep()</h4>
|
|
|
|
<p>Suspends execution of the calling application for a specified period of time
|
|
and resumes it after that period.</p>
|
|
|
|
<pre class="prettyprint">
|
|
long nanosleep(uint32_t clock_id, uint32_t flags, uint64_t sleep_time)
|
|
</pre>
|
|
|
|
<p>[in] <code>clock_id</code>: Reserved, should be zero</p>
|
|
|
|
<p>[in] <code>flags</code>: Reserved, should be zero</p>
|
|
|
|
<p>[in] <code>sleep_time</code>: Sleep time in nanoseconds</p>
|
|
|
|
<p>[retval]: <code>NO_ERROR</code> on success; a negative error otherwise</p>
|
|
|
|
<h2 id=example_of_a_trusted_application_server>Example of a trusted application server</h2>
|
|
|
|
<p>The following sample application shows the usage of the above APIs. The sample
|
|
creates an "echo" service that handles multiple incoming connections and
|
|
reflects back to the caller all messages it receives from clients originated
|
|
from the secure or non-secure side.</p>
|
|
|
|
<pre class="prettyprint">
|
|
#include <assert.h>
|
|
#include <err.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <trusty_std.h>
|
|
|
|
#include <app/echo/uuids.h>
|
|
|
|
#define LOG_TAG "echo_srv"
|
|
|
|
#define TLOGE(fmt, ...) \
|
|
fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ## __VA_ARGS__)
|
|
|
|
#define MAX_ECHO_MSG_SIZE 64
|
|
|
|
static const char *srv_name = "com.android.echo.srv.echo";
|
|
|
|
static uint8_t msg_buf[MAX_ECHO_MSG_SIZE];
|
|
|
|
/*
|
|
* Message handler
|
|
*/
|
|
static int handle_msg(handle_t chan)
|
|
{
|
|
int rc;
|
|
iovec_t iov;
|
|
ipc_msg_t msg;
|
|
ipc_msg_info_t msg_inf;
|
|
|
|
iov.base = msg_buf;
|
|
iov.len = sizeof(msg_buf);
|
|
|
|
msg.num_iov = 1;
|
|
msg.iov = &iov;
|
|
msg.num_handles = 0;
|
|
msg.handles = NULL;
|
|
|
|
/* get message info */
|
|
rc = get_msg(chan, &msg_inf);
|
|
if (rc == ERR_NO_MSG)
|
|
return NO_ERROR; /* no new messages */
|
|
|
|
if (rc != NO_ERROR) {
|
|
TLOGE("failed (%d) to get_msg for chan (%d)\n",
|
|
rc, chan);
|
|
return rc;
|
|
}
|
|
|
|
/* read msg content */
|
|
rc = read_msg(chan, msg_inf.id, 0, &msg);
|
|
if (rc < 0) {
|
|
TLOGE("failed (%d) to read_msg for chan (%d)\n",
|
|
rc, chan);
|
|
return rc;
|
|
}
|
|
|
|
/* update number of bytes received */
|
|
iov.len = (size_t) rc;
|
|
|
|
/* send message back to the caller */
|
|
rc = send_msg(chan, &msg);
|
|
if (rc < 0) {
|
|
TLOGE("failed (%d) to send_msg for chan (%d)\n",
|
|
rc, chan);
|
|
return rc;
|
|
}
|
|
|
|
/* retire message */
|
|
rc = put_msg(chan, msg_inf.id);
|
|
if ( rc != NO_ERROR) {
|
|
TLOGE("failed (%d) to put_msg for chan (%d)\n",
|
|
rc, chan);
|
|
return rc;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Channel event handler
|
|
*/
|
|
static void handle_channel_event(const uevent_t *ev)
|
|
{
|
|
int rc;
|
|
|
|
if (ev->event & IPC_HANDLE_POLL_MSG) {
|
|
rc = handle_msg(ev->handle);
|
|
if (rc != NO_ERROR) {
|
|
/* report an error and close channel */
|
|
TLOGE("failed (%d) to handle event on channel %d\n",
|
|
rc, ev->handle);
|
|
close(ev->handle);
|
|
}
|
|
return;
|
|
}
|
|
if (ev->event & IPC_HANDLE_POLL_HUP) {
|
|
/* closed by peer. */
|
|
close(ev->handle);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Port event handler
|
|
*/
|
|
static void handle_port_event(const uevent_t *ev)
|
|
{
|
|
uuid_t peer_uuid;
|
|
|
|
if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
|
|
(ev->event & IPC_HANDLE_POLL_HUP) ||
|
|
(ev->event & IPC_HANDLE_POLL_MSG) ||
|
|
(ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
|
|
/* should never happen with port handles */
|
|
TLOGE("error event (0x%x) for port (%d)\n",
|
|
ev->event, ev->handle);
|
|
abort();
|
|
}
|
|
if (ev->event & IPC_HANDLE_POLL_READY) {
|
|
/* incoming connection: accept it */
|
|
int rc = accept(ev->handle, &peer_uuid);
|
|
if (rc < 0) {
|
|
TLOGE("failed (%d) to accept on port %d\n",
|
|
rc, ev->handle);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Main application entry point
|
|
*/
|
|
int main(void)
|
|
{
|
|
int rc;
|
|
handle_t port;
|
|
|
|
/* Initialize service */
|
|
rc = port_create(srv_name, 1, MAX_ECHO_MSG_SIZE,
|
|
IPC_PORT_ALLOW_NS_CONNECT |
|
|
IPC_PORT_ALLOW_TA_CONNECT );
|
|
if (rc < 0) {
|
|
TLOGE("Failed (%d) to create port %s\n",
|
|
rc, srv_name);
|
|
abort();
|
|
}
|
|
port = (handle_t)rc;
|
|
|
|
/* enter main event loop */
|
|
while (true) {
|
|
uevent_t ev;
|
|
|
|
ev.handle = INVALID_IPC_HANDLE;
|
|
ev.event = 0;
|
|
ev.cookie = NULL;
|
|
|
|
/* wait forever */
|
|
rc = wait_any(&ev, -1);
|
|
if (rc == NO_ERROR) {
|
|
/* got an event */
|
|
if (ev.handle == port) {
|
|
handle_port_event(&ev);
|
|
} else {
|
|
handle_channel_event(&ev);
|
|
}
|
|
} else {
|
|
TLOGE("wait_any returned (%d)\n", rc);
|
|
abort();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
</pre>
|
|
|
|
<h2 id=example_of_a_trusted_application_client>Example of a trusted application client</h2>
|
|
|
|
<p>The following code snippets show the use of the Trusty messaging APIs to
|
|
implement a client of an "echo" service (shown in the code above). The <code>sync_connect()</code>
|
|
method shows an implementation of a synchronous connect with a timeout on top
|
|
of an asynchronous <code>connect()</code> call.</p>
|
|
|
|
<pre class="prettyprint">
|
|
/*
|
|
* Local wrapper on top of an async connect that provides a
|
|
* synchronous connect with timeout.
|
|
*/
|
|
int sync_connect(const char *path, uint timeout)
|
|
{
|
|
int rc;
|
|
uevent_t evt;
|
|
handle_t chan;
|
|
|
|
rc = connect(path, IPC_CONNECT_ASYNC | IPC_CONNECT_WAIT_FOR_PORT);
|
|
if (rc >= 0) {
|
|
chan = (handle_t) rc;
|
|
rc = wait(chan, &evt, timeout);
|
|
if (rc == 0) {
|
|
rc = ERR_BAD_STATE;
|
|
if (evt.handle == chan) {
|
|
if (evt.event & IPC_HANDLE_POLL_READY)
|
|
return chan;
|
|
if (evt.event & IPC_HANDLE_POLL_HUP)
|
|
rc = ERR_CHANNEL_CLOSED;
|
|
}
|
|
}
|
|
close(chan);
|
|
}
|
|
return rc;
|
|
}
|
|
</pre>
|
|
|
|
<p>The <code>run_end_to_end_msg_test()</code> method sends 10,000 messages asynchronously
|
|
to the "echo" service and handles
|
|
replies.</p>
|
|
|
|
<pre class="prettyprint">
|
|
static int run_echo_test(void)
|
|
{
|
|
int rc;
|
|
handle_t chan;
|
|
uevent_t uevt;
|
|
uint8_t tx_buf[64];
|
|
uint8_t rx_buf[64];
|
|
ipc_msg_info_t inf;
|
|
ipc_msg_t tx_msg;
|
|
iovec_t tx_iov;
|
|
ipc_msg_t rx_msg;
|
|
iovec_t rx_iov;
|
|
|
|
/* prepare tx message buffer */
|
|
tx_iov.base = tx_buf;
|
|
tx_iov.len = sizeof(tx_buf);
|
|
tx_msg.num_iov = 1;
|
|
tx_msg.iov = &tx_iov;
|
|
tx_msg.num_handles = 0;
|
|
tx_msg.handles = NULL;
|
|
|
|
memset (tx_buf, 0x55, sizeof(tx_buf));
|
|
|
|
/* prepare rx message buffer */
|
|
rx_iov.base = rx_buf;
|
|
rx_iov.len = sizeof(rx_buf);
|
|
rx_msg.num_iov = 1;
|
|
rx_msg.iov = &rx_iov;
|
|
rx_msg.num_handles = 0;
|
|
rx_msg.handles = NULL;
|
|
|
|
/* open connection to echo service */
|
|
rc = sync_connect(srv_name, 1000);
|
|
if(rc < 0)
|
|
return rc;
|
|
|
|
/* got channel */
|
|
chan = (handle_t)rc;
|
|
|
|
/* send/receive 10000 messages asynchronously. */
|
|
uint tx_cnt = 10000;
|
|
uint rx_cnt = 10000;
|
|
|
|
while (tx_cnt || rx_cnt) {
|
|
/* send messages until all buffers are full */
|
|
while (tx_cnt) {
|
|
rc = send_msg(chan, &tx_msg);
|
|
if (rc == ERR_NOT_ENOUGH_BUFFER)
|
|
break; /* no more space */
|
|
if (rc != 64) {
|
|
if (rc > 0) {
|
|
/* incomplete send */
|
|
rc = ERR_NOT_VALID;
|
|
}
|
|
goto abort_test;
|
|
}
|
|
tx_cnt--;
|
|
}
|
|
|
|
/* wait for reply msg or room */
|
|
rc = wait(chan, &uevt, 1000);
|
|
if (rc != NO_ERROR)
|
|
goto abort_test;
|
|
|
|
/* drain all messages */
|
|
while (rx_cnt) {
|
|
/* get a reply */
|
|
rc = get_msg(chan, &inf);
|
|
if (rc == ERR_NO_MSG)
|
|
break; /* no more messages */
|
|
if (rc != NO_ERROR)
|
|
goto abort_test;
|
|
|
|
/* read reply data */
|
|
rc = read_msg(chan, inf.id, 0, &rx_msg);
|
|
if (rc != 64) {
|
|
/* unexpected reply length */
|
|
rc = ERR_NOT_VALID;
|
|
goto abort_test;
|
|
}
|
|
|
|
/* discard reply */
|
|
rc = put_msg(chan, inf.id);
|
|
if (rc != NO_ERROR)
|
|
goto abort_test;
|
|
rx_cnt--;
|
|
}
|
|
}
|
|
|
|
abort_test:
|
|
close(chan);
|
|
return rc;
|
|
}
|
|
</pre>
|
|
|
|
<h2 id=non-secure_world_apis_and_applications>Non-secure world APIs and applications</h2>
|
|
|
|
<p>A set of Trusty services, published from the secure side and marked with
|
|
the <code>IPC_PORT_ALLOW_NS_CONNECT</code> attribute, are accessible to kernel
|
|
and user space programs running on the
|
|
non-secure side.</p>
|
|
|
|
<p>The execution environment on the non-secure side (kernel and user space) is
|
|
drastically different from the execution environment on the secure-side.
|
|
Therefore, rather than a single library for both environments, there are two
|
|
different sets of APIs. In the kernel, the Client API is provided by the
|
|
trusty-ipc kernel driver and registers a character device node that can be used
|
|
by user space processes to communicate with services running on the secure
|
|
side.</p>
|
|
|
|
<h3 id=user_space_trusty_ipc_client_api>User space Trusty IPC Client API</h3>
|
|
|
|
<p>The user space Trusty IPC Client API library is a thin layer on top of the
|
|
device node <code>fd</code>.</p>
|
|
|
|
<p>A user space program starts a communication session
|
|
by calling <code>tipc_connect()</code>,
|
|
initializing a connection to a specified Trusty service. Internally,
|
|
the <code>tipc_connect()</code> call opens a specified device node to
|
|
obtain a file descriptor and invokes a <code>TIPC_IOC_CONNECT ioctl()</code>
|
|
call with the <code>argp</code> parameter pointing to a string containing a
|
|
service name to which to connect.</p>
|
|
|
|
<pre class="prettyprint">
|
|
#define TIPC_IOC_MAGIC 'r'
|
|
#define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char *)
|
|
</pre>
|
|
|
|
<p>The resulting file descriptor can only be used to communicate with the service
|
|
for which it was created. The file descriptor should be closed by
|
|
calling <code>tipc_close()</code> when the connection is not required anymore.</p>
|
|
|
|
<p>The file descriptor obtained by the <code>tipc_connect()</code> call
|
|
behaves as a typical character device node; the file descriptor:</p>
|
|
|
|
<ul>
|
|
<li>Can be switched to non-blocking mode if needed
|
|
<li>Can be written to using a standard <code>write()</code>
|
|
call to send messages to the other side
|
|
<li>Can be polled (using <code>poll()</code> calls or <code>select()</code> calls)
|
|
for availability of incoming messages as a regular file descriptor
|
|
<li>Can be read to retrieve incoming messages
|
|
</ul>
|
|
|
|
<p>A caller sends a message to the Trusty service by executing a write call for
|
|
the specified <code>fd</code>. All data passed to the above <code>write()</code> call
|
|
is transformed into a message by the trusty-ipc driver. The message is
|
|
delivered to the secure side where the data is handled by the IPC subsystem in
|
|
the Trusty kernel and routed to the proper destination and delivered to an app
|
|
event loop as an <code>IPC_HANDLE_POLL_MSG</code> event on a particular channel
|
|
handle. Depending on the particular,
|
|
service-specific protocol, the Trusty service may send one or more reply
|
|
messages that are delivered back to the non-secure side and placed in the
|
|
appropriate channel file descriptor message queue to be retrieved by the user
|
|
space application <code>read()</code> call.</p>
|
|
|
|
<h4 id=tipc_connect>tipc_connect()</h4>
|
|
|
|
<p>Opens a specified <code>tipc</code> device node and initiates a
|
|
connection to a specified Trusty service.</p>
|
|
|
|
<pre class="prettyprint">
|
|
int tipc_connect(const char *dev_name, const char *srv_name);
|
|
</pre>
|
|
|
|
<p>[in] <code>dev_name</code>: Path to the Trusty IPC device node to open</p>
|
|
|
|
<p>[in] <code>srv_name</code>: Name of a published Trusty service to which to connect</p>
|
|
|
|
<p>[retval]: Valid file descriptor on success, -1 otherwise.</p>
|
|
|
|
<h4 id=tipc_close>tipc_close()</h4>
|
|
|
|
<p>Closes the connection to the Trusty service specified by a file descriptor.</p>
|
|
|
|
<pre class="prettyprint">
|
|
int tipc_close(int fd);
|
|
</pre>
|
|
|
|
<p>[in] <code>fd</code>: File descriptor previously opened by
|
|
a <code>tipc_connect()</code> call</p>
|
|
|
|
<h2 id=kernel_trusty_ipc_client_api>Kernel Trusty IPC Client API</h2>
|
|
|
|
<p>The kernel Trusty IPC Client API is available for kernel drivers. The user
|
|
space Trusty IPC API is implemented on top of this API.</p>
|
|
|
|
<p>In general, typical usage of this API consists of a caller creating
|
|
a <code>struct tipc_chan</code> object by using the <code>tipc_create_channel()</code>
|
|
function and then using the <code>tipc_chan_connect()</code> call to initiate a
|
|
connection to the Trusty IPC service running on the secure
|
|
side. The connection to the remote side can be terminated by
|
|
calling <code>tipc_chan_shutdown()</code> followed by
|
|
<code>tipc_chan_destroy()</code> to clean up resources.</p>
|
|
|
|
<p>Upon receiving a notification (through the <code>handle_event()</code> callback)
|
|
that a connection has been successfully established, a caller does
|
|
the following:</p>
|
|
|
|
<ul>
|
|
<li>Obtains a message buffer using the <code>tipc_chan_get_txbuf_timeout()</code> call
|
|
<li>Composes a message, and
|
|
<li>Queues the message using the <code>tipc_chan_queue_msg()</code>
|
|
method for delivery to a Trusty service (on the secure side), to which the
|
|
channel is connected
|
|
</ul>
|
|
|
|
<p>After queueing is successful, the caller should forget the message buffer
|
|
because the message buffer eventually returns to the free buffer pool after
|
|
processing by the remote side (for reuse later, for other messages). The user
|
|
only needs to call <code>tipc_chan_put_txbuf()</code> if it fails to
|
|
queue such buffer or it is not required anymore.</p>
|
|
|
|
<p>An API user receives messages from the remote side by handling a
|
|
<code>handle_msg()</code> notification callback (which is called in
|
|
the context of the trusty-ipc <code>rx</code> workqueue) that
|
|
provides a pointer to an <code>rx</code> buffer containing an
|
|
incoming message to be handled.</p>
|
|
|
|
<p>It is expected that the <code>handle_msg()</code> callback
|
|
implementation will return a pointer to a valid <code>struct tipc_msg_buf</code>.
|
|
It can be the same as the incoming message buffer if it is handled locally
|
|
and not required anymore. Alternatively, it can be a new buffer obtained by
|
|
a <code>tipc_chan_get_rxbuf()</code> call if the incoming buffer is queued
|
|
for further processing. A detached <code>rx</code> buffer must be tracked
|
|
and eventually released using a <code>tipc_chan_put_rxbuf()</code> call when
|
|
it is no longer needed.</p>
|
|
|
|
<h3 id=methods_ktic_api>Methods in the Kernel Trusty IPC Client API</h3>
|
|
|
|
<h4 id=tipc_create_channel>tipc_create_channel()</h4>
|
|
|
|
<p>Creates and configures an instance of a Trusty IPC channel for a particular
|
|
trusty-ipc device.</p>
|
|
|
|
<pre class="prettyprint">
|
|
struct tipc_chan *tipc_create_channel(struct device *dev,
|
|
const struct tipc_chan_ops *ops,
|
|
void *cb_arg);
|
|
</pre>
|
|
|
|
<p>[in] <code>dev</code>: Pointer to the trusty-ipc for which the device
|
|
channel is created</p>
|
|
|
|
<p>[in] <code>ops</code>: Pointer to a <code>struct tipc_chan_ops</code>,
|
|
with caller-specific
|
|
callbacks filled in</p>
|
|
|
|
<p>[in] <code>cb_arg</code>: Pointer to data that will be passed
|
|
to <code>tipc_chan_ops</code> callbacks</p>
|
|
|
|
<p>[retval]: Pointer to a newly-created instance of
|
|
<code>struct tipc_chan</code> on success,
|
|
<code>ERR_PTR(err)</code> otherwise</p>
|
|
|
|
<p>In general, a caller must provide two callbacks that are asynchronously invoked
|
|
when the corresponding activity is occurring.</p>
|
|
|
|
<p>The <code>void (*handle_event)(void *cb_arg, int event)</code>event is invoked
|
|
to notify a caller about a channel state change.</p>
|
|
|
|
<p>[in] <code>cb_arg</code>: Pointer to data passed to a
|
|
<code>tipc_create_channel()</code> call</p>
|
|
|
|
<p>[in] <code>event</code>: An event that can be one of the following values:</p>
|
|
|
|
<ul>
|
|
<li><code>TIPC_CHANNEL_CONNECTED</code> - indicates a successful connection
|
|
to the remote side
|
|
<li><code>TIPC_CHANNEL_DISCONNECTED</code> - indicates the remote side denied the
|
|
new connection request or requested
|
|
disconnection for the previously connected channel
|
|
<li><code>TIPC_CHANNEL_SHUTDOWN</code> - indicates the remote side is shutting down,
|
|
permanently terminating all connections
|
|
</ul>
|
|
|
|
<p>The <code>struct tipc_msg_buf *(*handle_msg)(void *cb_arg, struct tipc_msg_buf *mb)</code>
|
|
callback is invoked to provide notification that a new message has been
|
|
received over a specified channel:</p>
|
|
|
|
<ul>
|
|
<li>[in] <code>cb_arg</code>: Pointer to data passed to the
|
|
<code>tipc_create_channel()</code> call
|
|
<li>[in] <code>mb</code>: Pointer to a <code>struct tipc_msg_buf</code>
|
|
describing an incoming message
|
|
<li>[retval]: The callback implementation is expected to return a pointer to a
|
|
<code>struct tipc_msg_buf</code> that can be the same pointer received
|
|
as an
|
|
<code>mb</code> parameter if the message is handled locally and is not
|
|
required anymore (or it
|
|
can be a new buffer obtained by the <code>tipc_chan_get_rxbuf()</code> call)
|
|
</ul>
|
|
|
|
<h4 id=tipc_chan_connect>tipc_chan_connect()</h4>
|
|
|
|
<p>Initiates a connection to the specified Trusty IPC service.</p>
|
|
|
|
<pre class="prettyprint">
|
|
int tipc_chan_connect(struct tipc_chan *chan, const char *port);
|
|
</pre>
|
|
|
|
<p>[in] <code>chan</code>: Pointer to a channel returned by the
|
|
<code>tipc_create_chan()</code> call</p>
|
|
|
|
<p>[in] <code>port</code>: Pointer to a string containing the
|
|
service name to which to connect</p>
|
|
|
|
<p>[retval]: 0 on success, a negative error otherwise</p>
|
|
|
|
<p>The caller is notified when a connection is established by receiving a
|
|
<code>handle_event</code> callback.</p>
|
|
|
|
<h4 id=tipc_chan_shutdown>tipc_chan_shutdown()</h4>
|
|
|
|
<p>Terminates a connection to the Trusty IPC service previously initiated
|
|
by a <code>tipc_chan_connect()</code> call.</p>
|
|
|
|
<pre class="prettyprint">
|
|
int tipc_chan_shutdown(struct tipc_chan *chan);
|
|
</pre>
|
|
|
|
<p>[in] <code>chan</code>: Pointer to a channel returned by
|
|
a <code>tipc_create_chan()</code> call</p>
|
|
|
|
<h4 id=tipc_chan_destroy>tipc_chan_destroy()</h4>
|
|
|
|
<p>Destroys a specified Trusty IPC channel.</p>
|
|
|
|
<pre class="prettyprint">
|
|
void tipc_chan_destroy(struct tipc_chan *chan);
|
|
</pre>
|
|
|
|
<p>[in] <code>chan</code>: Pointer to a channel returned by the
|
|
<code>tipc_create_chan()</code> call</p>
|
|
|
|
<h4 id=tipc_chan_get_txbuf_timeout>tipc_chan_get_txbuf_timeout()</h4>
|
|
|
|
<p>Obtains a message buffer that can be used to send data over a specified
|
|
channel. If the buffer is not immediately available the caller may be blocked
|
|
for the specified timeout (in milliseconds).</p>
|
|
|
|
<pre class="prettyprint">
|
|
struct tipc_msg_buf *
|
|
tipc_chan_get_txbuf_timeout(struct tipc_chan *chan, long timeout);
|
|
</pre>
|
|
|
|
<p>[in] <code>chan</code>: Pointer to the channel to which to queue a message</p>
|
|
|
|
<p>[in] <code>chan</code>: Maximum timeout to wait until the
|
|
<code>tx</code> buffer becomes available </p>
|
|
|
|
<p>[retval]: A valid message buffer on success,
|
|
<code>ERR_PTR(err)</code> on error</p>
|
|
|
|
<h4 id=tipc_chan_queue_msg>tipc_chan_queue_msg()</h4>
|
|
|
|
<p>Queues a message to be sent over the specified
|
|
Trusty IPC channels.</p>
|
|
|
|
<pre class="prettyprint">
|
|
int tipc_chan_queue_msg(struct tipc_chan *chan, struct tipc_msg_buf *mb);
|
|
</pre>
|
|
|
|
<p>[in] <code>chan</code>: Pointer to the channel to which to queue the message</p>
|
|
|
|
<p>[in] <code>mb:</code> Pointer to the message to queue
|
|
(obtained by a <code>tipc_chan_get_txbuf_timeout()</code> call)</p>
|
|
|
|
<p>[retval]: 0 on success, a negative error otherwise</p>
|
|
|
|
<h4 id=tipc_chan_put_txbuf>tipc_chan_put_txbuf()</h4>
|
|
|
|
<p>Releases the specified <code>Tx</code> message buffer
|
|
previously obtained by a <code>tipc_chan_get_txbuf_timeout()</code> call.</p>
|
|
|
|
<pre class="prettyprint">
|
|
void tipc_chan_put_txbuf(struct tipc_chan *chan,
|
|
struct tipc_msg_buf *mb);
|
|
</pre>
|
|
|
|
<p>[in] <code>chan</code>: Pointer to the channel to which
|
|
this message buffer belongs</p>
|
|
|
|
<p>[in] <code>mb</code>: Pointer to the message buffer to release</p>
|
|
|
|
<p>[retval]: None</p>
|
|
|
|
<h4 id=tipc_chan_get_rxbuf>tipc_chan_get_rxbuf()</h4>
|
|
|
|
<p>Obtains a new message buffer that can be used to receive messages over the
|
|
specified channel.</p>
|
|
|
|
<pre class="prettyprint">
|
|
struct tipc_msg_buf *tipc_chan_get_rxbuf(struct tipc_chan *chan);
|
|
</pre>
|
|
|
|
<p>[in] <code>chan</code>: Pointer to a channel to which this message buffer belongs</p>
|
|
|
|
<p>[retval]: A valid message buffer on success, <code>ERR_PTR(err)</code> on error</p>
|
|
|
|
<h4 id=tipc_chan_put_rxbuf>tipc_chan_put_rxbuf()</h4>
|
|
|
|
<p>Releases a specified message buffer previously obtained by a
|
|
<code>tipc_chan_get_rxbuf()</code> call.</p>
|
|
|
|
<pre class="prettyprint">
|
|
void tipc_chan_put_rxbuf(struct tipc_chan *chan,
|
|
struct tipc_msg_buf *mb);
|
|
</pre>
|
|
|
|
<p>[in] <code>chan</code>: Pointer to a channel to which this message buffer belongs</p>
|
|
|
|
<p>[in] <code>mb</code>: Pointer to a message buffer to release</p>
|
|
|
|
<p>[retval]: None</p>
|
|
|
|
</body>
|
|
</html>
|