*
* Caller must hold socket lock
*/
-
static void advance_rx_queue(struct sock *sk)
{
kfree_skb(__skb_dequeue(&sk->sk_receive_queue));
*
* Caller must hold socket lock
*/
-
static void discard_rx_queue(struct sock *sk)
{
struct sk_buff *buf;
*
* Caller must hold socket lock
*/
-
static void reject_rx_queue(struct sock *sk)
{
struct sk_buff *buf;
*
* Returns 0 on success, errno otherwise
*/
-
static int tipc_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
struct tipc_port *tp_ptr;
/* Validate arguments */
-
if (unlikely(protocol != 0))
return -EPROTONOSUPPORT;
}
/* Allocate socket's protocol area */
-
sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto);
if (sk == NULL)
return -ENOMEM;
/* Allocate TIPC port for socket to use */
-
tp_ptr = tipc_createport_raw(sk, &dispatch, &wakeupdispatch,
TIPC_LOW_IMPORTANCE);
if (unlikely(!tp_ptr)) {
}
/* Finish initializing socket data structures */
-
sock->ops = ops;
sock->state = state;
*
* Returns 0 on success, errno otherwise
*/
-
static int release(struct socket *sock)
{
struct sock *sk = sock->sk;
* Exit if socket isn't fully initialized (occurs when a failed accept()
* releases a pre-allocated child socket that was never used)
*/
-
if (sk == NULL)
return 0;
* Reject all unreceived messages, except on an active connection
* (which disconnects locally & sends a 'FIN+' to peer)
*/
-
while (sock->state != SS_DISCONNECTING) {
buf = __skb_dequeue(&sk->sk_receive_queue);
if (buf == NULL)
* Delete TIPC port; this ensures no more messages are queued
* (also disconnects an active connection & sends a 'FIN-' to peer)
*/
-
res = tipc_deleteport(tport->ref);
/* Discard any remaining (connection-based) messages in receive queue */
-
discard_rx_queue(sk);
/* Reject any messages that accumulated in backlog queue */
-
sock->state = SS_DISCONNECTING;
release_sock(sk);
* NOTE: This routine doesn't need to take the socket lock since it doesn't
* access any non-constant socket information.
*/
-
static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
{
struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
* accesses socket information that is unchanging (or which changes in
* a completely predictable manner).
*/
-
static int get_name(struct socket *sock, struct sockaddr *uaddr,
int *uaddr_len, int peer)
{
* imply that the operation will succeed, merely that it should be performed
* and will not block.
*/
-
static unsigned int poll(struct file *file, struct socket *sock,
poll_table *wait)
{
*
* Returns 0 if permission is granted, otherwise errno
*/
-
static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
{
struct tipc_cfg_msg_hdr hdr;
*
* Returns the number of bytes sent on success, or errno otherwise
*/
-
static int send_msg(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t total_len)
{
(dest->family != AF_TIPC)))
return -EINVAL;
if ((total_len > TIPC_MAX_USER_MSG_SIZE) ||
- (m->msg_iovlen > (unsigned)INT_MAX))
+ (m->msg_iovlen > (unsigned int)INT_MAX))
return -EMSGSIZE;
if (iocb)
}
/* Abort any pending connection attempts (very unlikely) */
-
reject_rx_queue(sk);
}
*
* Returns the number of bytes sent on success, or errno otherwise
*/
-
static int send_packet(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t total_len)
{
int res;
/* Handle implied connection establishment */
-
if (unlikely(dest))
return send_msg(iocb, sock, m, total_len);
if ((total_len > TIPC_MAX_USER_MSG_SIZE) ||
- (m->msg_iovlen > (unsigned)INT_MAX))
+ (m->msg_iovlen > (unsigned int)INT_MAX))
return -EMSGSIZE;
if (iocb)
* Returns the number of bytes sent on success (or partial success),
* or errno if no data sent
*/
-
static int send_stream(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t total_len)
{
lock_sock(sk);
/* Handle special cases where there is no connection */
-
if (unlikely(sock->state != SS_CONNECTED)) {
if (sock->state == SS_UNCONNECTED) {
res = send_packet(NULL, sock, m, total_len);
goto exit;
}
- if ((total_len > (unsigned)INT_MAX) ||
- (m->msg_iovlen > (unsigned)INT_MAX)) {
+ if ((total_len > (unsigned int)INT_MAX) ||
+ (m->msg_iovlen > (unsigned int)INT_MAX)) {
res = -EMSGSIZE;
goto exit;
}
* (i.e. one large iovec entry), but could be improved to pass sets
* of small iovec entries into send_packet().
*/
-
curr_iov = m->msg_iov;
curr_iovlen = m->msg_iovlen;
my_msg.msg_iov = &my_iov;
*
* Returns 0 on success, errno otherwise
*/
-
static int auto_connect(struct socket *sock, struct tipc_msg *msg)
{
struct tipc_sock *tsock = tipc_sk(sock->sk);
*
* Note: Address is not captured if not requested by receiver.
*/
-
static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
{
struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name;
*
* Returns 0 if successful, otherwise errno
*/
-
static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
struct tipc_port *tport)
{
return 0;
/* Optionally capture errored message object(s) */
-
err = msg ? msg_errcode(msg) : 0;
if (unlikely(err)) {
anc_data[0] = err;
}
/* Optionally capture message destination object */
-
dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG;
switch (dest_type) {
case TIPC_NAMED_MSG:
*
* Returns size of returned message data, errno otherwise
*/
-
static int recv_msg(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t buf_len, int flags)
{
int res;
/* Catch invalid receive requests */
-
if (unlikely(!buf_len))
return -EINVAL;
restart:
/* Look for a message in receive queue; wait if necessary */
-
while (skb_queue_empty(&sk->sk_receive_queue)) {
if (sock->state == SS_DISCONNECTING) {
res = -ENOTCONN;
}
/* Look at first message in receive queue */
-
buf = skb_peek(&sk->sk_receive_queue);
msg = buf_msg(buf);
sz = msg_data_sz(msg);
err = msg_errcode(msg);
/* Complete connection setup for an implied connect */
-
if (unlikely(sock->state == SS_CONNECTING)) {
res = auto_connect(sock, msg);
if (res)
}
/* Discard an empty non-errored message & try again */
-
if ((!sz) && (!err)) {
advance_rx_queue(sk);
goto restart;
}
/* Capture sender's address (optional) */
-
set_orig_addr(m, msg);
/* Capture ancillary data (optional) */
-
res = anc_data_recv(m, msg, tport);
if (res)
goto exit;
/* Capture message data (if valid) & compute return value (always) */
-
if (!err) {
if (unlikely(buf_len < sz)) {
sz = buf_len;
}
/* Consume received message (optional) */
-
if (likely(!(flags & MSG_PEEK))) {
if ((sock->state != SS_READY) &&
(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
*
* Returns size of returned message data, errno otherwise
*/
-
static int recv_stream(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t buf_len, int flags)
{
int res = 0;
/* Catch invalid receive attempts */
-
if (unlikely(!buf_len))
return -EINVAL;
target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-restart:
+restart:
/* Look for a message in receive queue; wait if necessary */
-
while (skb_queue_empty(&sk->sk_receive_queue)) {
if (sock->state == SS_DISCONNECTING) {
res = -ENOTCONN;
}
/* Look at first message in receive queue */
-
buf = skb_peek(&sk->sk_receive_queue);
msg = buf_msg(buf);
sz = msg_data_sz(msg);
err = msg_errcode(msg);
/* Discard an empty non-errored message & try again */
-
if ((!sz) && (!err)) {
advance_rx_queue(sk);
goto restart;
}
/* Optionally capture sender's address & ancillary data of first msg */
-
if (sz_copied == 0) {
set_orig_addr(m, msg);
res = anc_data_recv(m, msg, tport);
}
/* Capture message data (if valid) & compute return value (always) */
-
if (!err) {
u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle);
}
/* Consume received message (optional) */
-
if (likely(!(flags & MSG_PEEK))) {
if (unlikely(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
tipc_acknowledge(tport->ref, tport->conn_unacked);
}
/* Loop around if more data is required */
-
if ((sz_copied < buf_len) && /* didn't get all requested data */
(!skb_queue_empty(&sk->sk_receive_queue) ||
(sz_copied < target)) && /* and more is ready or required */
*
* Returns 1 if queue is unable to accept message, 0 otherwise
*/
-
static int rx_queue_full(struct tipc_msg *msg, u32 queue_size, u32 base)
{
u32 threshold;
*
* Returns TIPC error status code (TIPC_OK if message is not to be rejected)
*/
-
static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
{
struct socket *sock = sk->sk_socket;
u32 recv_q_len;
/* Reject message if it is wrong sort of message for socket */
-
- /*
- * WOULD IT BE BETTER TO JUST DISCARD THESE MESSAGES INSTEAD?
- * "NO PORT" ISN'T REALLY THE RIGHT ERROR CODE, AND THERE MAY
- * BE SECURITY IMPLICATIONS INHERENT IN REJECTING INVALID TRAFFIC
- */
+ if (msg_type(msg) > TIPC_DIRECT_MSG)
+ return TIPC_ERR_NO_PORT;
if (sock->state == SS_READY) {
if (msg_connected(msg))
if (msg_mcast(msg))
return TIPC_ERR_NO_PORT;
if (sock->state == SS_CONNECTED) {
- if (!msg_connected(msg))
+ if (!msg_connected(msg) ||
+ !tipc_port_peer_msg(tipc_sk_port(sk), msg))
return TIPC_ERR_NO_PORT;
} else if (sock->state == SS_CONNECTING) {
if (!msg_connected(msg) && (msg_errcode(msg) == 0))
}
/* Reject message if there isn't room to queue it */
-
recv_q_len = (u32)atomic_read(&tipc_queue_size);
if (unlikely(recv_q_len >= OVERLOAD_LIMIT_BASE)) {
if (rx_queue_full(msg, recv_q_len, OVERLOAD_LIMIT_BASE))
}
/* Enqueue message (finally!) */
-
TIPC_SKB_CB(buf)->handle = 0;
atomic_inc(&tipc_queue_size);
__skb_queue_tail(&sk->sk_receive_queue, buf);
/* Initiate connection termination for an incoming 'FIN' */
-
if (unlikely(msg_errcode(msg) && (sock->state == SS_CONNECTED))) {
sock->state = SS_DISCONNECTING;
tipc_disconnect_port(tipc_sk_port(sk));
*
* Returns 0
*/
-
static int backlog_rcv(struct sock *sk, struct sk_buff *buf)
{
u32 res;
*
* Returns TIPC error status code (TIPC_OK if message is not to be rejected)
*/
-
static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
{
struct sock *sk = (struct sock *)tport->usr_handle;
* This code is based on sk_receive_skb(), but must be distinct from it
* since a TIPC-specific filter/reject mechanism is utilized
*/
-
bh_lock_sock(sk);
if (!sock_owned_by_user(sk)) {
res = filter_rcv(sk, buf);
} else {
- if (sk_add_backlog(sk, buf))
+ if (sk_add_backlog(sk, buf, sk->sk_rcvbuf))
res = TIPC_ERR_OVERLOAD;
else
res = TIPC_OK;
*
* Called with port lock already taken.
*/
-
static void wakeupdispatch(struct tipc_port *tport)
{
struct sock *sk = (struct sock *)tport->usr_handle;
*
* Returns 0 on success, errno otherwise
*/
-
static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
int flags)
{
lock_sock(sk);
/* For now, TIPC does not allow use of connect() with DGRAM/RDM types */
-
if (sock->state == SS_READY) {
res = -EOPNOTSUPP;
goto exit;
}
/* For now, TIPC does not support the non-blocking form of connect() */
-
if (flags & O_NONBLOCK) {
res = -EOPNOTSUPP;
goto exit;
}
/* Issue Posix-compliant error code if socket is in the wrong state */
-
if (sock->state == SS_LISTENING) {
res = -EOPNOTSUPP;
goto exit;
* Note: send_msg() validates the rest of the address fields,
* so there's no need to do it here
*/
-
if (dst->addrtype == TIPC_ADDR_MCAST) {
res = -EINVAL;
goto exit;
}
/* Reject any messages already in receive queue (very unlikely) */
-
reject_rx_queue(sk);
/* Send a 'SYN-' to destination */
-
m.msg_name = dest;
m.msg_namelen = destlen;
res = send_msg(NULL, sock, &m, 0);
goto exit;
/* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */
-
timeout = tipc_sk(sk)->conn_timeout;
release_sock(sk);
res = wait_event_interruptible_timeout(*sk_sleep(sk),
*
* Returns 0 on success, errno otherwise
*/
-
static int listen(struct socket *sock, int len)
{
struct sock *sk = sock->sk;
*
* Returns 0 on success, errno otherwise
*/
-
static int accept(struct socket *sock, struct socket *new_sock, int flags)
{
struct sock *sk = sock->sk;
* Reject any stray messages received by new socket
* before the socket lock was taken (very, very unlikely)
*/
-
reject_rx_queue(new_sk);
/* Connect new socket to it's peer */
-
new_tsock->peer_name.ref = msg_origport(msg);
new_tsock->peer_name.node = msg_orignode(msg);
tipc_connect2port(new_ref, &new_tsock->peer_name);
* Respond to 'SYN-' by discarding it & returning 'ACK'-.
* Respond to 'SYN+' by queuing it on new socket.
*/
-
if (!msg_data_sz(msg)) {
struct msghdr m = {NULL,};
*
* Returns 0 on success, errno otherwise
*/
-
static int shutdown(struct socket *sock, int how)
{
struct sock *sk = sock->sk;
case SS_CONNECTING:
case SS_CONNECTED:
- /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */
restart:
+ /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */
buf = __skb_dequeue(&sk->sk_receive_queue);
if (buf) {
atomic_dec(&tipc_queue_size);
case SS_DISCONNECTING:
/* Discard any unreceived messages; wake up sleeping tasks */
-
discard_rx_queue(sk);
if (waitqueue_active(sk_sleep(sk)))
wake_up_interruptible(sk_sleep(sk));
*
* Returns 0 on success, errno otherwise
*/
-
static int setsockopt(struct socket *sock,
int lvl, int opt, char __user *ov, unsigned int ol)
{
*
* Returns 0 on success, errno otherwise
*/
-
static int getsockopt(struct socket *sock,
int lvl, int opt, char __user *ov, int __user *ol)
{
/**
* Protocol switches for the various types of TIPC sockets
*/
-
static const struct proto_ops msg_ops = {
.owner = THIS_MODULE,
.family = AF_TIPC,
/**
* tipc_socket_stop - stop TIPC socket interface
*/
-
void tipc_socket_stop(void)
{
if (!sockets_enabled)
sock_unregister(tipc_family_ops.family);
proto_unregister(&tipc_proto);
}
-