4018 lines · 104.7 KB · C
RawDownload
/* * net/tipc/socket.c: TIPC socket API * * Copyright (c) 2001-2007, 2012-2019, Ericsson AB * Copyright (c) 2004-2008, 2010-2013, Wind River Systems * Copyright (c) 2020-2021, Red Hat Inc * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of its *    contributors may be used to endorse or promote products derived from *    this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <linux/rhashtable.h>#include <linux/sched/signal.h>#include <trace/events/sock.h> #include "core.h"#include "name_table.h"#include "node.h"#include "link.h"#include "name_distr.h"#include "socket.h"#include "bcast.h"#include "netlink.h"#include "group.h"#include "trace.h" #define NAGLE_START_INIT	4#define NAGLE_START_MAX		1024#define CONN_TIMEOUT_DEFAULT    8000    /* default connect timeout = 8s */#define CONN_PROBING_INTV	msecs_to_jiffies(3600000)  /* [ms] => 1 h */#define TIPC_MAX_PORT		0xffffffff#define TIPC_MIN_PORT		1#define TIPC_ACK_RATE		4       /* ACK at 1/4 of rcv window size */ enum {	TIPC_LISTEN = TCP_LISTEN,	TIPC_ESTABLISHED = TCP_ESTABLISHED,	TIPC_OPEN = TCP_CLOSE,	TIPC_DISCONNECTING = TCP_CLOSE_WAIT,	TIPC_CONNECTING = TCP_SYN_SENT,}; struct sockaddr_pair {	struct sockaddr_tipc sock;	struct sockaddr_tipc member;}; /** * struct tipc_sock - TIPC socket structure * @sk: socket - interacts with 'port' and with user via the socket API * @max_pkt: maximum packet size "hint" used when building messages sent by port * @maxnagle: maximum size of msg which can be subject to nagle * @portid: unique port identity in TIPC socket hash table * @phdr: preformatted message header used when sending messages * @cong_links: list of congested links * @publications: list of publications for port * @pub_count: total # of publications port has made during its lifetime * @conn_timeout: the time we can wait for an unresponded setup request * @probe_unacked: probe has not received ack yet * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue * @cong_link_cnt: number of congested links * @snt_unacked: # messages sent by socket, and not yet acked by peer * @snd_win: send window size * @peer_caps: peer capabilities mask * @rcv_unacked: # messages read by user, but not yet acked back to peer * @rcv_win: receive window size * @peer: 'connected' peer for dgram/rdm * @node: hash table node * @mc_method: cookie for use between socket and broadcast layer * @rcu: rcu struct for tipc_sock * @group: TIPC communications group * @oneway: message count in one direction (FIXME) * @nagle_start: current nagle value * @snd_backlog: send backlog count * @msg_acc: messages accepted; used in managing backlog and nagle * @pkt_cnt: TIPC socket packet count * @expect_ack: whether this TIPC socket is expecting an ack * @nodelay: setsockopt() TIPC_NODELAY setting * @group_is_open: TIPC socket group is fully open (FIXME) * @published: true if port has one or more associated names * @conn_addrtype: address type used when establishing connection */struct tipc_sock {	struct sock sk;	u32 max_pkt;	u32 maxnagle;	u32 portid;	struct tipc_msg phdr;	struct list_head cong_links;	struct list_head publications;	u32 pub_count;	atomic_t dupl_rcvcnt;	u16 conn_timeout;	bool probe_unacked;	u16 cong_link_cnt;	u16 snt_unacked;	u16 snd_win;	u16 peer_caps;	u16 rcv_unacked;	u16 rcv_win;	struct sockaddr_tipc peer;	struct rhash_head node;	struct tipc_mc_method mc_method;	struct rcu_head rcu;	struct tipc_group *group;	u32 oneway;	u32 nagle_start;	u16 snd_backlog;	u16 msg_acc;	u16 pkt_cnt;	bool expect_ack;	bool nodelay;	bool group_is_open;	bool published;	u8 conn_addrtype;}; static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb);static void tipc_data_ready(struct sock *sk);static void tipc_write_space(struct sock *sk);static void tipc_sock_destruct(struct sock *sk);static int tipc_release(struct socket *sock);static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags,		       bool kern);static void tipc_sk_timeout(struct timer_list *t);static int tipc_sk_publish(struct tipc_sock *tsk, struct tipc_uaddr *ua);static int tipc_sk_withdraw(struct tipc_sock *tsk, struct tipc_uaddr *ua);static int tipc_sk_leave(struct tipc_sock *tsk);static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid);static int tipc_sk_insert(struct tipc_sock *tsk);static void tipc_sk_remove(struct tipc_sock *tsk);static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz);static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz);static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack);static int tipc_wait_for_connect(struct socket *sock, long *timeo_p); static const struct proto_ops packet_ops;static const struct proto_ops stream_ops;static const struct proto_ops msg_ops;static struct proto tipc_proto;static const struct rhashtable_params tsk_rht_params; static u32 tsk_own_node(struct tipc_sock *tsk){	return msg_prevnode(&tsk->phdr);} static u32 tsk_peer_node(struct tipc_sock *tsk){	return msg_destnode(&tsk->phdr);} static u32 tsk_peer_port(struct tipc_sock *tsk){	return msg_destport(&tsk->phdr);} static  bool tsk_unreliable(struct tipc_sock *tsk){	return msg_src_droppable(&tsk->phdr) != 0;} static void tsk_set_unreliable(struct tipc_sock *tsk, bool unreliable){	msg_set_src_droppable(&tsk->phdr, unreliable ? 1 : 0);} static bool tsk_unreturnable(struct tipc_sock *tsk){	return msg_dest_droppable(&tsk->phdr) != 0;} static void tsk_set_unreturnable(struct tipc_sock *tsk, bool unreturnable){	msg_set_dest_droppable(&tsk->phdr, unreturnable ? 1 : 0);} static int tsk_importance(struct tipc_sock *tsk){	return msg_importance(&tsk->phdr);} static struct tipc_sock *tipc_sk(const struct sock *sk){	return container_of(sk, struct tipc_sock, sk);} int tsk_set_importance(struct sock *sk, int imp){	if (imp > TIPC_CRITICAL_IMPORTANCE)		return -EINVAL;	msg_set_importance(&tipc_sk(sk)->phdr, (u32)imp);	return 0;} static bool tsk_conn_cong(struct tipc_sock *tsk){	return tsk->snt_unacked > tsk->snd_win;} static u16 tsk_blocks(int len){	return ((len / FLOWCTL_BLK_SZ) + 1);} /* tsk_blocks(): translate a buffer size in bytes to number of * advertisable blocks, taking into account the ratio truesize(len)/len * We can trust that this ratio is always < 4 for len >= FLOWCTL_BLK_SZ */static u16 tsk_adv_blocks(int len){	return len / FLOWCTL_BLK_SZ / 4;} /* tsk_inc(): increment counter for sent or received data * - If block based flow control is not supported by peer we *   fall back to message based ditto, incrementing the counter */static u16 tsk_inc(struct tipc_sock *tsk, int msglen){	if (likely(tsk->peer_caps & TIPC_BLOCK_FLOWCTL))		return ((msglen / FLOWCTL_BLK_SZ) + 1);	return 1;} /* tsk_set_nagle - enable/disable nagle property by manipulating maxnagle */static void tsk_set_nagle(struct tipc_sock *tsk){	struct sock *sk = &tsk->sk; 	tsk->maxnagle = 0;	if (sk->sk_type != SOCK_STREAM)		return;	if (tsk->nodelay)		return;	if (!(tsk->peer_caps & TIPC_NAGLE))		return;	/* Limit node local buffer size to avoid receive queue overflow */	if (tsk->max_pkt == MAX_MSG_SIZE)		tsk->maxnagle = 1500;	else		tsk->maxnagle = tsk->max_pkt;} /** * tsk_advance_rx_queue - discard first buffer in socket receive queue * @sk: network socket * * Caller must hold socket lock */static void tsk_advance_rx_queue(struct sock *sk){	trace_tipc_sk_advance_rx(sk, NULL, TIPC_DUMP_SK_RCVQ, " ");	kfree_skb(__skb_dequeue(&sk->sk_receive_queue));} /* tipc_sk_respond() : send response message back to sender */static void tipc_sk_respond(struct sock *sk, struct sk_buff *skb, int err){	u32 selector;	u32 dnode;	u32 onode = tipc_own_addr(sock_net(sk)); 	if (!tipc_msg_reverse(onode, &skb, err))		return; 	trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_NONE, "@sk_respond!");	dnode = msg_destnode(buf_msg(skb));	selector = msg_origport(buf_msg(skb));	tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector);} /** * tsk_rej_rx_queue - reject all buffers in socket receive queue * @sk: network socket * @error: response error code * * Caller must hold socket lock */static void tsk_rej_rx_queue(struct sock *sk, int error){	struct sk_buff *skb; 	while ((skb = __skb_dequeue(&sk->sk_receive_queue)))		tipc_sk_respond(sk, skb, error);} static bool tipc_sk_connected(const struct sock *sk){	return READ_ONCE(sk->sk_state) == TIPC_ESTABLISHED;} /* tipc_sk_type_connectionless - check if the socket is datagram socket * @sk: socket * * Returns true if connection less, false otherwise */static bool tipc_sk_type_connectionless(struct sock *sk){	return sk->sk_type == SOCK_RDM || sk->sk_type == SOCK_DGRAM;} /* tsk_peer_msg - verify if message was sent by connected port's peer * * Handles cases where the node's network address has changed from * the default of <0.0.0> to its configured setting. */static bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg){	struct sock *sk = &tsk->sk;	u32 self = tipc_own_addr(sock_net(sk));	u32 peer_port = tsk_peer_port(tsk);	u32 orig_node, peer_node; 	if (unlikely(!tipc_sk_connected(sk)))		return false; 	if (unlikely(msg_origport(msg) != peer_port))		return false; 	orig_node = msg_orignode(msg);	peer_node = tsk_peer_node(tsk); 	if (likely(orig_node == peer_node))		return true; 	if (!orig_node && peer_node == self)		return true; 	if (!peer_node && orig_node == self)		return true; 	return false;} /* tipc_set_sk_state - set the sk_state of the socket * @sk: socket * * Caller must hold socket lock * * Returns 0 on success, errno otherwise */static int tipc_set_sk_state(struct sock *sk, int state){	int oldsk_state = sk->sk_state;	int res = -EINVAL; 	switch (state) {	case TIPC_OPEN:		res = 0;		break;	case TIPC_LISTEN:	case TIPC_CONNECTING:		if (oldsk_state == TIPC_OPEN)			res = 0;		break;	case TIPC_ESTABLISHED:		if (oldsk_state == TIPC_CONNECTING ||		    oldsk_state == TIPC_OPEN)			res = 0;		break;	case TIPC_DISCONNECTING:		if (oldsk_state == TIPC_CONNECTING ||		    oldsk_state == TIPC_ESTABLISHED)			res = 0;		break;	} 	if (!res)		sk->sk_state = state; 	return res;} static int tipc_sk_sock_err(struct socket *sock, long *timeout){	struct sock *sk = sock->sk;	int err = sock_error(sk);	int typ = sock->type; 	if (err)		return err;	if (typ == SOCK_STREAM || typ == SOCK_SEQPACKET) {		if (sk->sk_state == TIPC_DISCONNECTING)			return -EPIPE;		else if (!tipc_sk_connected(sk))			return -ENOTCONN;	}	if (!*timeout)		return -EAGAIN;	if (signal_pending(current))		return sock_intr_errno(*timeout); 	return 0;} #define tipc_wait_for_cond(sock_, timeo_, condition_)			       \({                                                                             \	DEFINE_WAIT_FUNC(wait_, woken_wake_function);                          \	struct sock *sk_;						       \	int rc_;							       \									       \	while ((rc_ = !(condition_))) {					       \		/* coupled with smp_wmb() in tipc_sk_proto_rcv() */            \		smp_rmb();                                                     \		sk_ = (sock_)->sk;					       \		rc_ = tipc_sk_sock_err((sock_), timeo_);		       \		if (rc_)						       \			break;						       \		add_wait_queue(sk_sleep(sk_), &wait_);                         \		release_sock(sk_);					       \		*(timeo_) = wait_woken(&wait_, TASK_INTERRUPTIBLE, *(timeo_)); \		sched_annotate_sleep();				               \		lock_sock(sk_);						       \		remove_wait_queue(sk_sleep(sk_), &wait_);		       \	}								       \	rc_;								       \}) /** * tipc_sk_create - create a TIPC socket * @net: network namespace (must be default network) * @sock: pre-allocated socket structure * @protocol: protocol indicator (must be 0) * @kern: caused by kernel or by userspace? * * This routine creates additional data structures used by the TIPC socket, * initializes them, and links them together. * * Return: 0 on success, errno otherwise */static int tipc_sk_create(struct net *net, struct socket *sock,			  int protocol, int kern){	const struct proto_ops *ops;	struct sock *sk;	struct tipc_sock *tsk;	struct tipc_msg *msg; 	/* Validate arguments */	if (unlikely(protocol != 0))		return -EPROTONOSUPPORT; 	switch (sock->type) {	case SOCK_STREAM:		ops = &stream_ops;		break;	case SOCK_SEQPACKET:		ops = &packet_ops;		break;	case SOCK_DGRAM:	case SOCK_RDM:		ops = &msg_ops;		break;	default:		return -EPROTOTYPE;	} 	/* Allocate socket's protocol area */	sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto, kern);	if (sk == NULL)		return -ENOMEM; 	tsk = tipc_sk(sk);	tsk->max_pkt = MAX_PKT_DEFAULT;	tsk->maxnagle = 0;	tsk->nagle_start = NAGLE_START_INIT;	INIT_LIST_HEAD(&tsk->publications);	INIT_LIST_HEAD(&tsk->cong_links);	msg = &tsk->phdr; 	/* Finish initializing socket data structures */

Lines 1–500 of 4018.