18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * net/tipc/socket.c: TIPC socket API
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2001-2007, 2012-2017, Ericsson AB
58c2ecf20Sopenharmony_ci * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
68c2ecf20Sopenharmony_ci * All rights reserved.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
128c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
148c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
158c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
168c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its
178c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived from
188c2ecf20Sopenharmony_ci *    this software without specific prior written permission.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
228c2ecf20Sopenharmony_ci * Software Foundation.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
268c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
278c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
288c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
318c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
328c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
338c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
348c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <linux/rhashtable.h>
388c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include "core.h"
418c2ecf20Sopenharmony_ci#include "name_table.h"
428c2ecf20Sopenharmony_ci#include "node.h"
438c2ecf20Sopenharmony_ci#include "link.h"
448c2ecf20Sopenharmony_ci#include "name_distr.h"
458c2ecf20Sopenharmony_ci#include "socket.h"
468c2ecf20Sopenharmony_ci#include "bcast.h"
478c2ecf20Sopenharmony_ci#include "netlink.h"
488c2ecf20Sopenharmony_ci#include "group.h"
498c2ecf20Sopenharmony_ci#include "trace.h"
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define NAGLE_START_INIT	4
528c2ecf20Sopenharmony_ci#define NAGLE_START_MAX		1024
538c2ecf20Sopenharmony_ci#define CONN_TIMEOUT_DEFAULT    8000    /* default connect timeout = 8s */
548c2ecf20Sopenharmony_ci#define CONN_PROBING_INTV	msecs_to_jiffies(3600000)  /* [ms] => 1 h */
558c2ecf20Sopenharmony_ci#define TIPC_MAX_PORT		0xffffffff
568c2ecf20Sopenharmony_ci#define TIPC_MIN_PORT		1
578c2ecf20Sopenharmony_ci#define TIPC_ACK_RATE		4       /* ACK at 1/4 of rcv window size */
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cienum {
608c2ecf20Sopenharmony_ci	TIPC_LISTEN = TCP_LISTEN,
618c2ecf20Sopenharmony_ci	TIPC_ESTABLISHED = TCP_ESTABLISHED,
628c2ecf20Sopenharmony_ci	TIPC_OPEN = TCP_CLOSE,
638c2ecf20Sopenharmony_ci	TIPC_DISCONNECTING = TCP_CLOSE_WAIT,
648c2ecf20Sopenharmony_ci	TIPC_CONNECTING = TCP_SYN_SENT,
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistruct sockaddr_pair {
688c2ecf20Sopenharmony_ci	struct sockaddr_tipc sock;
698c2ecf20Sopenharmony_ci	struct sockaddr_tipc member;
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/**
738c2ecf20Sopenharmony_ci * struct tipc_sock - TIPC socket structure
748c2ecf20Sopenharmony_ci * @sk: socket - interacts with 'port' and with user via the socket API
758c2ecf20Sopenharmony_ci * @conn_type: TIPC type used when connection was established
768c2ecf20Sopenharmony_ci * @conn_instance: TIPC instance used when connection was established
778c2ecf20Sopenharmony_ci * @published: non-zero if port has one or more associated names
788c2ecf20Sopenharmony_ci * @max_pkt: maximum packet size "hint" used when building messages sent by port
798c2ecf20Sopenharmony_ci * @maxnagle: maximum size of msg which can be subject to nagle
808c2ecf20Sopenharmony_ci * @portid: unique port identity in TIPC socket hash table
818c2ecf20Sopenharmony_ci * @phdr: preformatted message header used when sending messages
828c2ecf20Sopenharmony_ci * #cong_links: list of congested links
838c2ecf20Sopenharmony_ci * @publications: list of publications for port
848c2ecf20Sopenharmony_ci * @blocking_link: address of the congested link we are currently sleeping on
858c2ecf20Sopenharmony_ci * @pub_count: total # of publications port has made during its lifetime
868c2ecf20Sopenharmony_ci * @conn_timeout: the time we can wait for an unresponded setup request
878c2ecf20Sopenharmony_ci * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue
888c2ecf20Sopenharmony_ci * @cong_link_cnt: number of congested links
898c2ecf20Sopenharmony_ci * @snt_unacked: # messages sent by socket, and not yet acked by peer
908c2ecf20Sopenharmony_ci * @rcv_unacked: # messages read by user, but not yet acked back to peer
918c2ecf20Sopenharmony_ci * @peer: 'connected' peer for dgram/rdm
928c2ecf20Sopenharmony_ci * @node: hash table node
938c2ecf20Sopenharmony_ci * @mc_method: cookie for use between socket and broadcast layer
948c2ecf20Sopenharmony_ci * @rcu: rcu struct for tipc_sock
958c2ecf20Sopenharmony_ci */
968c2ecf20Sopenharmony_cistruct tipc_sock {
978c2ecf20Sopenharmony_ci	struct sock sk;
988c2ecf20Sopenharmony_ci	u32 conn_type;
998c2ecf20Sopenharmony_ci	u32 conn_instance;
1008c2ecf20Sopenharmony_ci	int published;
1018c2ecf20Sopenharmony_ci	u32 max_pkt;
1028c2ecf20Sopenharmony_ci	u32 maxnagle;
1038c2ecf20Sopenharmony_ci	u32 portid;
1048c2ecf20Sopenharmony_ci	struct tipc_msg phdr;
1058c2ecf20Sopenharmony_ci	struct list_head cong_links;
1068c2ecf20Sopenharmony_ci	struct list_head publications;
1078c2ecf20Sopenharmony_ci	u32 pub_count;
1088c2ecf20Sopenharmony_ci	atomic_t dupl_rcvcnt;
1098c2ecf20Sopenharmony_ci	u16 conn_timeout;
1108c2ecf20Sopenharmony_ci	bool probe_unacked;
1118c2ecf20Sopenharmony_ci	u16 cong_link_cnt;
1128c2ecf20Sopenharmony_ci	u16 snt_unacked;
1138c2ecf20Sopenharmony_ci	u16 snd_win;
1148c2ecf20Sopenharmony_ci	u16 peer_caps;
1158c2ecf20Sopenharmony_ci	u16 rcv_unacked;
1168c2ecf20Sopenharmony_ci	u16 rcv_win;
1178c2ecf20Sopenharmony_ci	struct sockaddr_tipc peer;
1188c2ecf20Sopenharmony_ci	struct rhash_head node;
1198c2ecf20Sopenharmony_ci	struct tipc_mc_method mc_method;
1208c2ecf20Sopenharmony_ci	struct rcu_head rcu;
1218c2ecf20Sopenharmony_ci	struct tipc_group *group;
1228c2ecf20Sopenharmony_ci	u32 oneway;
1238c2ecf20Sopenharmony_ci	u32 nagle_start;
1248c2ecf20Sopenharmony_ci	u16 snd_backlog;
1258c2ecf20Sopenharmony_ci	u16 msg_acc;
1268c2ecf20Sopenharmony_ci	u16 pkt_cnt;
1278c2ecf20Sopenharmony_ci	bool expect_ack;
1288c2ecf20Sopenharmony_ci	bool nodelay;
1298c2ecf20Sopenharmony_ci	bool group_is_open;
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb);
1338c2ecf20Sopenharmony_cistatic void tipc_data_ready(struct sock *sk);
1348c2ecf20Sopenharmony_cistatic void tipc_write_space(struct sock *sk);
1358c2ecf20Sopenharmony_cistatic void tipc_sock_destruct(struct sock *sk);
1368c2ecf20Sopenharmony_cistatic int tipc_release(struct socket *sock);
1378c2ecf20Sopenharmony_cistatic int tipc_accept(struct socket *sock, struct socket *new_sock, int flags,
1388c2ecf20Sopenharmony_ci		       bool kern);
1398c2ecf20Sopenharmony_cistatic void tipc_sk_timeout(struct timer_list *t);
1408c2ecf20Sopenharmony_cistatic int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
1418c2ecf20Sopenharmony_ci			   struct tipc_name_seq const *seq);
1428c2ecf20Sopenharmony_cistatic int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
1438c2ecf20Sopenharmony_ci			    struct tipc_name_seq const *seq);
1448c2ecf20Sopenharmony_cistatic int tipc_sk_leave(struct tipc_sock *tsk);
1458c2ecf20Sopenharmony_cistatic struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid);
1468c2ecf20Sopenharmony_cistatic int tipc_sk_insert(struct tipc_sock *tsk);
1478c2ecf20Sopenharmony_cistatic void tipc_sk_remove(struct tipc_sock *tsk);
1488c2ecf20Sopenharmony_cistatic int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz);
1498c2ecf20Sopenharmony_cistatic int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz);
1508c2ecf20Sopenharmony_cistatic void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack);
1518c2ecf20Sopenharmony_cistatic int tipc_wait_for_connect(struct socket *sock, long *timeo_p);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic const struct proto_ops packet_ops;
1548c2ecf20Sopenharmony_cistatic const struct proto_ops stream_ops;
1558c2ecf20Sopenharmony_cistatic const struct proto_ops msg_ops;
1568c2ecf20Sopenharmony_cistatic struct proto tipc_proto;
1578c2ecf20Sopenharmony_cistatic const struct rhashtable_params tsk_rht_params;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic u32 tsk_own_node(struct tipc_sock *tsk)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	return msg_prevnode(&tsk->phdr);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic u32 tsk_peer_node(struct tipc_sock *tsk)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	return msg_destnode(&tsk->phdr);
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic u32 tsk_peer_port(struct tipc_sock *tsk)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	return msg_destport(&tsk->phdr);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic  bool tsk_unreliable(struct tipc_sock *tsk)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	return msg_src_droppable(&tsk->phdr) != 0;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic void tsk_set_unreliable(struct tipc_sock *tsk, bool unreliable)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	msg_set_src_droppable(&tsk->phdr, unreliable ? 1 : 0);
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic bool tsk_unreturnable(struct tipc_sock *tsk)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	return msg_dest_droppable(&tsk->phdr) != 0;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void tsk_set_unreturnable(struct tipc_sock *tsk, bool unreturnable)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	msg_set_dest_droppable(&tsk->phdr, unreturnable ? 1 : 0);
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int tsk_importance(struct tipc_sock *tsk)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	return msg_importance(&tsk->phdr);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic struct tipc_sock *tipc_sk(const struct sock *sk)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	return container_of(sk, struct tipc_sock, sk);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ciint tsk_set_importance(struct sock *sk, int imp)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	if (imp > TIPC_CRITICAL_IMPORTANCE)
2078c2ecf20Sopenharmony_ci		return -EINVAL;
2088c2ecf20Sopenharmony_ci	msg_set_importance(&tipc_sk(sk)->phdr, (u32)imp);
2098c2ecf20Sopenharmony_ci	return 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic bool tsk_conn_cong(struct tipc_sock *tsk)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	return tsk->snt_unacked > tsk->snd_win;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic u16 tsk_blocks(int len)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	return ((len / FLOWCTL_BLK_SZ) + 1);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/* tsk_blocks(): translate a buffer size in bytes to number of
2238c2ecf20Sopenharmony_ci * advertisable blocks, taking into account the ratio truesize(len)/len
2248c2ecf20Sopenharmony_ci * We can trust that this ratio is always < 4 for len >= FLOWCTL_BLK_SZ
2258c2ecf20Sopenharmony_ci */
2268c2ecf20Sopenharmony_cistatic u16 tsk_adv_blocks(int len)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	return len / FLOWCTL_BLK_SZ / 4;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/* tsk_inc(): increment counter for sent or received data
2328c2ecf20Sopenharmony_ci * - If block based flow control is not supported by peer we
2338c2ecf20Sopenharmony_ci *   fall back to message based ditto, incrementing the counter
2348c2ecf20Sopenharmony_ci */
2358c2ecf20Sopenharmony_cistatic u16 tsk_inc(struct tipc_sock *tsk, int msglen)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	if (likely(tsk->peer_caps & TIPC_BLOCK_FLOWCTL))
2388c2ecf20Sopenharmony_ci		return ((msglen / FLOWCTL_BLK_SZ) + 1);
2398c2ecf20Sopenharmony_ci	return 1;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci/* tsk_set_nagle - enable/disable nagle property by manipulating maxnagle
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_cistatic void tsk_set_nagle(struct tipc_sock *tsk)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	tsk->maxnagle = 0;
2498c2ecf20Sopenharmony_ci	if (sk->sk_type != SOCK_STREAM)
2508c2ecf20Sopenharmony_ci		return;
2518c2ecf20Sopenharmony_ci	if (tsk->nodelay)
2528c2ecf20Sopenharmony_ci		return;
2538c2ecf20Sopenharmony_ci	if (!(tsk->peer_caps & TIPC_NAGLE))
2548c2ecf20Sopenharmony_ci		return;
2558c2ecf20Sopenharmony_ci	/* Limit node local buffer size to avoid receive queue overflow */
2568c2ecf20Sopenharmony_ci	if (tsk->max_pkt == MAX_MSG_SIZE)
2578c2ecf20Sopenharmony_ci		tsk->maxnagle = 1500;
2588c2ecf20Sopenharmony_ci	else
2598c2ecf20Sopenharmony_ci		tsk->maxnagle = tsk->max_pkt;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci/**
2638c2ecf20Sopenharmony_ci * tsk_advance_rx_queue - discard first buffer in socket receive queue
2648c2ecf20Sopenharmony_ci *
2658c2ecf20Sopenharmony_ci * Caller must hold socket lock
2668c2ecf20Sopenharmony_ci */
2678c2ecf20Sopenharmony_cistatic void tsk_advance_rx_queue(struct sock *sk)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	trace_tipc_sk_advance_rx(sk, NULL, TIPC_DUMP_SK_RCVQ, " ");
2708c2ecf20Sopenharmony_ci	kfree_skb(__skb_dequeue(&sk->sk_receive_queue));
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci/* tipc_sk_respond() : send response message back to sender
2748c2ecf20Sopenharmony_ci */
2758c2ecf20Sopenharmony_cistatic void tipc_sk_respond(struct sock *sk, struct sk_buff *skb, int err)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	u32 selector;
2788c2ecf20Sopenharmony_ci	u32 dnode;
2798c2ecf20Sopenharmony_ci	u32 onode = tipc_own_addr(sock_net(sk));
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (!tipc_msg_reverse(onode, &skb, err))
2828c2ecf20Sopenharmony_ci		return;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_NONE, "@sk_respond!");
2858c2ecf20Sopenharmony_ci	dnode = msg_destnode(buf_msg(skb));
2868c2ecf20Sopenharmony_ci	selector = msg_origport(buf_msg(skb));
2878c2ecf20Sopenharmony_ci	tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector);
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/**
2918c2ecf20Sopenharmony_ci * tsk_rej_rx_queue - reject all buffers in socket receive queue
2928c2ecf20Sopenharmony_ci *
2938c2ecf20Sopenharmony_ci * Caller must hold socket lock
2948c2ecf20Sopenharmony_ci */
2958c2ecf20Sopenharmony_cistatic void tsk_rej_rx_queue(struct sock *sk, int error)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&sk->sk_receive_queue)))
3008c2ecf20Sopenharmony_ci		tipc_sk_respond(sk, skb, error);
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic bool tipc_sk_connected(const struct sock *sk)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	return READ_ONCE(sk->sk_state) == TIPC_ESTABLISHED;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/* tipc_sk_type_connectionless - check if the socket is datagram socket
3098c2ecf20Sopenharmony_ci * @sk: socket
3108c2ecf20Sopenharmony_ci *
3118c2ecf20Sopenharmony_ci * Returns true if connection less, false otherwise
3128c2ecf20Sopenharmony_ci */
3138c2ecf20Sopenharmony_cistatic bool tipc_sk_type_connectionless(struct sock *sk)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	return sk->sk_type == SOCK_RDM || sk->sk_type == SOCK_DGRAM;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci/* tsk_peer_msg - verify if message was sent by connected port's peer
3198c2ecf20Sopenharmony_ci *
3208c2ecf20Sopenharmony_ci * Handles cases where the node's network address has changed from
3218c2ecf20Sopenharmony_ci * the default of <0.0.0> to its configured setting.
3228c2ecf20Sopenharmony_ci */
3238c2ecf20Sopenharmony_cistatic bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
3268c2ecf20Sopenharmony_ci	u32 self = tipc_own_addr(sock_net(sk));
3278c2ecf20Sopenharmony_ci	u32 peer_port = tsk_peer_port(tsk);
3288c2ecf20Sopenharmony_ci	u32 orig_node, peer_node;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (unlikely(!tipc_sk_connected(sk)))
3318c2ecf20Sopenharmony_ci		return false;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (unlikely(msg_origport(msg) != peer_port))
3348c2ecf20Sopenharmony_ci		return false;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	orig_node = msg_orignode(msg);
3378c2ecf20Sopenharmony_ci	peer_node = tsk_peer_node(tsk);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (likely(orig_node == peer_node))
3408c2ecf20Sopenharmony_ci		return true;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (!orig_node && peer_node == self)
3438c2ecf20Sopenharmony_ci		return true;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (!peer_node && orig_node == self)
3468c2ecf20Sopenharmony_ci		return true;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return false;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/* tipc_set_sk_state - set the sk_state of the socket
3528c2ecf20Sopenharmony_ci * @sk: socket
3538c2ecf20Sopenharmony_ci *
3548c2ecf20Sopenharmony_ci * Caller must hold socket lock
3558c2ecf20Sopenharmony_ci *
3568c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
3578c2ecf20Sopenharmony_ci */
3588c2ecf20Sopenharmony_cistatic int tipc_set_sk_state(struct sock *sk, int state)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	int oldsk_state = sk->sk_state;
3618c2ecf20Sopenharmony_ci	int res = -EINVAL;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	switch (state) {
3648c2ecf20Sopenharmony_ci	case TIPC_OPEN:
3658c2ecf20Sopenharmony_ci		res = 0;
3668c2ecf20Sopenharmony_ci		break;
3678c2ecf20Sopenharmony_ci	case TIPC_LISTEN:
3688c2ecf20Sopenharmony_ci	case TIPC_CONNECTING:
3698c2ecf20Sopenharmony_ci		if (oldsk_state == TIPC_OPEN)
3708c2ecf20Sopenharmony_ci			res = 0;
3718c2ecf20Sopenharmony_ci		break;
3728c2ecf20Sopenharmony_ci	case TIPC_ESTABLISHED:
3738c2ecf20Sopenharmony_ci		if (oldsk_state == TIPC_CONNECTING ||
3748c2ecf20Sopenharmony_ci		    oldsk_state == TIPC_OPEN)
3758c2ecf20Sopenharmony_ci			res = 0;
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	case TIPC_DISCONNECTING:
3788c2ecf20Sopenharmony_ci		if (oldsk_state == TIPC_CONNECTING ||
3798c2ecf20Sopenharmony_ci		    oldsk_state == TIPC_ESTABLISHED)
3808c2ecf20Sopenharmony_ci			res = 0;
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (!res)
3858c2ecf20Sopenharmony_ci		sk->sk_state = state;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	return res;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic int tipc_sk_sock_err(struct socket *sock, long *timeout)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
3938c2ecf20Sopenharmony_ci	int err = sock_error(sk);
3948c2ecf20Sopenharmony_ci	int typ = sock->type;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (err)
3978c2ecf20Sopenharmony_ci		return err;
3988c2ecf20Sopenharmony_ci	if (typ == SOCK_STREAM || typ == SOCK_SEQPACKET) {
3998c2ecf20Sopenharmony_ci		if (sk->sk_state == TIPC_DISCONNECTING)
4008c2ecf20Sopenharmony_ci			return -EPIPE;
4018c2ecf20Sopenharmony_ci		else if (!tipc_sk_connected(sk))
4028c2ecf20Sopenharmony_ci			return -ENOTCONN;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci	if (!*timeout)
4058c2ecf20Sopenharmony_ci		return -EAGAIN;
4068c2ecf20Sopenharmony_ci	if (signal_pending(current))
4078c2ecf20Sopenharmony_ci		return sock_intr_errno(*timeout);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return 0;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci#define tipc_wait_for_cond(sock_, timeo_, condition_)			       \
4138c2ecf20Sopenharmony_ci({                                                                             \
4148c2ecf20Sopenharmony_ci	DEFINE_WAIT_FUNC(wait_, woken_wake_function);                          \
4158c2ecf20Sopenharmony_ci	struct sock *sk_;						       \
4168c2ecf20Sopenharmony_ci	int rc_;							       \
4178c2ecf20Sopenharmony_ci									       \
4188c2ecf20Sopenharmony_ci	while ((rc_ = !(condition_))) {					       \
4198c2ecf20Sopenharmony_ci		/* coupled with smp_wmb() in tipc_sk_proto_rcv() */            \
4208c2ecf20Sopenharmony_ci		smp_rmb();                                                     \
4218c2ecf20Sopenharmony_ci		sk_ = (sock_)->sk;					       \
4228c2ecf20Sopenharmony_ci		rc_ = tipc_sk_sock_err((sock_), timeo_);		       \
4238c2ecf20Sopenharmony_ci		if (rc_)						       \
4248c2ecf20Sopenharmony_ci			break;						       \
4258c2ecf20Sopenharmony_ci		add_wait_queue(sk_sleep(sk_), &wait_);                         \
4268c2ecf20Sopenharmony_ci		release_sock(sk_);					       \
4278c2ecf20Sopenharmony_ci		*(timeo_) = wait_woken(&wait_, TASK_INTERRUPTIBLE, *(timeo_)); \
4288c2ecf20Sopenharmony_ci		sched_annotate_sleep();				               \
4298c2ecf20Sopenharmony_ci		lock_sock(sk_);						       \
4308c2ecf20Sopenharmony_ci		remove_wait_queue(sk_sleep(sk_), &wait_);		       \
4318c2ecf20Sopenharmony_ci	}								       \
4328c2ecf20Sopenharmony_ci	rc_;								       \
4338c2ecf20Sopenharmony_ci})
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci/**
4368c2ecf20Sopenharmony_ci * tipc_sk_create - create a TIPC socket
4378c2ecf20Sopenharmony_ci * @net: network namespace (must be default network)
4388c2ecf20Sopenharmony_ci * @sock: pre-allocated socket structure
4398c2ecf20Sopenharmony_ci * @protocol: protocol indicator (must be 0)
4408c2ecf20Sopenharmony_ci * @kern: caused by kernel or by userspace?
4418c2ecf20Sopenharmony_ci *
4428c2ecf20Sopenharmony_ci * This routine creates additional data structures used by the TIPC socket,
4438c2ecf20Sopenharmony_ci * initializes them, and links them together.
4448c2ecf20Sopenharmony_ci *
4458c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
4468c2ecf20Sopenharmony_ci */
4478c2ecf20Sopenharmony_cistatic int tipc_sk_create(struct net *net, struct socket *sock,
4488c2ecf20Sopenharmony_ci			  int protocol, int kern)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	const struct proto_ops *ops;
4518c2ecf20Sopenharmony_ci	struct sock *sk;
4528c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
4538c2ecf20Sopenharmony_ci	struct tipc_msg *msg;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* Validate arguments */
4568c2ecf20Sopenharmony_ci	if (unlikely(protocol != 0))
4578c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	switch (sock->type) {
4608c2ecf20Sopenharmony_ci	case SOCK_STREAM:
4618c2ecf20Sopenharmony_ci		ops = &stream_ops;
4628c2ecf20Sopenharmony_ci		break;
4638c2ecf20Sopenharmony_ci	case SOCK_SEQPACKET:
4648c2ecf20Sopenharmony_ci		ops = &packet_ops;
4658c2ecf20Sopenharmony_ci		break;
4668c2ecf20Sopenharmony_ci	case SOCK_DGRAM:
4678c2ecf20Sopenharmony_ci	case SOCK_RDM:
4688c2ecf20Sopenharmony_ci		ops = &msg_ops;
4698c2ecf20Sopenharmony_ci		break;
4708c2ecf20Sopenharmony_ci	default:
4718c2ecf20Sopenharmony_ci		return -EPROTOTYPE;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	/* Allocate socket's protocol area */
4758c2ecf20Sopenharmony_ci	sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto, kern);
4768c2ecf20Sopenharmony_ci	if (sk == NULL)
4778c2ecf20Sopenharmony_ci		return -ENOMEM;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	tsk = tipc_sk(sk);
4808c2ecf20Sopenharmony_ci	tsk->max_pkt = MAX_PKT_DEFAULT;
4818c2ecf20Sopenharmony_ci	tsk->maxnagle = 0;
4828c2ecf20Sopenharmony_ci	tsk->nagle_start = NAGLE_START_INIT;
4838c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&tsk->publications);
4848c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&tsk->cong_links);
4858c2ecf20Sopenharmony_ci	msg = &tsk->phdr;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* Finish initializing socket data structures */
4888c2ecf20Sopenharmony_ci	sock->ops = ops;
4898c2ecf20Sopenharmony_ci	sock_init_data(sock, sk);
4908c2ecf20Sopenharmony_ci	tipc_set_sk_state(sk, TIPC_OPEN);
4918c2ecf20Sopenharmony_ci	if (tipc_sk_insert(tsk)) {
4928c2ecf20Sopenharmony_ci		sk_free(sk);
4938c2ecf20Sopenharmony_ci		pr_warn("Socket create failed; port number exhausted\n");
4948c2ecf20Sopenharmony_ci		return -EINVAL;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/* Ensure tsk is visible before we read own_addr. */
4988c2ecf20Sopenharmony_ci	smp_mb();
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	tipc_msg_init(tipc_own_addr(net), msg, TIPC_LOW_IMPORTANCE,
5018c2ecf20Sopenharmony_ci		      TIPC_NAMED_MSG, NAMED_H_SIZE, 0);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	msg_set_origport(msg, tsk->portid);
5048c2ecf20Sopenharmony_ci	timer_setup(&sk->sk_timer, tipc_sk_timeout, 0);
5058c2ecf20Sopenharmony_ci	sk->sk_shutdown = 0;
5068c2ecf20Sopenharmony_ci	sk->sk_backlog_rcv = tipc_sk_backlog_rcv;
5078c2ecf20Sopenharmony_ci	sk->sk_rcvbuf = READ_ONCE(sysctl_tipc_rmem[1]);
5088c2ecf20Sopenharmony_ci	sk->sk_data_ready = tipc_data_ready;
5098c2ecf20Sopenharmony_ci	sk->sk_write_space = tipc_write_space;
5108c2ecf20Sopenharmony_ci	sk->sk_destruct = tipc_sock_destruct;
5118c2ecf20Sopenharmony_ci	tsk->conn_timeout = CONN_TIMEOUT_DEFAULT;
5128c2ecf20Sopenharmony_ci	tsk->group_is_open = true;
5138c2ecf20Sopenharmony_ci	atomic_set(&tsk->dupl_rcvcnt, 0);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/* Start out with safe limits until we receive an advertised window */
5168c2ecf20Sopenharmony_ci	tsk->snd_win = tsk_adv_blocks(RCVBUF_MIN);
5178c2ecf20Sopenharmony_ci	tsk->rcv_win = tsk->snd_win;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (tipc_sk_type_connectionless(sk)) {
5208c2ecf20Sopenharmony_ci		tsk_set_unreturnable(tsk, true);
5218c2ecf20Sopenharmony_ci		if (sock->type == SOCK_DGRAM)
5228c2ecf20Sopenharmony_ci			tsk_set_unreliable(tsk, true);
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci	__skb_queue_head_init(&tsk->mc_method.deferredq);
5258c2ecf20Sopenharmony_ci	trace_tipc_sk_create(sk, NULL, TIPC_DUMP_NONE, " ");
5268c2ecf20Sopenharmony_ci	return 0;
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic void tipc_sk_callback(struct rcu_head *head)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = container_of(head, struct tipc_sock, rcu);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	sock_put(&tsk->sk);
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci/* Caller should hold socket lock for the socket. */
5378c2ecf20Sopenharmony_cistatic void __tipc_shutdown(struct socket *sock, int error)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
5408c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
5418c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
5428c2ecf20Sopenharmony_ci	long timeout = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT);
5438c2ecf20Sopenharmony_ci	u32 dnode = tsk_peer_node(tsk);
5448c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	/* Avoid that hi-prio shutdown msgs bypass msgs in link wakeup queue */
5478c2ecf20Sopenharmony_ci	tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt &&
5488c2ecf20Sopenharmony_ci					    !tsk_conn_cong(tsk)));
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* Push out delayed messages if in Nagle mode */
5518c2ecf20Sopenharmony_ci	tipc_sk_push_backlog(tsk, false);
5528c2ecf20Sopenharmony_ci	/* Remove pending SYN */
5538c2ecf20Sopenharmony_ci	__skb_queue_purge(&sk->sk_write_queue);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	/* Remove partially received buffer if any */
5568c2ecf20Sopenharmony_ci	skb = skb_peek(&sk->sk_receive_queue);
5578c2ecf20Sopenharmony_ci	if (skb && TIPC_SKB_CB(skb)->bytes_read) {
5588c2ecf20Sopenharmony_ci		__skb_unlink(skb, &sk->sk_receive_queue);
5598c2ecf20Sopenharmony_ci		kfree_skb(skb);
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	/* Reject all unreceived messages if connectionless */
5638c2ecf20Sopenharmony_ci	if (tipc_sk_type_connectionless(sk)) {
5648c2ecf20Sopenharmony_ci		tsk_rej_rx_queue(sk, error);
5658c2ecf20Sopenharmony_ci		return;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
5698c2ecf20Sopenharmony_ci	case TIPC_CONNECTING:
5708c2ecf20Sopenharmony_ci	case TIPC_ESTABLISHED:
5718c2ecf20Sopenharmony_ci		tipc_set_sk_state(sk, TIPC_DISCONNECTING);
5728c2ecf20Sopenharmony_ci		tipc_node_remove_conn(net, dnode, tsk->portid);
5738c2ecf20Sopenharmony_ci		/* Send a FIN+/- to its peer */
5748c2ecf20Sopenharmony_ci		skb = __skb_dequeue(&sk->sk_receive_queue);
5758c2ecf20Sopenharmony_ci		if (skb) {
5768c2ecf20Sopenharmony_ci			__skb_queue_purge(&sk->sk_receive_queue);
5778c2ecf20Sopenharmony_ci			tipc_sk_respond(sk, skb, error);
5788c2ecf20Sopenharmony_ci			break;
5798c2ecf20Sopenharmony_ci		}
5808c2ecf20Sopenharmony_ci		skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
5818c2ecf20Sopenharmony_ci				      TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode,
5828c2ecf20Sopenharmony_ci				      tsk_own_node(tsk), tsk_peer_port(tsk),
5838c2ecf20Sopenharmony_ci				      tsk->portid, error);
5848c2ecf20Sopenharmony_ci		if (skb)
5858c2ecf20Sopenharmony_ci			tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
5868c2ecf20Sopenharmony_ci		break;
5878c2ecf20Sopenharmony_ci	case TIPC_LISTEN:
5888c2ecf20Sopenharmony_ci		/* Reject all SYN messages */
5898c2ecf20Sopenharmony_ci		tsk_rej_rx_queue(sk, error);
5908c2ecf20Sopenharmony_ci		break;
5918c2ecf20Sopenharmony_ci	default:
5928c2ecf20Sopenharmony_ci		__skb_queue_purge(&sk->sk_receive_queue);
5938c2ecf20Sopenharmony_ci		break;
5948c2ecf20Sopenharmony_ci	}
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci/**
5988c2ecf20Sopenharmony_ci * tipc_release - destroy a TIPC socket
5998c2ecf20Sopenharmony_ci * @sock: socket to destroy
6008c2ecf20Sopenharmony_ci *
6018c2ecf20Sopenharmony_ci * This routine cleans up any messages that are still queued on the socket.
6028c2ecf20Sopenharmony_ci * For DGRAM and RDM socket types, all queued messages are rejected.
6038c2ecf20Sopenharmony_ci * For SEQPACKET and STREAM socket types, the first message is rejected
6048c2ecf20Sopenharmony_ci * and any others are discarded.  (If the first message on a STREAM socket
6058c2ecf20Sopenharmony_ci * is partially-read, it is discarded and the next one is rejected instead.)
6068c2ecf20Sopenharmony_ci *
6078c2ecf20Sopenharmony_ci * NOTE: Rejected messages are not necessarily returned to the sender!  They
6088c2ecf20Sopenharmony_ci * are returned or discarded according to the "destination droppable" setting
6098c2ecf20Sopenharmony_ci * specified for the message by the sender.
6108c2ecf20Sopenharmony_ci *
6118c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
6128c2ecf20Sopenharmony_ci */
6138c2ecf20Sopenharmony_cistatic int tipc_release(struct socket *sock)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
6168c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	/*
6198c2ecf20Sopenharmony_ci	 * Exit if socket isn't fully initialized (occurs when a failed accept()
6208c2ecf20Sopenharmony_ci	 * releases a pre-allocated child socket that was never used)
6218c2ecf20Sopenharmony_ci	 */
6228c2ecf20Sopenharmony_ci	if (sk == NULL)
6238c2ecf20Sopenharmony_ci		return 0;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	tsk = tipc_sk(sk);
6268c2ecf20Sopenharmony_ci	lock_sock(sk);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	trace_tipc_sk_release(sk, NULL, TIPC_DUMP_ALL, " ");
6298c2ecf20Sopenharmony_ci	__tipc_shutdown(sock, TIPC_ERR_NO_PORT);
6308c2ecf20Sopenharmony_ci	sk->sk_shutdown = SHUTDOWN_MASK;
6318c2ecf20Sopenharmony_ci	tipc_sk_leave(tsk);
6328c2ecf20Sopenharmony_ci	tipc_sk_withdraw(tsk, 0, NULL);
6338c2ecf20Sopenharmony_ci	__skb_queue_purge(&tsk->mc_method.deferredq);
6348c2ecf20Sopenharmony_ci	sk_stop_timer(sk, &sk->sk_timer);
6358c2ecf20Sopenharmony_ci	tipc_sk_remove(tsk);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	sock_orphan(sk);
6388c2ecf20Sopenharmony_ci	/* Reject any messages that accumulated in backlog queue */
6398c2ecf20Sopenharmony_ci	release_sock(sk);
6408c2ecf20Sopenharmony_ci	tipc_dest_list_purge(&tsk->cong_links);
6418c2ecf20Sopenharmony_ci	tsk->cong_link_cnt = 0;
6428c2ecf20Sopenharmony_ci	call_rcu(&tsk->rcu, tipc_sk_callback);
6438c2ecf20Sopenharmony_ci	sock->sk = NULL;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	return 0;
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci/**
6498c2ecf20Sopenharmony_ci * tipc_bind - associate or disassocate TIPC name(s) with a socket
6508c2ecf20Sopenharmony_ci * @sock: socket structure
6518c2ecf20Sopenharmony_ci * @uaddr: socket address describing name(s) and desired operation
6528c2ecf20Sopenharmony_ci * @uaddr_len: size of socket address data structure
6538c2ecf20Sopenharmony_ci *
6548c2ecf20Sopenharmony_ci * Name and name sequence binding is indicated using a positive scope value;
6558c2ecf20Sopenharmony_ci * a negative scope value unbinds the specified name.  Specifying no name
6568c2ecf20Sopenharmony_ci * (i.e. a socket address length of 0) unbinds all names from the socket.
6578c2ecf20Sopenharmony_ci *
6588c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
6598c2ecf20Sopenharmony_ci *
6608c2ecf20Sopenharmony_ci * NOTE: This routine doesn't need to take the socket lock since it doesn't
6618c2ecf20Sopenharmony_ci *       access any non-constant socket information.
6628c2ecf20Sopenharmony_ci */
6638c2ecf20Sopenharmony_cistatic int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
6648c2ecf20Sopenharmony_ci		     int uaddr_len)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
6678c2ecf20Sopenharmony_ci	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
6688c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
6698c2ecf20Sopenharmony_ci	int res = -EINVAL;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	lock_sock(sk);
6728c2ecf20Sopenharmony_ci	if (unlikely(!uaddr_len)) {
6738c2ecf20Sopenharmony_ci		res = tipc_sk_withdraw(tsk, 0, NULL);
6748c2ecf20Sopenharmony_ci		goto exit;
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci	if (tsk->group) {
6778c2ecf20Sopenharmony_ci		res = -EACCES;
6788c2ecf20Sopenharmony_ci		goto exit;
6798c2ecf20Sopenharmony_ci	}
6808c2ecf20Sopenharmony_ci	if (uaddr_len < sizeof(struct sockaddr_tipc)) {
6818c2ecf20Sopenharmony_ci		res = -EINVAL;
6828c2ecf20Sopenharmony_ci		goto exit;
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci	if (addr->family != AF_TIPC) {
6858c2ecf20Sopenharmony_ci		res = -EAFNOSUPPORT;
6868c2ecf20Sopenharmony_ci		goto exit;
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (addr->addrtype == TIPC_ADDR_NAME)
6908c2ecf20Sopenharmony_ci		addr->addr.nameseq.upper = addr->addr.nameseq.lower;
6918c2ecf20Sopenharmony_ci	else if (addr->addrtype != TIPC_ADDR_NAMESEQ) {
6928c2ecf20Sopenharmony_ci		res = -EAFNOSUPPORT;
6938c2ecf20Sopenharmony_ci		goto exit;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) &&
6978c2ecf20Sopenharmony_ci	    (addr->addr.nameseq.type != TIPC_TOP_SRV) &&
6988c2ecf20Sopenharmony_ci	    (addr->addr.nameseq.type != TIPC_CFG_SRV)) {
6998c2ecf20Sopenharmony_ci		res = -EACCES;
7008c2ecf20Sopenharmony_ci		goto exit;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	res = (addr->scope >= 0) ?
7048c2ecf20Sopenharmony_ci		tipc_sk_publish(tsk, addr->scope, &addr->addr.nameseq) :
7058c2ecf20Sopenharmony_ci		tipc_sk_withdraw(tsk, -addr->scope, &addr->addr.nameseq);
7068c2ecf20Sopenharmony_ciexit:
7078c2ecf20Sopenharmony_ci	release_sock(sk);
7088c2ecf20Sopenharmony_ci	return res;
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci/**
7128c2ecf20Sopenharmony_ci * tipc_getname - get port ID of socket or peer socket
7138c2ecf20Sopenharmony_ci * @sock: socket structure
7148c2ecf20Sopenharmony_ci * @uaddr: area for returned socket address
7158c2ecf20Sopenharmony_ci * @peer: 0 = own ID, 1 = current peer ID, 2 = current/former peer ID
7168c2ecf20Sopenharmony_ci *
7178c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
7188c2ecf20Sopenharmony_ci *
7198c2ecf20Sopenharmony_ci * NOTE: This routine doesn't need to take the socket lock since it only
7208c2ecf20Sopenharmony_ci *       accesses socket information that is unchanging (or which changes in
7218c2ecf20Sopenharmony_ci *       a completely predictable manner).
7228c2ecf20Sopenharmony_ci */
7238c2ecf20Sopenharmony_cistatic int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
7248c2ecf20Sopenharmony_ci			int peer)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
7278c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
7288c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	memset(addr, 0, sizeof(*addr));
7318c2ecf20Sopenharmony_ci	if (peer) {
7328c2ecf20Sopenharmony_ci		if ((!tipc_sk_connected(sk)) &&
7338c2ecf20Sopenharmony_ci		    ((peer != 2) || (sk->sk_state != TIPC_DISCONNECTING)))
7348c2ecf20Sopenharmony_ci			return -ENOTCONN;
7358c2ecf20Sopenharmony_ci		addr->addr.id.ref = tsk_peer_port(tsk);
7368c2ecf20Sopenharmony_ci		addr->addr.id.node = tsk_peer_node(tsk);
7378c2ecf20Sopenharmony_ci	} else {
7388c2ecf20Sopenharmony_ci		addr->addr.id.ref = tsk->portid;
7398c2ecf20Sopenharmony_ci		addr->addr.id.node = tipc_own_addr(sock_net(sk));
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	addr->addrtype = TIPC_ADDR_ID;
7438c2ecf20Sopenharmony_ci	addr->family = AF_TIPC;
7448c2ecf20Sopenharmony_ci	addr->scope = 0;
7458c2ecf20Sopenharmony_ci	addr->addr.name.domain = 0;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	return sizeof(*addr);
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci/**
7518c2ecf20Sopenharmony_ci * tipc_poll - read and possibly block on pollmask
7528c2ecf20Sopenharmony_ci * @file: file structure associated with the socket
7538c2ecf20Sopenharmony_ci * @sock: socket for which to calculate the poll bits
7548c2ecf20Sopenharmony_ci * @wait: ???
7558c2ecf20Sopenharmony_ci *
7568c2ecf20Sopenharmony_ci * Returns pollmask value
7578c2ecf20Sopenharmony_ci *
7588c2ecf20Sopenharmony_ci * COMMENTARY:
7598c2ecf20Sopenharmony_ci * It appears that the usual socket locking mechanisms are not useful here
7608c2ecf20Sopenharmony_ci * since the pollmask info is potentially out-of-date the moment this routine
7618c2ecf20Sopenharmony_ci * exits.  TCP and other protocols seem to rely on higher level poll routines
7628c2ecf20Sopenharmony_ci * to handle any preventable race conditions, so TIPC will do the same ...
7638c2ecf20Sopenharmony_ci *
7648c2ecf20Sopenharmony_ci * IMPORTANT: The fact that a read or write operation is indicated does NOT
7658c2ecf20Sopenharmony_ci * imply that the operation will succeed, merely that it should be performed
7668c2ecf20Sopenharmony_ci * and will not block.
7678c2ecf20Sopenharmony_ci */
7688c2ecf20Sopenharmony_cistatic __poll_t tipc_poll(struct file *file, struct socket *sock,
7698c2ecf20Sopenharmony_ci			      poll_table *wait)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
7728c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
7738c2ecf20Sopenharmony_ci	__poll_t revents = 0;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	sock_poll_wait(file, sock, wait);
7768c2ecf20Sopenharmony_ci	trace_tipc_sk_poll(sk, NULL, TIPC_DUMP_ALL, " ");
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (sk->sk_shutdown & RCV_SHUTDOWN)
7798c2ecf20Sopenharmony_ci		revents |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM;
7808c2ecf20Sopenharmony_ci	if (sk->sk_shutdown == SHUTDOWN_MASK)
7818c2ecf20Sopenharmony_ci		revents |= EPOLLHUP;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
7848c2ecf20Sopenharmony_ci	case TIPC_ESTABLISHED:
7858c2ecf20Sopenharmony_ci		if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk))
7868c2ecf20Sopenharmony_ci			revents |= EPOLLOUT;
7878c2ecf20Sopenharmony_ci		fallthrough;
7888c2ecf20Sopenharmony_ci	case TIPC_LISTEN:
7898c2ecf20Sopenharmony_ci	case TIPC_CONNECTING:
7908c2ecf20Sopenharmony_ci		if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
7918c2ecf20Sopenharmony_ci			revents |= EPOLLIN | EPOLLRDNORM;
7928c2ecf20Sopenharmony_ci		break;
7938c2ecf20Sopenharmony_ci	case TIPC_OPEN:
7948c2ecf20Sopenharmony_ci		if (tsk->group_is_open && !tsk->cong_link_cnt)
7958c2ecf20Sopenharmony_ci			revents |= EPOLLOUT;
7968c2ecf20Sopenharmony_ci		if (!tipc_sk_type_connectionless(sk))
7978c2ecf20Sopenharmony_ci			break;
7988c2ecf20Sopenharmony_ci		if (skb_queue_empty_lockless(&sk->sk_receive_queue))
7998c2ecf20Sopenharmony_ci			break;
8008c2ecf20Sopenharmony_ci		revents |= EPOLLIN | EPOLLRDNORM;
8018c2ecf20Sopenharmony_ci		break;
8028c2ecf20Sopenharmony_ci	case TIPC_DISCONNECTING:
8038c2ecf20Sopenharmony_ci		revents = EPOLLIN | EPOLLRDNORM | EPOLLHUP;
8048c2ecf20Sopenharmony_ci		break;
8058c2ecf20Sopenharmony_ci	}
8068c2ecf20Sopenharmony_ci	return revents;
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci/**
8108c2ecf20Sopenharmony_ci * tipc_sendmcast - send multicast message
8118c2ecf20Sopenharmony_ci * @sock: socket structure
8128c2ecf20Sopenharmony_ci * @seq: destination address
8138c2ecf20Sopenharmony_ci * @msg: message to send
8148c2ecf20Sopenharmony_ci * @dlen: length of data to send
8158c2ecf20Sopenharmony_ci * @timeout: timeout to wait for wakeup
8168c2ecf20Sopenharmony_ci *
8178c2ecf20Sopenharmony_ci * Called from function tipc_sendmsg(), which has done all sanity checks
8188c2ecf20Sopenharmony_ci * Returns the number of bytes sent on success, or errno
8198c2ecf20Sopenharmony_ci */
8208c2ecf20Sopenharmony_cistatic int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,
8218c2ecf20Sopenharmony_ci			  struct msghdr *msg, size_t dlen, long timeout)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
8248c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
8258c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = &tsk->phdr;
8268c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
8278c2ecf20Sopenharmony_ci	int mtu = tipc_bcast_get_mtu(net);
8288c2ecf20Sopenharmony_ci	struct tipc_mc_method *method = &tsk->mc_method;
8298c2ecf20Sopenharmony_ci	struct sk_buff_head pkts;
8308c2ecf20Sopenharmony_ci	struct tipc_nlist dsts;
8318c2ecf20Sopenharmony_ci	int rc;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (tsk->group)
8348c2ecf20Sopenharmony_ci		return -EACCES;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	/* Block or return if any destination link is congested */
8378c2ecf20Sopenharmony_ci	rc = tipc_wait_for_cond(sock, &timeout, !tsk->cong_link_cnt);
8388c2ecf20Sopenharmony_ci	if (unlikely(rc))
8398c2ecf20Sopenharmony_ci		return rc;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	/* Lookup destination nodes */
8428c2ecf20Sopenharmony_ci	tipc_nlist_init(&dsts, tipc_own_addr(net));
8438c2ecf20Sopenharmony_ci	tipc_nametbl_lookup_dst_nodes(net, seq->type, seq->lower,
8448c2ecf20Sopenharmony_ci				      seq->upper, &dsts);
8458c2ecf20Sopenharmony_ci	if (!dsts.local && !dsts.remote)
8468c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/* Build message header */
8498c2ecf20Sopenharmony_ci	msg_set_type(hdr, TIPC_MCAST_MSG);
8508c2ecf20Sopenharmony_ci	msg_set_hdr_sz(hdr, MCAST_H_SIZE);
8518c2ecf20Sopenharmony_ci	msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE);
8528c2ecf20Sopenharmony_ci	msg_set_destport(hdr, 0);
8538c2ecf20Sopenharmony_ci	msg_set_destnode(hdr, 0);
8548c2ecf20Sopenharmony_ci	msg_set_nametype(hdr, seq->type);
8558c2ecf20Sopenharmony_ci	msg_set_namelower(hdr, seq->lower);
8568c2ecf20Sopenharmony_ci	msg_set_nameupper(hdr, seq->upper);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	/* Build message as chain of buffers */
8598c2ecf20Sopenharmony_ci	__skb_queue_head_init(&pkts);
8608c2ecf20Sopenharmony_ci	rc = tipc_msg_build(hdr, msg, 0, dlen, mtu, &pkts);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	/* Send message if build was successful */
8638c2ecf20Sopenharmony_ci	if (unlikely(rc == dlen)) {
8648c2ecf20Sopenharmony_ci		trace_tipc_sk_sendmcast(sk, skb_peek(&pkts),
8658c2ecf20Sopenharmony_ci					TIPC_DUMP_SK_SNDQ, " ");
8668c2ecf20Sopenharmony_ci		rc = tipc_mcast_xmit(net, &pkts, method, &dsts,
8678c2ecf20Sopenharmony_ci				     &tsk->cong_link_cnt);
8688c2ecf20Sopenharmony_ci	}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	tipc_nlist_purge(&dsts);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	return rc ? rc : dlen;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci/**
8768c2ecf20Sopenharmony_ci * tipc_send_group_msg - send a message to a member in the group
8778c2ecf20Sopenharmony_ci * @net: network namespace
8788c2ecf20Sopenharmony_ci * @m: message to send
8798c2ecf20Sopenharmony_ci * @mb: group member
8808c2ecf20Sopenharmony_ci * @dnode: destination node
8818c2ecf20Sopenharmony_ci * @dport: destination port
8828c2ecf20Sopenharmony_ci * @dlen: total length of message data
8838c2ecf20Sopenharmony_ci */
8848c2ecf20Sopenharmony_cistatic int tipc_send_group_msg(struct net *net, struct tipc_sock *tsk,
8858c2ecf20Sopenharmony_ci			       struct msghdr *m, struct tipc_member *mb,
8868c2ecf20Sopenharmony_ci			       u32 dnode, u32 dport, int dlen)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	u16 bc_snd_nxt = tipc_group_bc_snd_nxt(tsk->group);
8898c2ecf20Sopenharmony_ci	struct tipc_mc_method *method = &tsk->mc_method;
8908c2ecf20Sopenharmony_ci	int blks = tsk_blocks(GROUP_H_SIZE + dlen);
8918c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = &tsk->phdr;
8928c2ecf20Sopenharmony_ci	struct sk_buff_head pkts;
8938c2ecf20Sopenharmony_ci	int mtu, rc;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* Complete message header */
8968c2ecf20Sopenharmony_ci	msg_set_type(hdr, TIPC_GRP_UCAST_MSG);
8978c2ecf20Sopenharmony_ci	msg_set_hdr_sz(hdr, GROUP_H_SIZE);
8988c2ecf20Sopenharmony_ci	msg_set_destport(hdr, dport);
8998c2ecf20Sopenharmony_ci	msg_set_destnode(hdr, dnode);
9008c2ecf20Sopenharmony_ci	msg_set_grp_bc_seqno(hdr, bc_snd_nxt);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	/* Build message as chain of buffers */
9038c2ecf20Sopenharmony_ci	__skb_queue_head_init(&pkts);
9048c2ecf20Sopenharmony_ci	mtu = tipc_node_get_mtu(net, dnode, tsk->portid, false);
9058c2ecf20Sopenharmony_ci	rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts);
9068c2ecf20Sopenharmony_ci	if (unlikely(rc != dlen))
9078c2ecf20Sopenharmony_ci		return rc;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* Send message */
9108c2ecf20Sopenharmony_ci	rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);
9118c2ecf20Sopenharmony_ci	if (unlikely(rc == -ELINKCONG)) {
9128c2ecf20Sopenharmony_ci		tipc_dest_push(&tsk->cong_links, dnode, 0);
9138c2ecf20Sopenharmony_ci		tsk->cong_link_cnt++;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	/* Update send window */
9178c2ecf20Sopenharmony_ci	tipc_group_update_member(mb, blks);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	/* A broadcast sent within next EXPIRE period must follow same path */
9208c2ecf20Sopenharmony_ci	method->rcast = true;
9218c2ecf20Sopenharmony_ci	method->mandatory = true;
9228c2ecf20Sopenharmony_ci	return dlen;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci/**
9268c2ecf20Sopenharmony_ci * tipc_send_group_unicast - send message to a member in the group
9278c2ecf20Sopenharmony_ci * @sock: socket structure
9288c2ecf20Sopenharmony_ci * @m: message to send
9298c2ecf20Sopenharmony_ci * @dlen: total length of message data
9308c2ecf20Sopenharmony_ci * @timeout: timeout to wait for wakeup
9318c2ecf20Sopenharmony_ci *
9328c2ecf20Sopenharmony_ci * Called from function tipc_sendmsg(), which has done all sanity checks
9338c2ecf20Sopenharmony_ci * Returns the number of bytes sent on success, or errno
9348c2ecf20Sopenharmony_ci */
9358c2ecf20Sopenharmony_cistatic int tipc_send_group_unicast(struct socket *sock, struct msghdr *m,
9368c2ecf20Sopenharmony_ci				   int dlen, long timeout)
9378c2ecf20Sopenharmony_ci{
9388c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
9398c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
9408c2ecf20Sopenharmony_ci	int blks = tsk_blocks(GROUP_H_SIZE + dlen);
9418c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
9428c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
9438c2ecf20Sopenharmony_ci	struct tipc_member *mb = NULL;
9448c2ecf20Sopenharmony_ci	u32 node, port;
9458c2ecf20Sopenharmony_ci	int rc;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	node = dest->addr.id.node;
9488c2ecf20Sopenharmony_ci	port = dest->addr.id.ref;
9498c2ecf20Sopenharmony_ci	if (!port && !node)
9508c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	/* Block or return if destination link or member is congested */
9538c2ecf20Sopenharmony_ci	rc = tipc_wait_for_cond(sock, &timeout,
9548c2ecf20Sopenharmony_ci				!tipc_dest_find(&tsk->cong_links, node, 0) &&
9558c2ecf20Sopenharmony_ci				tsk->group &&
9568c2ecf20Sopenharmony_ci				!tipc_group_cong(tsk->group, node, port, blks,
9578c2ecf20Sopenharmony_ci						 &mb));
9588c2ecf20Sopenharmony_ci	if (unlikely(rc))
9598c2ecf20Sopenharmony_ci		return rc;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (unlikely(!mb))
9628c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	rc = tipc_send_group_msg(net, tsk, m, mb, node, port, dlen);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	return rc ? rc : dlen;
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci/**
9708c2ecf20Sopenharmony_ci * tipc_send_group_anycast - send message to any member with given identity
9718c2ecf20Sopenharmony_ci * @sock: socket structure
9728c2ecf20Sopenharmony_ci * @m: message to send
9738c2ecf20Sopenharmony_ci * @dlen: total length of message data
9748c2ecf20Sopenharmony_ci * @timeout: timeout to wait for wakeup
9758c2ecf20Sopenharmony_ci *
9768c2ecf20Sopenharmony_ci * Called from function tipc_sendmsg(), which has done all sanity checks
9778c2ecf20Sopenharmony_ci * Returns the number of bytes sent on success, or errno
9788c2ecf20Sopenharmony_ci */
9798c2ecf20Sopenharmony_cistatic int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,
9808c2ecf20Sopenharmony_ci				   int dlen, long timeout)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
9838c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
9848c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
9858c2ecf20Sopenharmony_ci	struct list_head *cong_links = &tsk->cong_links;
9868c2ecf20Sopenharmony_ci	int blks = tsk_blocks(GROUP_H_SIZE + dlen);
9878c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = &tsk->phdr;
9888c2ecf20Sopenharmony_ci	struct tipc_member *first = NULL;
9898c2ecf20Sopenharmony_ci	struct tipc_member *mbr = NULL;
9908c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
9918c2ecf20Sopenharmony_ci	u32 node, port, exclude;
9928c2ecf20Sopenharmony_ci	struct list_head dsts;
9938c2ecf20Sopenharmony_ci	u32 type, inst, scope;
9948c2ecf20Sopenharmony_ci	int lookups = 0;
9958c2ecf20Sopenharmony_ci	int dstcnt, rc;
9968c2ecf20Sopenharmony_ci	bool cong;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dsts);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	type = msg_nametype(hdr);
10018c2ecf20Sopenharmony_ci	inst = dest->addr.name.name.instance;
10028c2ecf20Sopenharmony_ci	scope = msg_lookup_scope(hdr);
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	while (++lookups < 4) {
10058c2ecf20Sopenharmony_ci		exclude = tipc_group_exclude(tsk->group);
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci		first = NULL;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		/* Look for a non-congested destination member, if any */
10108c2ecf20Sopenharmony_ci		while (1) {
10118c2ecf20Sopenharmony_ci			if (!tipc_nametbl_lookup(net, type, inst, scope, &dsts,
10128c2ecf20Sopenharmony_ci						 &dstcnt, exclude, false))
10138c2ecf20Sopenharmony_ci				return -EHOSTUNREACH;
10148c2ecf20Sopenharmony_ci			tipc_dest_pop(&dsts, &node, &port);
10158c2ecf20Sopenharmony_ci			cong = tipc_group_cong(tsk->group, node, port, blks,
10168c2ecf20Sopenharmony_ci					       &mbr);
10178c2ecf20Sopenharmony_ci			if (!cong)
10188c2ecf20Sopenharmony_ci				break;
10198c2ecf20Sopenharmony_ci			if (mbr == first)
10208c2ecf20Sopenharmony_ci				break;
10218c2ecf20Sopenharmony_ci			if (!first)
10228c2ecf20Sopenharmony_ci				first = mbr;
10238c2ecf20Sopenharmony_ci		}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci		/* Start over if destination was not in member list */
10268c2ecf20Sopenharmony_ci		if (unlikely(!mbr))
10278c2ecf20Sopenharmony_ci			continue;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci		if (likely(!cong && !tipc_dest_find(cong_links, node, 0)))
10308c2ecf20Sopenharmony_ci			break;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci		/* Block or return if destination link or member is congested */
10338c2ecf20Sopenharmony_ci		rc = tipc_wait_for_cond(sock, &timeout,
10348c2ecf20Sopenharmony_ci					!tipc_dest_find(cong_links, node, 0) &&
10358c2ecf20Sopenharmony_ci					tsk->group &&
10368c2ecf20Sopenharmony_ci					!tipc_group_cong(tsk->group, node, port,
10378c2ecf20Sopenharmony_ci							 blks, &mbr));
10388c2ecf20Sopenharmony_ci		if (unlikely(rc))
10398c2ecf20Sopenharmony_ci			return rc;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci		/* Send, unless destination disappeared while waiting */
10428c2ecf20Sopenharmony_ci		if (likely(mbr))
10438c2ecf20Sopenharmony_ci			break;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	if (unlikely(lookups >= 4))
10478c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	rc = tipc_send_group_msg(net, tsk, m, mbr, node, port, dlen);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	return rc ? rc : dlen;
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci/**
10558c2ecf20Sopenharmony_ci * tipc_send_group_bcast - send message to all members in communication group
10568c2ecf20Sopenharmony_ci * @sock: socket structure
10578c2ecf20Sopenharmony_ci * @m: message to send
10588c2ecf20Sopenharmony_ci * @dlen: total length of message data
10598c2ecf20Sopenharmony_ci * @timeout: timeout to wait for wakeup
10608c2ecf20Sopenharmony_ci *
10618c2ecf20Sopenharmony_ci * Called from function tipc_sendmsg(), which has done all sanity checks
10628c2ecf20Sopenharmony_ci * Returns the number of bytes sent on success, or errno
10638c2ecf20Sopenharmony_ci */
10648c2ecf20Sopenharmony_cistatic int tipc_send_group_bcast(struct socket *sock, struct msghdr *m,
10658c2ecf20Sopenharmony_ci				 int dlen, long timeout)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
10688c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
10698c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
10708c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
10718c2ecf20Sopenharmony_ci	struct tipc_nlist *dsts;
10728c2ecf20Sopenharmony_ci	struct tipc_mc_method *method = &tsk->mc_method;
10738c2ecf20Sopenharmony_ci	bool ack = method->mandatory && method->rcast;
10748c2ecf20Sopenharmony_ci	int blks = tsk_blocks(MCAST_H_SIZE + dlen);
10758c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = &tsk->phdr;
10768c2ecf20Sopenharmony_ci	int mtu = tipc_bcast_get_mtu(net);
10778c2ecf20Sopenharmony_ci	struct sk_buff_head pkts;
10788c2ecf20Sopenharmony_ci	int rc = -EHOSTUNREACH;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	/* Block or return if any destination link or member is congested */
10818c2ecf20Sopenharmony_ci	rc = tipc_wait_for_cond(sock, &timeout,
10828c2ecf20Sopenharmony_ci				!tsk->cong_link_cnt && tsk->group &&
10838c2ecf20Sopenharmony_ci				!tipc_group_bc_cong(tsk->group, blks));
10848c2ecf20Sopenharmony_ci	if (unlikely(rc))
10858c2ecf20Sopenharmony_ci		return rc;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	dsts = tipc_group_dests(tsk->group);
10888c2ecf20Sopenharmony_ci	if (!dsts->local && !dsts->remote)
10898c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	/* Complete message header */
10928c2ecf20Sopenharmony_ci	if (dest) {
10938c2ecf20Sopenharmony_ci		msg_set_type(hdr, TIPC_GRP_MCAST_MSG);
10948c2ecf20Sopenharmony_ci		msg_set_nameinst(hdr, dest->addr.name.name.instance);
10958c2ecf20Sopenharmony_ci	} else {
10968c2ecf20Sopenharmony_ci		msg_set_type(hdr, TIPC_GRP_BCAST_MSG);
10978c2ecf20Sopenharmony_ci		msg_set_nameinst(hdr, 0);
10988c2ecf20Sopenharmony_ci	}
10998c2ecf20Sopenharmony_ci	msg_set_hdr_sz(hdr, GROUP_H_SIZE);
11008c2ecf20Sopenharmony_ci	msg_set_destport(hdr, 0);
11018c2ecf20Sopenharmony_ci	msg_set_destnode(hdr, 0);
11028c2ecf20Sopenharmony_ci	msg_set_grp_bc_seqno(hdr, tipc_group_bc_snd_nxt(tsk->group));
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	/* Avoid getting stuck with repeated forced replicasts */
11058c2ecf20Sopenharmony_ci	msg_set_grp_bc_ack_req(hdr, ack);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	/* Build message as chain of buffers */
11088c2ecf20Sopenharmony_ci	__skb_queue_head_init(&pkts);
11098c2ecf20Sopenharmony_ci	rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts);
11108c2ecf20Sopenharmony_ci	if (unlikely(rc != dlen))
11118c2ecf20Sopenharmony_ci		return rc;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	/* Send message */
11148c2ecf20Sopenharmony_ci	rc = tipc_mcast_xmit(net, &pkts, method, dsts, &tsk->cong_link_cnt);
11158c2ecf20Sopenharmony_ci	if (unlikely(rc))
11168c2ecf20Sopenharmony_ci		return rc;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	/* Update broadcast sequence number and send windows */
11198c2ecf20Sopenharmony_ci	tipc_group_update_bc_members(tsk->group, blks, ack);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/* Broadcast link is now free to choose method for next broadcast */
11228c2ecf20Sopenharmony_ci	method->mandatory = false;
11238c2ecf20Sopenharmony_ci	method->expires = jiffies;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	return dlen;
11268c2ecf20Sopenharmony_ci}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci/**
11298c2ecf20Sopenharmony_ci * tipc_send_group_mcast - send message to all members with given identity
11308c2ecf20Sopenharmony_ci * @sock: socket structure
11318c2ecf20Sopenharmony_ci * @m: message to send
11328c2ecf20Sopenharmony_ci * @dlen: total length of message data
11338c2ecf20Sopenharmony_ci * @timeout: timeout to wait for wakeup
11348c2ecf20Sopenharmony_ci *
11358c2ecf20Sopenharmony_ci * Called from function tipc_sendmsg(), which has done all sanity checks
11368c2ecf20Sopenharmony_ci * Returns the number of bytes sent on success, or errno
11378c2ecf20Sopenharmony_ci */
11388c2ecf20Sopenharmony_cistatic int tipc_send_group_mcast(struct socket *sock, struct msghdr *m,
11398c2ecf20Sopenharmony_ci				 int dlen, long timeout)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
11428c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
11438c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
11448c2ecf20Sopenharmony_ci	struct tipc_group *grp = tsk->group;
11458c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = &tsk->phdr;
11468c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
11478c2ecf20Sopenharmony_ci	u32 type, inst, scope, exclude;
11488c2ecf20Sopenharmony_ci	struct list_head dsts;
11498c2ecf20Sopenharmony_ci	u32 dstcnt;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dsts);
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	type = msg_nametype(hdr);
11548c2ecf20Sopenharmony_ci	inst = dest->addr.name.name.instance;
11558c2ecf20Sopenharmony_ci	scope = msg_lookup_scope(hdr);
11568c2ecf20Sopenharmony_ci	exclude = tipc_group_exclude(grp);
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	if (!tipc_nametbl_lookup(net, type, inst, scope, &dsts,
11598c2ecf20Sopenharmony_ci				 &dstcnt, exclude, true))
11608c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if (dstcnt == 1) {
11638c2ecf20Sopenharmony_ci		tipc_dest_pop(&dsts, &dest->addr.id.node, &dest->addr.id.ref);
11648c2ecf20Sopenharmony_ci		return tipc_send_group_unicast(sock, m, dlen, timeout);
11658c2ecf20Sopenharmony_ci	}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	tipc_dest_list_purge(&dsts);
11688c2ecf20Sopenharmony_ci	return tipc_send_group_bcast(sock, m, dlen, timeout);
11698c2ecf20Sopenharmony_ci}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci/**
11728c2ecf20Sopenharmony_ci * tipc_sk_mcast_rcv - Deliver multicast messages to all destination sockets
11738c2ecf20Sopenharmony_ci * @arrvq: queue with arriving messages, to be cloned after destination lookup
11748c2ecf20Sopenharmony_ci * @inputq: queue with cloned messages, delivered to socket after dest lookup
11758c2ecf20Sopenharmony_ci *
11768c2ecf20Sopenharmony_ci * Multi-threaded: parallel calls with reference to same queues may occur
11778c2ecf20Sopenharmony_ci */
11788c2ecf20Sopenharmony_civoid tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
11798c2ecf20Sopenharmony_ci		       struct sk_buff_head *inputq)
11808c2ecf20Sopenharmony_ci{
11818c2ecf20Sopenharmony_ci	u32 self = tipc_own_addr(net);
11828c2ecf20Sopenharmony_ci	u32 type, lower, upper, scope;
11838c2ecf20Sopenharmony_ci	struct sk_buff *skb, *_skb;
11848c2ecf20Sopenharmony_ci	u32 portid, onode;
11858c2ecf20Sopenharmony_ci	struct sk_buff_head tmpq;
11868c2ecf20Sopenharmony_ci	struct list_head dports;
11878c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
11888c2ecf20Sopenharmony_ci	int user, mtyp, hlen;
11898c2ecf20Sopenharmony_ci	bool exact;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	__skb_queue_head_init(&tmpq);
11928c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dports);
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	skb = tipc_skb_peek(arrvq, &inputq->lock);
11958c2ecf20Sopenharmony_ci	for (; skb; skb = tipc_skb_peek(arrvq, &inputq->lock)) {
11968c2ecf20Sopenharmony_ci		hdr = buf_msg(skb);
11978c2ecf20Sopenharmony_ci		user = msg_user(hdr);
11988c2ecf20Sopenharmony_ci		mtyp = msg_type(hdr);
11998c2ecf20Sopenharmony_ci		hlen = skb_headroom(skb) + msg_hdr_sz(hdr);
12008c2ecf20Sopenharmony_ci		onode = msg_orignode(hdr);
12018c2ecf20Sopenharmony_ci		type = msg_nametype(hdr);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci		if (mtyp == TIPC_GRP_UCAST_MSG || user == GROUP_PROTOCOL) {
12048c2ecf20Sopenharmony_ci			spin_lock_bh(&inputq->lock);
12058c2ecf20Sopenharmony_ci			if (skb_peek(arrvq) == skb) {
12068c2ecf20Sopenharmony_ci				__skb_dequeue(arrvq);
12078c2ecf20Sopenharmony_ci				__skb_queue_tail(inputq, skb);
12088c2ecf20Sopenharmony_ci			}
12098c2ecf20Sopenharmony_ci			kfree_skb(skb);
12108c2ecf20Sopenharmony_ci			spin_unlock_bh(&inputq->lock);
12118c2ecf20Sopenharmony_ci			continue;
12128c2ecf20Sopenharmony_ci		}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci		/* Group messages require exact scope match */
12158c2ecf20Sopenharmony_ci		if (msg_in_group(hdr)) {
12168c2ecf20Sopenharmony_ci			lower = 0;
12178c2ecf20Sopenharmony_ci			upper = ~0;
12188c2ecf20Sopenharmony_ci			scope = msg_lookup_scope(hdr);
12198c2ecf20Sopenharmony_ci			exact = true;
12208c2ecf20Sopenharmony_ci		} else {
12218c2ecf20Sopenharmony_ci			/* TIPC_NODE_SCOPE means "any scope" in this context */
12228c2ecf20Sopenharmony_ci			if (onode == self)
12238c2ecf20Sopenharmony_ci				scope = TIPC_NODE_SCOPE;
12248c2ecf20Sopenharmony_ci			else
12258c2ecf20Sopenharmony_ci				scope = TIPC_CLUSTER_SCOPE;
12268c2ecf20Sopenharmony_ci			exact = false;
12278c2ecf20Sopenharmony_ci			lower = msg_namelower(hdr);
12288c2ecf20Sopenharmony_ci			upper = msg_nameupper(hdr);
12298c2ecf20Sopenharmony_ci		}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci		/* Create destination port list: */
12328c2ecf20Sopenharmony_ci		tipc_nametbl_mc_lookup(net, type, lower, upper,
12338c2ecf20Sopenharmony_ci				       scope, exact, &dports);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci		/* Clone message per destination */
12368c2ecf20Sopenharmony_ci		while (tipc_dest_pop(&dports, NULL, &portid)) {
12378c2ecf20Sopenharmony_ci			_skb = __pskb_copy(skb, hlen, GFP_ATOMIC);
12388c2ecf20Sopenharmony_ci			if (_skb) {
12398c2ecf20Sopenharmony_ci				msg_set_destport(buf_msg(_skb), portid);
12408c2ecf20Sopenharmony_ci				__skb_queue_tail(&tmpq, _skb);
12418c2ecf20Sopenharmony_ci				continue;
12428c2ecf20Sopenharmony_ci			}
12438c2ecf20Sopenharmony_ci			pr_warn("Failed to clone mcast rcv buffer\n");
12448c2ecf20Sopenharmony_ci		}
12458c2ecf20Sopenharmony_ci		/* Append to inputq if not already done by other thread */
12468c2ecf20Sopenharmony_ci		spin_lock_bh(&inputq->lock);
12478c2ecf20Sopenharmony_ci		if (skb_peek(arrvq) == skb) {
12488c2ecf20Sopenharmony_ci			skb_queue_splice_tail_init(&tmpq, inputq);
12498c2ecf20Sopenharmony_ci			/* Decrease the skb's refcnt as increasing in the
12508c2ecf20Sopenharmony_ci			 * function tipc_skb_peek
12518c2ecf20Sopenharmony_ci			 */
12528c2ecf20Sopenharmony_ci			kfree_skb(__skb_dequeue(arrvq));
12538c2ecf20Sopenharmony_ci		}
12548c2ecf20Sopenharmony_ci		spin_unlock_bh(&inputq->lock);
12558c2ecf20Sopenharmony_ci		__skb_queue_purge(&tmpq);
12568c2ecf20Sopenharmony_ci		kfree_skb(skb);
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci	tipc_sk_rcv(net, inputq);
12598c2ecf20Sopenharmony_ci}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci/* tipc_sk_push_backlog(): send accumulated buffers in socket write queue
12628c2ecf20Sopenharmony_ci *                         when socket is in Nagle mode
12638c2ecf20Sopenharmony_ci */
12648c2ecf20Sopenharmony_cistatic void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack)
12658c2ecf20Sopenharmony_ci{
12668c2ecf20Sopenharmony_ci	struct sk_buff_head *txq = &tsk->sk.sk_write_queue;
12678c2ecf20Sopenharmony_ci	struct sk_buff *skb = skb_peek_tail(txq);
12688c2ecf20Sopenharmony_ci	struct net *net = sock_net(&tsk->sk);
12698c2ecf20Sopenharmony_ci	u32 dnode = tsk_peer_node(tsk);
12708c2ecf20Sopenharmony_ci	int rc;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	if (nagle_ack) {
12738c2ecf20Sopenharmony_ci		tsk->pkt_cnt += skb_queue_len(txq);
12748c2ecf20Sopenharmony_ci		if (!tsk->pkt_cnt || tsk->msg_acc / tsk->pkt_cnt < 2) {
12758c2ecf20Sopenharmony_ci			tsk->oneway = 0;
12768c2ecf20Sopenharmony_ci			if (tsk->nagle_start < NAGLE_START_MAX)
12778c2ecf20Sopenharmony_ci				tsk->nagle_start *= 2;
12788c2ecf20Sopenharmony_ci			tsk->expect_ack = false;
12798c2ecf20Sopenharmony_ci			pr_debug("tsk %10u: bad nagle %u -> %u, next start %u!\n",
12808c2ecf20Sopenharmony_ci				 tsk->portid, tsk->msg_acc, tsk->pkt_cnt,
12818c2ecf20Sopenharmony_ci				 tsk->nagle_start);
12828c2ecf20Sopenharmony_ci		} else {
12838c2ecf20Sopenharmony_ci			tsk->nagle_start = NAGLE_START_INIT;
12848c2ecf20Sopenharmony_ci			if (skb) {
12858c2ecf20Sopenharmony_ci				msg_set_ack_required(buf_msg(skb));
12868c2ecf20Sopenharmony_ci				tsk->expect_ack = true;
12878c2ecf20Sopenharmony_ci			} else {
12888c2ecf20Sopenharmony_ci				tsk->expect_ack = false;
12898c2ecf20Sopenharmony_ci			}
12908c2ecf20Sopenharmony_ci		}
12918c2ecf20Sopenharmony_ci		tsk->msg_acc = 0;
12928c2ecf20Sopenharmony_ci		tsk->pkt_cnt = 0;
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	if (!skb || tsk->cong_link_cnt)
12968c2ecf20Sopenharmony_ci		return;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	/* Do not send SYN again after congestion */
12998c2ecf20Sopenharmony_ci	if (msg_is_syn(buf_msg(skb)))
13008c2ecf20Sopenharmony_ci		return;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if (tsk->msg_acc)
13038c2ecf20Sopenharmony_ci		tsk->pkt_cnt += skb_queue_len(txq);
13048c2ecf20Sopenharmony_ci	tsk->snt_unacked += tsk->snd_backlog;
13058c2ecf20Sopenharmony_ci	tsk->snd_backlog = 0;
13068c2ecf20Sopenharmony_ci	rc = tipc_node_xmit(net, txq, dnode, tsk->portid);
13078c2ecf20Sopenharmony_ci	if (rc == -ELINKCONG)
13088c2ecf20Sopenharmony_ci		tsk->cong_link_cnt = 1;
13098c2ecf20Sopenharmony_ci}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci/**
13128c2ecf20Sopenharmony_ci * tipc_sk_conn_proto_rcv - receive a connection mng protocol message
13138c2ecf20Sopenharmony_ci * @tsk: receiving socket
13148c2ecf20Sopenharmony_ci * @skb: pointer to message buffer.
13158c2ecf20Sopenharmony_ci */
13168c2ecf20Sopenharmony_cistatic void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
13178c2ecf20Sopenharmony_ci				   struct sk_buff_head *inputq,
13188c2ecf20Sopenharmony_ci				   struct sk_buff_head *xmitq)
13198c2ecf20Sopenharmony_ci{
13208c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = buf_msg(skb);
13218c2ecf20Sopenharmony_ci	u32 onode = tsk_own_node(tsk);
13228c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
13238c2ecf20Sopenharmony_ci	int mtyp = msg_type(hdr);
13248c2ecf20Sopenharmony_ci	bool was_cong;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	/* Ignore if connection cannot be validated: */
13278c2ecf20Sopenharmony_ci	if (!tsk_peer_msg(tsk, hdr)) {
13288c2ecf20Sopenharmony_ci		trace_tipc_sk_drop_msg(sk, skb, TIPC_DUMP_NONE, "@proto_rcv!");
13298c2ecf20Sopenharmony_ci		goto exit;
13308c2ecf20Sopenharmony_ci	}
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	if (unlikely(msg_errcode(hdr))) {
13338c2ecf20Sopenharmony_ci		tipc_set_sk_state(sk, TIPC_DISCONNECTING);
13348c2ecf20Sopenharmony_ci		tipc_node_remove_conn(sock_net(sk), tsk_peer_node(tsk),
13358c2ecf20Sopenharmony_ci				      tsk_peer_port(tsk));
13368c2ecf20Sopenharmony_ci		sk->sk_state_change(sk);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci		/* State change is ignored if socket already awake,
13398c2ecf20Sopenharmony_ci		 * - convert msg to abort msg and add to inqueue
13408c2ecf20Sopenharmony_ci		 */
13418c2ecf20Sopenharmony_ci		msg_set_user(hdr, TIPC_CRITICAL_IMPORTANCE);
13428c2ecf20Sopenharmony_ci		msg_set_type(hdr, TIPC_CONN_MSG);
13438c2ecf20Sopenharmony_ci		msg_set_size(hdr, BASIC_H_SIZE);
13448c2ecf20Sopenharmony_ci		msg_set_hdr_sz(hdr, BASIC_H_SIZE);
13458c2ecf20Sopenharmony_ci		__skb_queue_tail(inputq, skb);
13468c2ecf20Sopenharmony_ci		return;
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	tsk->probe_unacked = false;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	if (mtyp == CONN_PROBE) {
13528c2ecf20Sopenharmony_ci		msg_set_type(hdr, CONN_PROBE_REPLY);
13538c2ecf20Sopenharmony_ci		if (tipc_msg_reverse(onode, &skb, TIPC_OK))
13548c2ecf20Sopenharmony_ci			__skb_queue_tail(xmitq, skb);
13558c2ecf20Sopenharmony_ci		return;
13568c2ecf20Sopenharmony_ci	} else if (mtyp == CONN_ACK) {
13578c2ecf20Sopenharmony_ci		was_cong = tsk_conn_cong(tsk);
13588c2ecf20Sopenharmony_ci		tipc_sk_push_backlog(tsk, msg_nagle_ack(hdr));
13598c2ecf20Sopenharmony_ci		tsk->snt_unacked -= msg_conn_ack(hdr);
13608c2ecf20Sopenharmony_ci		if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL)
13618c2ecf20Sopenharmony_ci			tsk->snd_win = msg_adv_win(hdr);
13628c2ecf20Sopenharmony_ci		if (was_cong && !tsk_conn_cong(tsk))
13638c2ecf20Sopenharmony_ci			sk->sk_write_space(sk);
13648c2ecf20Sopenharmony_ci	} else if (mtyp != CONN_PROBE_REPLY) {
13658c2ecf20Sopenharmony_ci		pr_warn("Received unknown CONN_PROTO msg\n");
13668c2ecf20Sopenharmony_ci	}
13678c2ecf20Sopenharmony_ciexit:
13688c2ecf20Sopenharmony_ci	kfree_skb(skb);
13698c2ecf20Sopenharmony_ci}
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci/**
13728c2ecf20Sopenharmony_ci * tipc_sendmsg - send message in connectionless manner
13738c2ecf20Sopenharmony_ci * @sock: socket structure
13748c2ecf20Sopenharmony_ci * @m: message to send
13758c2ecf20Sopenharmony_ci * @dsz: amount of user data to be sent
13768c2ecf20Sopenharmony_ci *
13778c2ecf20Sopenharmony_ci * Message must have an destination specified explicitly.
13788c2ecf20Sopenharmony_ci * Used for SOCK_RDM and SOCK_DGRAM messages,
13798c2ecf20Sopenharmony_ci * and for 'SYN' messages on SOCK_SEQPACKET and SOCK_STREAM connections.
13808c2ecf20Sopenharmony_ci * (Note: 'SYN+' is prohibited on SOCK_STREAM.)
13818c2ecf20Sopenharmony_ci *
13828c2ecf20Sopenharmony_ci * Returns the number of bytes sent on success, or errno otherwise
13838c2ecf20Sopenharmony_ci */
13848c2ecf20Sopenharmony_cistatic int tipc_sendmsg(struct socket *sock,
13858c2ecf20Sopenharmony_ci			struct msghdr *m, size_t dsz)
13868c2ecf20Sopenharmony_ci{
13878c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
13888c2ecf20Sopenharmony_ci	int ret;
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	lock_sock(sk);
13918c2ecf20Sopenharmony_ci	ret = __tipc_sendmsg(sock, m, dsz);
13928c2ecf20Sopenharmony_ci	release_sock(sk);
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	return ret;
13958c2ecf20Sopenharmony_ci}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_cistatic int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
14008c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
14018c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
14028c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
14038c2ecf20Sopenharmony_ci	long timeout = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
14048c2ecf20Sopenharmony_ci	struct list_head *clinks = &tsk->cong_links;
14058c2ecf20Sopenharmony_ci	bool syn = !tipc_sk_type_connectionless(sk);
14068c2ecf20Sopenharmony_ci	struct tipc_group *grp = tsk->group;
14078c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = &tsk->phdr;
14088c2ecf20Sopenharmony_ci	struct tipc_name_seq *seq;
14098c2ecf20Sopenharmony_ci	struct sk_buff_head pkts;
14108c2ecf20Sopenharmony_ci	u32 dport = 0, dnode = 0;
14118c2ecf20Sopenharmony_ci	u32 type = 0, inst = 0;
14128c2ecf20Sopenharmony_ci	int mtu, rc;
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	if (unlikely(dlen > TIPC_MAX_USER_MSG_SIZE))
14158c2ecf20Sopenharmony_ci		return -EMSGSIZE;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	if (likely(dest)) {
14188c2ecf20Sopenharmony_ci		if (unlikely(m->msg_namelen < sizeof(*dest)))
14198c2ecf20Sopenharmony_ci			return -EINVAL;
14208c2ecf20Sopenharmony_ci		if (unlikely(dest->family != AF_TIPC))
14218c2ecf20Sopenharmony_ci			return -EINVAL;
14228c2ecf20Sopenharmony_ci	}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	if (grp) {
14258c2ecf20Sopenharmony_ci		if (!dest)
14268c2ecf20Sopenharmony_ci			return tipc_send_group_bcast(sock, m, dlen, timeout);
14278c2ecf20Sopenharmony_ci		if (dest->addrtype == TIPC_ADDR_NAME)
14288c2ecf20Sopenharmony_ci			return tipc_send_group_anycast(sock, m, dlen, timeout);
14298c2ecf20Sopenharmony_ci		if (dest->addrtype == TIPC_ADDR_ID)
14308c2ecf20Sopenharmony_ci			return tipc_send_group_unicast(sock, m, dlen, timeout);
14318c2ecf20Sopenharmony_ci		if (dest->addrtype == TIPC_ADDR_MCAST)
14328c2ecf20Sopenharmony_ci			return tipc_send_group_mcast(sock, m, dlen, timeout);
14338c2ecf20Sopenharmony_ci		return -EINVAL;
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	if (unlikely(!dest)) {
14378c2ecf20Sopenharmony_ci		dest = &tsk->peer;
14388c2ecf20Sopenharmony_ci		if (!syn && dest->family != AF_TIPC)
14398c2ecf20Sopenharmony_ci			return -EDESTADDRREQ;
14408c2ecf20Sopenharmony_ci	}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	if (unlikely(syn)) {
14438c2ecf20Sopenharmony_ci		if (sk->sk_state == TIPC_LISTEN)
14448c2ecf20Sopenharmony_ci			return -EPIPE;
14458c2ecf20Sopenharmony_ci		if (sk->sk_state != TIPC_OPEN)
14468c2ecf20Sopenharmony_ci			return -EISCONN;
14478c2ecf20Sopenharmony_ci		if (tsk->published)
14488c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
14498c2ecf20Sopenharmony_ci		if (dest->addrtype == TIPC_ADDR_NAME) {
14508c2ecf20Sopenharmony_ci			tsk->conn_type = dest->addr.name.name.type;
14518c2ecf20Sopenharmony_ci			tsk->conn_instance = dest->addr.name.name.instance;
14528c2ecf20Sopenharmony_ci		}
14538c2ecf20Sopenharmony_ci		msg_set_syn(hdr, 1);
14548c2ecf20Sopenharmony_ci	}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	seq = &dest->addr.nameseq;
14578c2ecf20Sopenharmony_ci	if (dest->addrtype == TIPC_ADDR_MCAST)
14588c2ecf20Sopenharmony_ci		return tipc_sendmcast(sock, seq, m, dlen, timeout);
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	if (dest->addrtype == TIPC_ADDR_NAME) {
14618c2ecf20Sopenharmony_ci		type = dest->addr.name.name.type;
14628c2ecf20Sopenharmony_ci		inst = dest->addr.name.name.instance;
14638c2ecf20Sopenharmony_ci		dnode = dest->addr.name.domain;
14648c2ecf20Sopenharmony_ci		dport = tipc_nametbl_translate(net, type, inst, &dnode);
14658c2ecf20Sopenharmony_ci		if (unlikely(!dport && !dnode))
14668c2ecf20Sopenharmony_ci			return -EHOSTUNREACH;
14678c2ecf20Sopenharmony_ci	} else if (dest->addrtype == TIPC_ADDR_ID) {
14688c2ecf20Sopenharmony_ci		dnode = dest->addr.id.node;
14698c2ecf20Sopenharmony_ci	} else {
14708c2ecf20Sopenharmony_ci		return -EINVAL;
14718c2ecf20Sopenharmony_ci	}
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	/* Block or return if destination link is congested */
14748c2ecf20Sopenharmony_ci	rc = tipc_wait_for_cond(sock, &timeout,
14758c2ecf20Sopenharmony_ci				!tipc_dest_find(clinks, dnode, 0));
14768c2ecf20Sopenharmony_ci	if (unlikely(rc))
14778c2ecf20Sopenharmony_ci		return rc;
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	if (dest->addrtype == TIPC_ADDR_NAME) {
14808c2ecf20Sopenharmony_ci		msg_set_type(hdr, TIPC_NAMED_MSG);
14818c2ecf20Sopenharmony_ci		msg_set_hdr_sz(hdr, NAMED_H_SIZE);
14828c2ecf20Sopenharmony_ci		msg_set_nametype(hdr, type);
14838c2ecf20Sopenharmony_ci		msg_set_nameinst(hdr, inst);
14848c2ecf20Sopenharmony_ci		msg_set_lookup_scope(hdr, tipc_node2scope(dnode));
14858c2ecf20Sopenharmony_ci		msg_set_destnode(hdr, dnode);
14868c2ecf20Sopenharmony_ci		msg_set_destport(hdr, dport);
14878c2ecf20Sopenharmony_ci	} else { /* TIPC_ADDR_ID */
14888c2ecf20Sopenharmony_ci		msg_set_type(hdr, TIPC_DIRECT_MSG);
14898c2ecf20Sopenharmony_ci		msg_set_lookup_scope(hdr, 0);
14908c2ecf20Sopenharmony_ci		msg_set_destnode(hdr, dnode);
14918c2ecf20Sopenharmony_ci		msg_set_destport(hdr, dest->addr.id.ref);
14928c2ecf20Sopenharmony_ci		msg_set_hdr_sz(hdr, BASIC_H_SIZE);
14938c2ecf20Sopenharmony_ci	}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	__skb_queue_head_init(&pkts);
14968c2ecf20Sopenharmony_ci	mtu = tipc_node_get_mtu(net, dnode, tsk->portid, true);
14978c2ecf20Sopenharmony_ci	rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts);
14988c2ecf20Sopenharmony_ci	if (unlikely(rc != dlen))
14998c2ecf20Sopenharmony_ci		return rc;
15008c2ecf20Sopenharmony_ci	if (unlikely(syn && !tipc_msg_skb_clone(&pkts, &sk->sk_write_queue))) {
15018c2ecf20Sopenharmony_ci		__skb_queue_purge(&pkts);
15028c2ecf20Sopenharmony_ci		return -ENOMEM;
15038c2ecf20Sopenharmony_ci	}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	trace_tipc_sk_sendmsg(sk, skb_peek(&pkts), TIPC_DUMP_SK_SNDQ, " ");
15068c2ecf20Sopenharmony_ci	rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);
15078c2ecf20Sopenharmony_ci	if (unlikely(rc == -ELINKCONG)) {
15088c2ecf20Sopenharmony_ci		tipc_dest_push(clinks, dnode, 0);
15098c2ecf20Sopenharmony_ci		tsk->cong_link_cnt++;
15108c2ecf20Sopenharmony_ci		rc = 0;
15118c2ecf20Sopenharmony_ci	}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	if (unlikely(syn && !rc)) {
15148c2ecf20Sopenharmony_ci		tipc_set_sk_state(sk, TIPC_CONNECTING);
15158c2ecf20Sopenharmony_ci		if (dlen && timeout) {
15168c2ecf20Sopenharmony_ci			timeout = msecs_to_jiffies(timeout);
15178c2ecf20Sopenharmony_ci			tipc_wait_for_connect(sock, &timeout);
15188c2ecf20Sopenharmony_ci		}
15198c2ecf20Sopenharmony_ci	}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	return rc ? rc : dlen;
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci/**
15258c2ecf20Sopenharmony_ci * tipc_sendstream - send stream-oriented data
15268c2ecf20Sopenharmony_ci * @sock: socket structure
15278c2ecf20Sopenharmony_ci * @m: data to send
15288c2ecf20Sopenharmony_ci * @dsz: total length of data to be transmitted
15298c2ecf20Sopenharmony_ci *
15308c2ecf20Sopenharmony_ci * Used for SOCK_STREAM data.
15318c2ecf20Sopenharmony_ci *
15328c2ecf20Sopenharmony_ci * Returns the number of bytes sent on success (or partial success),
15338c2ecf20Sopenharmony_ci * or errno if no data sent
15348c2ecf20Sopenharmony_ci */
15358c2ecf20Sopenharmony_cistatic int tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz)
15368c2ecf20Sopenharmony_ci{
15378c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
15388c2ecf20Sopenharmony_ci	int ret;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	lock_sock(sk);
15418c2ecf20Sopenharmony_ci	ret = __tipc_sendstream(sock, m, dsz);
15428c2ecf20Sopenharmony_ci	release_sock(sk);
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	return ret;
15458c2ecf20Sopenharmony_ci}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_cistatic int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dlen)
15488c2ecf20Sopenharmony_ci{
15498c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
15508c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
15518c2ecf20Sopenharmony_ci	long timeout = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
15528c2ecf20Sopenharmony_ci	struct sk_buff_head *txq = &sk->sk_write_queue;
15538c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
15548c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = &tsk->phdr;
15558c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
15568c2ecf20Sopenharmony_ci	struct sk_buff *skb;
15578c2ecf20Sopenharmony_ci	u32 dnode = tsk_peer_node(tsk);
15588c2ecf20Sopenharmony_ci	int maxnagle = tsk->maxnagle;
15598c2ecf20Sopenharmony_ci	int maxpkt = tsk->max_pkt;
15608c2ecf20Sopenharmony_ci	int send, sent = 0;
15618c2ecf20Sopenharmony_ci	int blocks, rc = 0;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	if (unlikely(dlen > INT_MAX))
15648c2ecf20Sopenharmony_ci		return -EMSGSIZE;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	/* Handle implicit connection setup */
15678c2ecf20Sopenharmony_ci	if (unlikely(dest && sk->sk_state == TIPC_OPEN)) {
15688c2ecf20Sopenharmony_ci		rc = __tipc_sendmsg(sock, m, dlen);
15698c2ecf20Sopenharmony_ci		if (dlen && dlen == rc) {
15708c2ecf20Sopenharmony_ci			tsk->peer_caps = tipc_node_get_capabilities(net, dnode);
15718c2ecf20Sopenharmony_ci			tsk->snt_unacked = tsk_inc(tsk, dlen + msg_hdr_sz(hdr));
15728c2ecf20Sopenharmony_ci		}
15738c2ecf20Sopenharmony_ci		return rc;
15748c2ecf20Sopenharmony_ci	}
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	do {
15778c2ecf20Sopenharmony_ci		rc = tipc_wait_for_cond(sock, &timeout,
15788c2ecf20Sopenharmony_ci					(!tsk->cong_link_cnt &&
15798c2ecf20Sopenharmony_ci					 !tsk_conn_cong(tsk) &&
15808c2ecf20Sopenharmony_ci					 tipc_sk_connected(sk)));
15818c2ecf20Sopenharmony_ci		if (unlikely(rc))
15828c2ecf20Sopenharmony_ci			break;
15838c2ecf20Sopenharmony_ci		send = min_t(size_t, dlen - sent, TIPC_MAX_USER_MSG_SIZE);
15848c2ecf20Sopenharmony_ci		blocks = tsk->snd_backlog;
15858c2ecf20Sopenharmony_ci		if (tsk->oneway++ >= tsk->nagle_start && maxnagle &&
15868c2ecf20Sopenharmony_ci		    send <= maxnagle) {
15878c2ecf20Sopenharmony_ci			rc = tipc_msg_append(hdr, m, send, maxnagle, txq);
15888c2ecf20Sopenharmony_ci			if (unlikely(rc < 0))
15898c2ecf20Sopenharmony_ci				break;
15908c2ecf20Sopenharmony_ci			blocks += rc;
15918c2ecf20Sopenharmony_ci			tsk->msg_acc++;
15928c2ecf20Sopenharmony_ci			if (blocks <= 64 && tsk->expect_ack) {
15938c2ecf20Sopenharmony_ci				tsk->snd_backlog = blocks;
15948c2ecf20Sopenharmony_ci				sent += send;
15958c2ecf20Sopenharmony_ci				break;
15968c2ecf20Sopenharmony_ci			} else if (blocks > 64) {
15978c2ecf20Sopenharmony_ci				tsk->pkt_cnt += skb_queue_len(txq);
15988c2ecf20Sopenharmony_ci			} else {
15998c2ecf20Sopenharmony_ci				skb = skb_peek_tail(txq);
16008c2ecf20Sopenharmony_ci				if (skb) {
16018c2ecf20Sopenharmony_ci					msg_set_ack_required(buf_msg(skb));
16028c2ecf20Sopenharmony_ci					tsk->expect_ack = true;
16038c2ecf20Sopenharmony_ci				} else {
16048c2ecf20Sopenharmony_ci					tsk->expect_ack = false;
16058c2ecf20Sopenharmony_ci				}
16068c2ecf20Sopenharmony_ci				tsk->msg_acc = 0;
16078c2ecf20Sopenharmony_ci				tsk->pkt_cnt = 0;
16088c2ecf20Sopenharmony_ci			}
16098c2ecf20Sopenharmony_ci		} else {
16108c2ecf20Sopenharmony_ci			rc = tipc_msg_build(hdr, m, sent, send, maxpkt, txq);
16118c2ecf20Sopenharmony_ci			if (unlikely(rc != send))
16128c2ecf20Sopenharmony_ci				break;
16138c2ecf20Sopenharmony_ci			blocks += tsk_inc(tsk, send + MIN_H_SIZE);
16148c2ecf20Sopenharmony_ci		}
16158c2ecf20Sopenharmony_ci		trace_tipc_sk_sendstream(sk, skb_peek(txq),
16168c2ecf20Sopenharmony_ci					 TIPC_DUMP_SK_SNDQ, " ");
16178c2ecf20Sopenharmony_ci		rc = tipc_node_xmit(net, txq, dnode, tsk->portid);
16188c2ecf20Sopenharmony_ci		if (unlikely(rc == -ELINKCONG)) {
16198c2ecf20Sopenharmony_ci			tsk->cong_link_cnt = 1;
16208c2ecf20Sopenharmony_ci			rc = 0;
16218c2ecf20Sopenharmony_ci		}
16228c2ecf20Sopenharmony_ci		if (likely(!rc)) {
16238c2ecf20Sopenharmony_ci			tsk->snt_unacked += blocks;
16248c2ecf20Sopenharmony_ci			tsk->snd_backlog = 0;
16258c2ecf20Sopenharmony_ci			sent += send;
16268c2ecf20Sopenharmony_ci		}
16278c2ecf20Sopenharmony_ci	} while (sent < dlen && !rc);
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	return sent ? sent : rc;
16308c2ecf20Sopenharmony_ci}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci/**
16338c2ecf20Sopenharmony_ci * tipc_send_packet - send a connection-oriented message
16348c2ecf20Sopenharmony_ci * @sock: socket structure
16358c2ecf20Sopenharmony_ci * @m: message to send
16368c2ecf20Sopenharmony_ci * @dsz: length of data to be transmitted
16378c2ecf20Sopenharmony_ci *
16388c2ecf20Sopenharmony_ci * Used for SOCK_SEQPACKET messages.
16398c2ecf20Sopenharmony_ci *
16408c2ecf20Sopenharmony_ci * Returns the number of bytes sent on success, or errno otherwise
16418c2ecf20Sopenharmony_ci */
16428c2ecf20Sopenharmony_cistatic int tipc_send_packet(struct socket *sock, struct msghdr *m, size_t dsz)
16438c2ecf20Sopenharmony_ci{
16448c2ecf20Sopenharmony_ci	if (dsz > TIPC_MAX_USER_MSG_SIZE)
16458c2ecf20Sopenharmony_ci		return -EMSGSIZE;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	return tipc_sendstream(sock, m, dsz);
16488c2ecf20Sopenharmony_ci}
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci/* tipc_sk_finish_conn - complete the setup of a connection
16518c2ecf20Sopenharmony_ci */
16528c2ecf20Sopenharmony_cistatic void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,
16538c2ecf20Sopenharmony_ci				u32 peer_node)
16548c2ecf20Sopenharmony_ci{
16558c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
16568c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
16578c2ecf20Sopenharmony_ci	struct tipc_msg *msg = &tsk->phdr;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	msg_set_syn(msg, 0);
16608c2ecf20Sopenharmony_ci	msg_set_destnode(msg, peer_node);
16618c2ecf20Sopenharmony_ci	msg_set_destport(msg, peer_port);
16628c2ecf20Sopenharmony_ci	msg_set_type(msg, TIPC_CONN_MSG);
16638c2ecf20Sopenharmony_ci	msg_set_lookup_scope(msg, 0);
16648c2ecf20Sopenharmony_ci	msg_set_hdr_sz(msg, SHORT_H_SIZE);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV);
16678c2ecf20Sopenharmony_ci	tipc_set_sk_state(sk, TIPC_ESTABLISHED);
16688c2ecf20Sopenharmony_ci	tipc_node_add_conn(net, peer_node, tsk->portid, peer_port);
16698c2ecf20Sopenharmony_ci	tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid, true);
16708c2ecf20Sopenharmony_ci	tsk->peer_caps = tipc_node_get_capabilities(net, peer_node);
16718c2ecf20Sopenharmony_ci	tsk_set_nagle(tsk);
16728c2ecf20Sopenharmony_ci	__skb_queue_purge(&sk->sk_write_queue);
16738c2ecf20Sopenharmony_ci	if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL)
16748c2ecf20Sopenharmony_ci		return;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	/* Fall back to message based flow control */
16778c2ecf20Sopenharmony_ci	tsk->rcv_win = FLOWCTL_MSG_WIN;
16788c2ecf20Sopenharmony_ci	tsk->snd_win = FLOWCTL_MSG_WIN;
16798c2ecf20Sopenharmony_ci}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci/**
16828c2ecf20Sopenharmony_ci * tipc_sk_set_orig_addr - capture sender's address for received message
16838c2ecf20Sopenharmony_ci * @m: descriptor for message info
16848c2ecf20Sopenharmony_ci * @skb: received message
16858c2ecf20Sopenharmony_ci *
16868c2ecf20Sopenharmony_ci * Note: Address is not captured if not requested by receiver.
16878c2ecf20Sopenharmony_ci */
16888c2ecf20Sopenharmony_cistatic void tipc_sk_set_orig_addr(struct msghdr *m, struct sk_buff *skb)
16898c2ecf20Sopenharmony_ci{
16908c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_pair *, srcaddr, m->msg_name);
16918c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = buf_msg(skb);
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	if (!srcaddr)
16948c2ecf20Sopenharmony_ci		return;
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	srcaddr->sock.family = AF_TIPC;
16978c2ecf20Sopenharmony_ci	srcaddr->sock.addrtype = TIPC_ADDR_ID;
16988c2ecf20Sopenharmony_ci	srcaddr->sock.scope = 0;
16998c2ecf20Sopenharmony_ci	srcaddr->sock.addr.id.ref = msg_origport(hdr);
17008c2ecf20Sopenharmony_ci	srcaddr->sock.addr.id.node = msg_orignode(hdr);
17018c2ecf20Sopenharmony_ci	srcaddr->sock.addr.name.domain = 0;
17028c2ecf20Sopenharmony_ci	m->msg_namelen = sizeof(struct sockaddr_tipc);
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	if (!msg_in_group(hdr))
17058c2ecf20Sopenharmony_ci		return;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	/* Group message users may also want to know sending member's id */
17088c2ecf20Sopenharmony_ci	srcaddr->member.family = AF_TIPC;
17098c2ecf20Sopenharmony_ci	srcaddr->member.addrtype = TIPC_ADDR_NAME;
17108c2ecf20Sopenharmony_ci	srcaddr->member.scope = 0;
17118c2ecf20Sopenharmony_ci	srcaddr->member.addr.name.name.type = msg_nametype(hdr);
17128c2ecf20Sopenharmony_ci	srcaddr->member.addr.name.name.instance = TIPC_SKB_CB(skb)->orig_member;
17138c2ecf20Sopenharmony_ci	srcaddr->member.addr.name.domain = 0;
17148c2ecf20Sopenharmony_ci	m->msg_namelen = sizeof(*srcaddr);
17158c2ecf20Sopenharmony_ci}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci/**
17188c2ecf20Sopenharmony_ci * tipc_sk_anc_data_recv - optionally capture ancillary data for received message
17198c2ecf20Sopenharmony_ci * @m: descriptor for message info
17208c2ecf20Sopenharmony_ci * @skb: received message buffer
17218c2ecf20Sopenharmony_ci * @tsk: TIPC port associated with message
17228c2ecf20Sopenharmony_ci *
17238c2ecf20Sopenharmony_ci * Note: Ancillary data is not captured if not requested by receiver.
17248c2ecf20Sopenharmony_ci *
17258c2ecf20Sopenharmony_ci * Returns 0 if successful, otherwise errno
17268c2ecf20Sopenharmony_ci */
17278c2ecf20Sopenharmony_cistatic int tipc_sk_anc_data_recv(struct msghdr *m, struct sk_buff *skb,
17288c2ecf20Sopenharmony_ci				 struct tipc_sock *tsk)
17298c2ecf20Sopenharmony_ci{
17308c2ecf20Sopenharmony_ci	struct tipc_msg *msg;
17318c2ecf20Sopenharmony_ci	u32 anc_data[3];
17328c2ecf20Sopenharmony_ci	u32 err;
17338c2ecf20Sopenharmony_ci	u32 dest_type;
17348c2ecf20Sopenharmony_ci	int has_name;
17358c2ecf20Sopenharmony_ci	int res;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	if (likely(m->msg_controllen == 0))
17388c2ecf20Sopenharmony_ci		return 0;
17398c2ecf20Sopenharmony_ci	msg = buf_msg(skb);
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	/* Optionally capture errored message object(s) */
17428c2ecf20Sopenharmony_ci	err = msg ? msg_errcode(msg) : 0;
17438c2ecf20Sopenharmony_ci	if (unlikely(err)) {
17448c2ecf20Sopenharmony_ci		anc_data[0] = err;
17458c2ecf20Sopenharmony_ci		anc_data[1] = msg_data_sz(msg);
17468c2ecf20Sopenharmony_ci		res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data);
17478c2ecf20Sopenharmony_ci		if (res)
17488c2ecf20Sopenharmony_ci			return res;
17498c2ecf20Sopenharmony_ci		if (anc_data[1]) {
17508c2ecf20Sopenharmony_ci			if (skb_linearize(skb))
17518c2ecf20Sopenharmony_ci				return -ENOMEM;
17528c2ecf20Sopenharmony_ci			msg = buf_msg(skb);
17538c2ecf20Sopenharmony_ci			res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1],
17548c2ecf20Sopenharmony_ci				       msg_data(msg));
17558c2ecf20Sopenharmony_ci			if (res)
17568c2ecf20Sopenharmony_ci				return res;
17578c2ecf20Sopenharmony_ci		}
17588c2ecf20Sopenharmony_ci	}
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	/* Optionally capture message destination object */
17618c2ecf20Sopenharmony_ci	dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG;
17628c2ecf20Sopenharmony_ci	switch (dest_type) {
17638c2ecf20Sopenharmony_ci	case TIPC_NAMED_MSG:
17648c2ecf20Sopenharmony_ci		has_name = 1;
17658c2ecf20Sopenharmony_ci		anc_data[0] = msg_nametype(msg);
17668c2ecf20Sopenharmony_ci		anc_data[1] = msg_namelower(msg);
17678c2ecf20Sopenharmony_ci		anc_data[2] = msg_namelower(msg);
17688c2ecf20Sopenharmony_ci		break;
17698c2ecf20Sopenharmony_ci	case TIPC_MCAST_MSG:
17708c2ecf20Sopenharmony_ci		has_name = 1;
17718c2ecf20Sopenharmony_ci		anc_data[0] = msg_nametype(msg);
17728c2ecf20Sopenharmony_ci		anc_data[1] = msg_namelower(msg);
17738c2ecf20Sopenharmony_ci		anc_data[2] = msg_nameupper(msg);
17748c2ecf20Sopenharmony_ci		break;
17758c2ecf20Sopenharmony_ci	case TIPC_CONN_MSG:
17768c2ecf20Sopenharmony_ci		has_name = (tsk->conn_type != 0);
17778c2ecf20Sopenharmony_ci		anc_data[0] = tsk->conn_type;
17788c2ecf20Sopenharmony_ci		anc_data[1] = tsk->conn_instance;
17798c2ecf20Sopenharmony_ci		anc_data[2] = tsk->conn_instance;
17808c2ecf20Sopenharmony_ci		break;
17818c2ecf20Sopenharmony_ci	default:
17828c2ecf20Sopenharmony_ci		has_name = 0;
17838c2ecf20Sopenharmony_ci	}
17848c2ecf20Sopenharmony_ci	if (has_name) {
17858c2ecf20Sopenharmony_ci		res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data);
17868c2ecf20Sopenharmony_ci		if (res)
17878c2ecf20Sopenharmony_ci			return res;
17888c2ecf20Sopenharmony_ci	}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	return 0;
17918c2ecf20Sopenharmony_ci}
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_cistatic struct sk_buff *tipc_sk_build_ack(struct tipc_sock *tsk)
17948c2ecf20Sopenharmony_ci{
17958c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
17968c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL;
17978c2ecf20Sopenharmony_ci	struct tipc_msg *msg;
17988c2ecf20Sopenharmony_ci	u32 peer_port = tsk_peer_port(tsk);
17998c2ecf20Sopenharmony_ci	u32 dnode = tsk_peer_node(tsk);
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	if (!tipc_sk_connected(sk))
18028c2ecf20Sopenharmony_ci		return NULL;
18038c2ecf20Sopenharmony_ci	skb = tipc_msg_create(CONN_MANAGER, CONN_ACK, INT_H_SIZE, 0,
18048c2ecf20Sopenharmony_ci			      dnode, tsk_own_node(tsk), peer_port,
18058c2ecf20Sopenharmony_ci			      tsk->portid, TIPC_OK);
18068c2ecf20Sopenharmony_ci	if (!skb)
18078c2ecf20Sopenharmony_ci		return NULL;
18088c2ecf20Sopenharmony_ci	msg = buf_msg(skb);
18098c2ecf20Sopenharmony_ci	msg_set_conn_ack(msg, tsk->rcv_unacked);
18108c2ecf20Sopenharmony_ci	tsk->rcv_unacked = 0;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	/* Adjust to and advertize the correct window limit */
18138c2ecf20Sopenharmony_ci	if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL) {
18148c2ecf20Sopenharmony_ci		tsk->rcv_win = tsk_adv_blocks(tsk->sk.sk_rcvbuf);
18158c2ecf20Sopenharmony_ci		msg_set_adv_win(msg, tsk->rcv_win);
18168c2ecf20Sopenharmony_ci	}
18178c2ecf20Sopenharmony_ci	return skb;
18188c2ecf20Sopenharmony_ci}
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_cistatic void tipc_sk_send_ack(struct tipc_sock *tsk)
18218c2ecf20Sopenharmony_ci{
18228c2ecf20Sopenharmony_ci	struct sk_buff *skb;
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	skb = tipc_sk_build_ack(tsk);
18258c2ecf20Sopenharmony_ci	if (!skb)
18268c2ecf20Sopenharmony_ci		return;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	tipc_node_xmit_skb(sock_net(&tsk->sk), skb, tsk_peer_node(tsk),
18298c2ecf20Sopenharmony_ci			   msg_link_selector(buf_msg(skb)));
18308c2ecf20Sopenharmony_ci}
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_cistatic int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
18338c2ecf20Sopenharmony_ci{
18348c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
18358c2ecf20Sopenharmony_ci	DEFINE_WAIT_FUNC(wait, woken_wake_function);
18368c2ecf20Sopenharmony_ci	long timeo = *timeop;
18378c2ecf20Sopenharmony_ci	int err = sock_error(sk);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	if (err)
18408c2ecf20Sopenharmony_ci		return err;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	for (;;) {
18438c2ecf20Sopenharmony_ci		if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
18448c2ecf20Sopenharmony_ci			if (sk->sk_shutdown & RCV_SHUTDOWN) {
18458c2ecf20Sopenharmony_ci				err = -ENOTCONN;
18468c2ecf20Sopenharmony_ci				break;
18478c2ecf20Sopenharmony_ci			}
18488c2ecf20Sopenharmony_ci			add_wait_queue(sk_sleep(sk), &wait);
18498c2ecf20Sopenharmony_ci			release_sock(sk);
18508c2ecf20Sopenharmony_ci			timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
18518c2ecf20Sopenharmony_ci			sched_annotate_sleep();
18528c2ecf20Sopenharmony_ci			lock_sock(sk);
18538c2ecf20Sopenharmony_ci			remove_wait_queue(sk_sleep(sk), &wait);
18548c2ecf20Sopenharmony_ci		}
18558c2ecf20Sopenharmony_ci		err = 0;
18568c2ecf20Sopenharmony_ci		if (!skb_queue_empty(&sk->sk_receive_queue))
18578c2ecf20Sopenharmony_ci			break;
18588c2ecf20Sopenharmony_ci		err = -EAGAIN;
18598c2ecf20Sopenharmony_ci		if (!timeo)
18608c2ecf20Sopenharmony_ci			break;
18618c2ecf20Sopenharmony_ci		err = sock_intr_errno(timeo);
18628c2ecf20Sopenharmony_ci		if (signal_pending(current))
18638c2ecf20Sopenharmony_ci			break;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci		err = sock_error(sk);
18668c2ecf20Sopenharmony_ci		if (err)
18678c2ecf20Sopenharmony_ci			break;
18688c2ecf20Sopenharmony_ci	}
18698c2ecf20Sopenharmony_ci	*timeop = timeo;
18708c2ecf20Sopenharmony_ci	return err;
18718c2ecf20Sopenharmony_ci}
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci/**
18748c2ecf20Sopenharmony_ci * tipc_recvmsg - receive packet-oriented message
18758c2ecf20Sopenharmony_ci * @m: descriptor for message info
18768c2ecf20Sopenharmony_ci * @buflen: length of user buffer area
18778c2ecf20Sopenharmony_ci * @flags: receive flags
18788c2ecf20Sopenharmony_ci *
18798c2ecf20Sopenharmony_ci * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages.
18808c2ecf20Sopenharmony_ci * If the complete message doesn't fit in user area, truncate it.
18818c2ecf20Sopenharmony_ci *
18828c2ecf20Sopenharmony_ci * Returns size of returned message data, errno otherwise
18838c2ecf20Sopenharmony_ci */
18848c2ecf20Sopenharmony_cistatic int tipc_recvmsg(struct socket *sock, struct msghdr *m,
18858c2ecf20Sopenharmony_ci			size_t buflen,	int flags)
18868c2ecf20Sopenharmony_ci{
18878c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
18888c2ecf20Sopenharmony_ci	bool connected = !tipc_sk_type_connectionless(sk);
18898c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
18908c2ecf20Sopenharmony_ci	int rc, err, hlen, dlen, copy;
18918c2ecf20Sopenharmony_ci	struct tipc_skb_cb *skb_cb;
18928c2ecf20Sopenharmony_ci	struct sk_buff_head xmitq;
18938c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
18948c2ecf20Sopenharmony_ci	struct sk_buff *skb;
18958c2ecf20Sopenharmony_ci	bool grp_evt;
18968c2ecf20Sopenharmony_ci	long timeout;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	/* Catch invalid receive requests */
18998c2ecf20Sopenharmony_ci	if (unlikely(!buflen))
19008c2ecf20Sopenharmony_ci		return -EINVAL;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	lock_sock(sk);
19038c2ecf20Sopenharmony_ci	if (unlikely(connected && sk->sk_state == TIPC_OPEN)) {
19048c2ecf20Sopenharmony_ci		rc = -ENOTCONN;
19058c2ecf20Sopenharmony_ci		goto exit;
19068c2ecf20Sopenharmony_ci	}
19078c2ecf20Sopenharmony_ci	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	/* Step rcv queue to first msg with data or error; wait if necessary */
19108c2ecf20Sopenharmony_ci	do {
19118c2ecf20Sopenharmony_ci		rc = tipc_wait_for_rcvmsg(sock, &timeout);
19128c2ecf20Sopenharmony_ci		if (unlikely(rc))
19138c2ecf20Sopenharmony_ci			goto exit;
19148c2ecf20Sopenharmony_ci		skb = skb_peek(&sk->sk_receive_queue);
19158c2ecf20Sopenharmony_ci		skb_cb = TIPC_SKB_CB(skb);
19168c2ecf20Sopenharmony_ci		hdr = buf_msg(skb);
19178c2ecf20Sopenharmony_ci		dlen = msg_data_sz(hdr);
19188c2ecf20Sopenharmony_ci		hlen = msg_hdr_sz(hdr);
19198c2ecf20Sopenharmony_ci		err = msg_errcode(hdr);
19208c2ecf20Sopenharmony_ci		grp_evt = msg_is_grp_evt(hdr);
19218c2ecf20Sopenharmony_ci		if (likely(dlen || err))
19228c2ecf20Sopenharmony_ci			break;
19238c2ecf20Sopenharmony_ci		tsk_advance_rx_queue(sk);
19248c2ecf20Sopenharmony_ci	} while (1);
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	/* Collect msg meta data, including error code and rejected data */
19278c2ecf20Sopenharmony_ci	tipc_sk_set_orig_addr(m, skb);
19288c2ecf20Sopenharmony_ci	rc = tipc_sk_anc_data_recv(m, skb, tsk);
19298c2ecf20Sopenharmony_ci	if (unlikely(rc))
19308c2ecf20Sopenharmony_ci		goto exit;
19318c2ecf20Sopenharmony_ci	hdr = buf_msg(skb);
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	/* Capture data if non-error msg, otherwise just set return value */
19348c2ecf20Sopenharmony_ci	if (likely(!err)) {
19358c2ecf20Sopenharmony_ci		int offset = skb_cb->bytes_read;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci		copy = min_t(int, dlen - offset, buflen);
19388c2ecf20Sopenharmony_ci		rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy);
19398c2ecf20Sopenharmony_ci		if (unlikely(rc))
19408c2ecf20Sopenharmony_ci			goto exit;
19418c2ecf20Sopenharmony_ci		if (unlikely(offset + copy < dlen)) {
19428c2ecf20Sopenharmony_ci			if (flags & MSG_EOR) {
19438c2ecf20Sopenharmony_ci				if (!(flags & MSG_PEEK))
19448c2ecf20Sopenharmony_ci					skb_cb->bytes_read = offset + copy;
19458c2ecf20Sopenharmony_ci			} else {
19468c2ecf20Sopenharmony_ci				m->msg_flags |= MSG_TRUNC;
19478c2ecf20Sopenharmony_ci				skb_cb->bytes_read = 0;
19488c2ecf20Sopenharmony_ci			}
19498c2ecf20Sopenharmony_ci		} else {
19508c2ecf20Sopenharmony_ci			if (flags & MSG_EOR)
19518c2ecf20Sopenharmony_ci				m->msg_flags |= MSG_EOR;
19528c2ecf20Sopenharmony_ci			skb_cb->bytes_read = 0;
19538c2ecf20Sopenharmony_ci		}
19548c2ecf20Sopenharmony_ci	} else {
19558c2ecf20Sopenharmony_ci		copy = 0;
19568c2ecf20Sopenharmony_ci		rc = 0;
19578c2ecf20Sopenharmony_ci		if (err != TIPC_CONN_SHUTDOWN && connected && !m->msg_control) {
19588c2ecf20Sopenharmony_ci			rc = -ECONNRESET;
19598c2ecf20Sopenharmony_ci			goto exit;
19608c2ecf20Sopenharmony_ci		}
19618c2ecf20Sopenharmony_ci	}
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	/* Mark message as group event if applicable */
19648c2ecf20Sopenharmony_ci	if (unlikely(grp_evt)) {
19658c2ecf20Sopenharmony_ci		if (msg_grp_evt(hdr) == TIPC_WITHDRAWN)
19668c2ecf20Sopenharmony_ci			m->msg_flags |= MSG_EOR;
19678c2ecf20Sopenharmony_ci		m->msg_flags |= MSG_OOB;
19688c2ecf20Sopenharmony_ci		copy = 0;
19698c2ecf20Sopenharmony_ci	}
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	/* Caption of data or error code/rejected data was successful */
19728c2ecf20Sopenharmony_ci	if (unlikely(flags & MSG_PEEK))
19738c2ecf20Sopenharmony_ci		goto exit;
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	/* Send group flow control advertisement when applicable */
19768c2ecf20Sopenharmony_ci	if (tsk->group && msg_in_group(hdr) && !grp_evt) {
19778c2ecf20Sopenharmony_ci		__skb_queue_head_init(&xmitq);
19788c2ecf20Sopenharmony_ci		tipc_group_update_rcv_win(tsk->group, tsk_blocks(hlen + dlen),
19798c2ecf20Sopenharmony_ci					  msg_orignode(hdr), msg_origport(hdr),
19808c2ecf20Sopenharmony_ci					  &xmitq);
19818c2ecf20Sopenharmony_ci		tipc_node_distr_xmit(sock_net(sk), &xmitq);
19828c2ecf20Sopenharmony_ci	}
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	if (skb_cb->bytes_read)
19858c2ecf20Sopenharmony_ci		goto exit;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	tsk_advance_rx_queue(sk);
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	if (likely(!connected))
19908c2ecf20Sopenharmony_ci		goto exit;
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	/* Send connection flow control advertisement when applicable */
19938c2ecf20Sopenharmony_ci	tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
19948c2ecf20Sopenharmony_ci	if (tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE)
19958c2ecf20Sopenharmony_ci		tipc_sk_send_ack(tsk);
19968c2ecf20Sopenharmony_ciexit:
19978c2ecf20Sopenharmony_ci	release_sock(sk);
19988c2ecf20Sopenharmony_ci	return rc ? rc : copy;
19998c2ecf20Sopenharmony_ci}
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci/**
20028c2ecf20Sopenharmony_ci * tipc_recvstream - receive stream-oriented data
20038c2ecf20Sopenharmony_ci * @m: descriptor for message info
20048c2ecf20Sopenharmony_ci * @buflen: total size of user buffer area
20058c2ecf20Sopenharmony_ci * @flags: receive flags
20068c2ecf20Sopenharmony_ci *
20078c2ecf20Sopenharmony_ci * Used for SOCK_STREAM messages only.  If not enough data is available
20088c2ecf20Sopenharmony_ci * will optionally wait for more; never truncates data.
20098c2ecf20Sopenharmony_ci *
20108c2ecf20Sopenharmony_ci * Returns size of returned message data, errno otherwise
20118c2ecf20Sopenharmony_ci */
20128c2ecf20Sopenharmony_cistatic int tipc_recvstream(struct socket *sock, struct msghdr *m,
20138c2ecf20Sopenharmony_ci			   size_t buflen, int flags)
20148c2ecf20Sopenharmony_ci{
20158c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
20168c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
20178c2ecf20Sopenharmony_ci	struct sk_buff *skb;
20188c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
20198c2ecf20Sopenharmony_ci	struct tipc_skb_cb *skb_cb;
20208c2ecf20Sopenharmony_ci	bool peek = flags & MSG_PEEK;
20218c2ecf20Sopenharmony_ci	int offset, required, copy, copied = 0;
20228c2ecf20Sopenharmony_ci	int hlen, dlen, err, rc;
20238c2ecf20Sopenharmony_ci	long timeout;
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	/* Catch invalid receive attempts */
20268c2ecf20Sopenharmony_ci	if (unlikely(!buflen))
20278c2ecf20Sopenharmony_ci		return -EINVAL;
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	lock_sock(sk);
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	if (unlikely(sk->sk_state == TIPC_OPEN)) {
20328c2ecf20Sopenharmony_ci		rc = -ENOTCONN;
20338c2ecf20Sopenharmony_ci		goto exit;
20348c2ecf20Sopenharmony_ci	}
20358c2ecf20Sopenharmony_ci	required = sock_rcvlowat(sk, flags & MSG_WAITALL, buflen);
20368c2ecf20Sopenharmony_ci	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	do {
20398c2ecf20Sopenharmony_ci		/* Look at first msg in receive queue; wait if necessary */
20408c2ecf20Sopenharmony_ci		rc = tipc_wait_for_rcvmsg(sock, &timeout);
20418c2ecf20Sopenharmony_ci		if (unlikely(rc))
20428c2ecf20Sopenharmony_ci			break;
20438c2ecf20Sopenharmony_ci		skb = skb_peek(&sk->sk_receive_queue);
20448c2ecf20Sopenharmony_ci		skb_cb = TIPC_SKB_CB(skb);
20458c2ecf20Sopenharmony_ci		hdr = buf_msg(skb);
20468c2ecf20Sopenharmony_ci		dlen = msg_data_sz(hdr);
20478c2ecf20Sopenharmony_ci		hlen = msg_hdr_sz(hdr);
20488c2ecf20Sopenharmony_ci		err = msg_errcode(hdr);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci		/* Discard any empty non-errored (SYN-) message */
20518c2ecf20Sopenharmony_ci		if (unlikely(!dlen && !err)) {
20528c2ecf20Sopenharmony_ci			tsk_advance_rx_queue(sk);
20538c2ecf20Sopenharmony_ci			continue;
20548c2ecf20Sopenharmony_ci		}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci		/* Collect msg meta data, incl. error code and rejected data */
20578c2ecf20Sopenharmony_ci		if (!copied) {
20588c2ecf20Sopenharmony_ci			tipc_sk_set_orig_addr(m, skb);
20598c2ecf20Sopenharmony_ci			rc = tipc_sk_anc_data_recv(m, skb, tsk);
20608c2ecf20Sopenharmony_ci			if (rc)
20618c2ecf20Sopenharmony_ci				break;
20628c2ecf20Sopenharmony_ci			hdr = buf_msg(skb);
20638c2ecf20Sopenharmony_ci		}
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci		/* Copy data if msg ok, otherwise return error/partial data */
20668c2ecf20Sopenharmony_ci		if (likely(!err)) {
20678c2ecf20Sopenharmony_ci			offset = skb_cb->bytes_read;
20688c2ecf20Sopenharmony_ci			copy = min_t(int, dlen - offset, buflen - copied);
20698c2ecf20Sopenharmony_ci			rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy);
20708c2ecf20Sopenharmony_ci			if (unlikely(rc))
20718c2ecf20Sopenharmony_ci				break;
20728c2ecf20Sopenharmony_ci			copied += copy;
20738c2ecf20Sopenharmony_ci			offset += copy;
20748c2ecf20Sopenharmony_ci			if (unlikely(offset < dlen)) {
20758c2ecf20Sopenharmony_ci				if (!peek)
20768c2ecf20Sopenharmony_ci					skb_cb->bytes_read = offset;
20778c2ecf20Sopenharmony_ci				break;
20788c2ecf20Sopenharmony_ci			}
20798c2ecf20Sopenharmony_ci		} else {
20808c2ecf20Sopenharmony_ci			rc = 0;
20818c2ecf20Sopenharmony_ci			if ((err != TIPC_CONN_SHUTDOWN) && !m->msg_control)
20828c2ecf20Sopenharmony_ci				rc = -ECONNRESET;
20838c2ecf20Sopenharmony_ci			if (copied || rc)
20848c2ecf20Sopenharmony_ci				break;
20858c2ecf20Sopenharmony_ci		}
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci		if (unlikely(peek))
20888c2ecf20Sopenharmony_ci			break;
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci		tsk_advance_rx_queue(sk);
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci		/* Send connection flow control advertisement when applicable */
20938c2ecf20Sopenharmony_ci		tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
20948c2ecf20Sopenharmony_ci		if (tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE)
20958c2ecf20Sopenharmony_ci			tipc_sk_send_ack(tsk);
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci		/* Exit if all requested data or FIN/error received */
20988c2ecf20Sopenharmony_ci		if (copied == buflen || err)
20998c2ecf20Sopenharmony_ci			break;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	} while (!skb_queue_empty(&sk->sk_receive_queue) || copied < required);
21028c2ecf20Sopenharmony_ciexit:
21038c2ecf20Sopenharmony_ci	release_sock(sk);
21048c2ecf20Sopenharmony_ci	return copied ? copied : rc;
21058c2ecf20Sopenharmony_ci}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci/**
21088c2ecf20Sopenharmony_ci * tipc_write_space - wake up thread if port congestion is released
21098c2ecf20Sopenharmony_ci * @sk: socket
21108c2ecf20Sopenharmony_ci */
21118c2ecf20Sopenharmony_cistatic void tipc_write_space(struct sock *sk)
21128c2ecf20Sopenharmony_ci{
21138c2ecf20Sopenharmony_ci	struct socket_wq *wq;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	rcu_read_lock();
21168c2ecf20Sopenharmony_ci	wq = rcu_dereference(sk->sk_wq);
21178c2ecf20Sopenharmony_ci	if (skwq_has_sleeper(wq))
21188c2ecf20Sopenharmony_ci		wake_up_interruptible_sync_poll(&wq->wait, EPOLLOUT |
21198c2ecf20Sopenharmony_ci						EPOLLWRNORM | EPOLLWRBAND);
21208c2ecf20Sopenharmony_ci	rcu_read_unlock();
21218c2ecf20Sopenharmony_ci}
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci/**
21248c2ecf20Sopenharmony_ci * tipc_data_ready - wake up threads to indicate messages have been received
21258c2ecf20Sopenharmony_ci * @sk: socket
21268c2ecf20Sopenharmony_ci */
21278c2ecf20Sopenharmony_cistatic void tipc_data_ready(struct sock *sk)
21288c2ecf20Sopenharmony_ci{
21298c2ecf20Sopenharmony_ci	struct socket_wq *wq;
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci	rcu_read_lock();
21328c2ecf20Sopenharmony_ci	wq = rcu_dereference(sk->sk_wq);
21338c2ecf20Sopenharmony_ci	if (skwq_has_sleeper(wq))
21348c2ecf20Sopenharmony_ci		wake_up_interruptible_sync_poll(&wq->wait, EPOLLIN |
21358c2ecf20Sopenharmony_ci						EPOLLRDNORM | EPOLLRDBAND);
21368c2ecf20Sopenharmony_ci	rcu_read_unlock();
21378c2ecf20Sopenharmony_ci}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_cistatic void tipc_sock_destruct(struct sock *sk)
21408c2ecf20Sopenharmony_ci{
21418c2ecf20Sopenharmony_ci	__skb_queue_purge(&sk->sk_receive_queue);
21428c2ecf20Sopenharmony_ci}
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_cistatic void tipc_sk_proto_rcv(struct sock *sk,
21458c2ecf20Sopenharmony_ci			      struct sk_buff_head *inputq,
21468c2ecf20Sopenharmony_ci			      struct sk_buff_head *xmitq)
21478c2ecf20Sopenharmony_ci{
21488c2ecf20Sopenharmony_ci	struct sk_buff *skb = __skb_dequeue(inputq);
21498c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
21508c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = buf_msg(skb);
21518c2ecf20Sopenharmony_ci	struct tipc_group *grp = tsk->group;
21528c2ecf20Sopenharmony_ci	bool wakeup = false;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	switch (msg_user(hdr)) {
21558c2ecf20Sopenharmony_ci	case CONN_MANAGER:
21568c2ecf20Sopenharmony_ci		tipc_sk_conn_proto_rcv(tsk, skb, inputq, xmitq);
21578c2ecf20Sopenharmony_ci		return;
21588c2ecf20Sopenharmony_ci	case SOCK_WAKEUP:
21598c2ecf20Sopenharmony_ci		tipc_dest_del(&tsk->cong_links, msg_orignode(hdr), 0);
21608c2ecf20Sopenharmony_ci		/* coupled with smp_rmb() in tipc_wait_for_cond() */
21618c2ecf20Sopenharmony_ci		smp_wmb();
21628c2ecf20Sopenharmony_ci		tsk->cong_link_cnt--;
21638c2ecf20Sopenharmony_ci		wakeup = true;
21648c2ecf20Sopenharmony_ci		tipc_sk_push_backlog(tsk, false);
21658c2ecf20Sopenharmony_ci		break;
21668c2ecf20Sopenharmony_ci	case GROUP_PROTOCOL:
21678c2ecf20Sopenharmony_ci		tipc_group_proto_rcv(grp, &wakeup, hdr, inputq, xmitq);
21688c2ecf20Sopenharmony_ci		break;
21698c2ecf20Sopenharmony_ci	case TOP_SRV:
21708c2ecf20Sopenharmony_ci		tipc_group_member_evt(tsk->group, &wakeup, &sk->sk_rcvbuf,
21718c2ecf20Sopenharmony_ci				      hdr, inputq, xmitq);
21728c2ecf20Sopenharmony_ci		break;
21738c2ecf20Sopenharmony_ci	default:
21748c2ecf20Sopenharmony_ci		break;
21758c2ecf20Sopenharmony_ci	}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	if (wakeup)
21788c2ecf20Sopenharmony_ci		sk->sk_write_space(sk);
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	kfree_skb(skb);
21818c2ecf20Sopenharmony_ci}
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci/**
21848c2ecf20Sopenharmony_ci * tipc_sk_filter_connect - check incoming message for a connection-based socket
21858c2ecf20Sopenharmony_ci * @tsk: TIPC socket
21868c2ecf20Sopenharmony_ci * @skb: pointer to message buffer.
21878c2ecf20Sopenharmony_ci * @xmitq: for Nagle ACK if any
21888c2ecf20Sopenharmony_ci * Returns true if message should be added to receive queue, false otherwise
21898c2ecf20Sopenharmony_ci */
21908c2ecf20Sopenharmony_cistatic bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb,
21918c2ecf20Sopenharmony_ci				   struct sk_buff_head *xmitq)
21928c2ecf20Sopenharmony_ci{
21938c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
21948c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
21958c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = buf_msg(skb);
21968c2ecf20Sopenharmony_ci	bool con_msg = msg_connected(hdr);
21978c2ecf20Sopenharmony_ci	u32 pport = tsk_peer_port(tsk);
21988c2ecf20Sopenharmony_ci	u32 pnode = tsk_peer_node(tsk);
21998c2ecf20Sopenharmony_ci	u32 oport = msg_origport(hdr);
22008c2ecf20Sopenharmony_ci	u32 onode = msg_orignode(hdr);
22018c2ecf20Sopenharmony_ci	int err = msg_errcode(hdr);
22028c2ecf20Sopenharmony_ci	unsigned long delay;
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	if (unlikely(msg_mcast(hdr)))
22058c2ecf20Sopenharmony_ci		return false;
22068c2ecf20Sopenharmony_ci	tsk->oneway = 0;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
22098c2ecf20Sopenharmony_ci	case TIPC_CONNECTING:
22108c2ecf20Sopenharmony_ci		/* Setup ACK */
22118c2ecf20Sopenharmony_ci		if (likely(con_msg)) {
22128c2ecf20Sopenharmony_ci			if (err)
22138c2ecf20Sopenharmony_ci				break;
22148c2ecf20Sopenharmony_ci			tipc_sk_finish_conn(tsk, oport, onode);
22158c2ecf20Sopenharmony_ci			msg_set_importance(&tsk->phdr, msg_importance(hdr));
22168c2ecf20Sopenharmony_ci			/* ACK+ message with data is added to receive queue */
22178c2ecf20Sopenharmony_ci			if (msg_data_sz(hdr))
22188c2ecf20Sopenharmony_ci				return true;
22198c2ecf20Sopenharmony_ci			/* Empty ACK-, - wake up sleeping connect() and drop */
22208c2ecf20Sopenharmony_ci			sk->sk_state_change(sk);
22218c2ecf20Sopenharmony_ci			msg_set_dest_droppable(hdr, 1);
22228c2ecf20Sopenharmony_ci			return false;
22238c2ecf20Sopenharmony_ci		}
22248c2ecf20Sopenharmony_ci		/* Ignore connectionless message if not from listening socket */
22258c2ecf20Sopenharmony_ci		if (oport != pport || onode != pnode)
22268c2ecf20Sopenharmony_ci			return false;
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci		/* Rejected SYN */
22298c2ecf20Sopenharmony_ci		if (err != TIPC_ERR_OVERLOAD)
22308c2ecf20Sopenharmony_ci			break;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci		/* Prepare for new setup attempt if we have a SYN clone */
22338c2ecf20Sopenharmony_ci		if (skb_queue_empty(&sk->sk_write_queue))
22348c2ecf20Sopenharmony_ci			break;
22358c2ecf20Sopenharmony_ci		get_random_bytes(&delay, 2);
22368c2ecf20Sopenharmony_ci		delay %= (tsk->conn_timeout / 4);
22378c2ecf20Sopenharmony_ci		delay = msecs_to_jiffies(delay + 100);
22388c2ecf20Sopenharmony_ci		sk_reset_timer(sk, &sk->sk_timer, jiffies + delay);
22398c2ecf20Sopenharmony_ci		return false;
22408c2ecf20Sopenharmony_ci	case TIPC_OPEN:
22418c2ecf20Sopenharmony_ci	case TIPC_DISCONNECTING:
22428c2ecf20Sopenharmony_ci		return false;
22438c2ecf20Sopenharmony_ci	case TIPC_LISTEN:
22448c2ecf20Sopenharmony_ci		/* Accept only SYN message */
22458c2ecf20Sopenharmony_ci		if (!msg_is_syn(hdr) &&
22468c2ecf20Sopenharmony_ci		    tipc_node_get_capabilities(net, onode) & TIPC_SYN_BIT)
22478c2ecf20Sopenharmony_ci			return false;
22488c2ecf20Sopenharmony_ci		if (!con_msg && !err)
22498c2ecf20Sopenharmony_ci			return true;
22508c2ecf20Sopenharmony_ci		return false;
22518c2ecf20Sopenharmony_ci	case TIPC_ESTABLISHED:
22528c2ecf20Sopenharmony_ci		if (!skb_queue_empty(&sk->sk_write_queue))
22538c2ecf20Sopenharmony_ci			tipc_sk_push_backlog(tsk, false);
22548c2ecf20Sopenharmony_ci		/* Accept only connection-based messages sent by peer */
22558c2ecf20Sopenharmony_ci		if (likely(con_msg && !err && pport == oport &&
22568c2ecf20Sopenharmony_ci			   pnode == onode)) {
22578c2ecf20Sopenharmony_ci			if (msg_ack_required(hdr)) {
22588c2ecf20Sopenharmony_ci				struct sk_buff *skb;
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci				skb = tipc_sk_build_ack(tsk);
22618c2ecf20Sopenharmony_ci				if (skb) {
22628c2ecf20Sopenharmony_ci					msg_set_nagle_ack(buf_msg(skb));
22638c2ecf20Sopenharmony_ci					__skb_queue_tail(xmitq, skb);
22648c2ecf20Sopenharmony_ci				}
22658c2ecf20Sopenharmony_ci			}
22668c2ecf20Sopenharmony_ci			return true;
22678c2ecf20Sopenharmony_ci		}
22688c2ecf20Sopenharmony_ci		if (!tsk_peer_msg(tsk, hdr))
22698c2ecf20Sopenharmony_ci			return false;
22708c2ecf20Sopenharmony_ci		if (!err)
22718c2ecf20Sopenharmony_ci			return true;
22728c2ecf20Sopenharmony_ci		tipc_set_sk_state(sk, TIPC_DISCONNECTING);
22738c2ecf20Sopenharmony_ci		tipc_node_remove_conn(net, pnode, tsk->portid);
22748c2ecf20Sopenharmony_ci		sk->sk_state_change(sk);
22758c2ecf20Sopenharmony_ci		return true;
22768c2ecf20Sopenharmony_ci	default:
22778c2ecf20Sopenharmony_ci		pr_err("Unknown sk_state %u\n", sk->sk_state);
22788c2ecf20Sopenharmony_ci	}
22798c2ecf20Sopenharmony_ci	/* Abort connection setup attempt */
22808c2ecf20Sopenharmony_ci	tipc_set_sk_state(sk, TIPC_DISCONNECTING);
22818c2ecf20Sopenharmony_ci	sk->sk_err = ECONNREFUSED;
22828c2ecf20Sopenharmony_ci	sk->sk_state_change(sk);
22838c2ecf20Sopenharmony_ci	return true;
22848c2ecf20Sopenharmony_ci}
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci/**
22878c2ecf20Sopenharmony_ci * rcvbuf_limit - get proper overload limit of socket receive queue
22888c2ecf20Sopenharmony_ci * @sk: socket
22898c2ecf20Sopenharmony_ci * @skb: message
22908c2ecf20Sopenharmony_ci *
22918c2ecf20Sopenharmony_ci * For connection oriented messages, irrespective of importance,
22928c2ecf20Sopenharmony_ci * default queue limit is 2 MB.
22938c2ecf20Sopenharmony_ci *
22948c2ecf20Sopenharmony_ci * For connectionless messages, queue limits are based on message
22958c2ecf20Sopenharmony_ci * importance as follows:
22968c2ecf20Sopenharmony_ci *
22978c2ecf20Sopenharmony_ci * TIPC_LOW_IMPORTANCE       (2 MB)
22988c2ecf20Sopenharmony_ci * TIPC_MEDIUM_IMPORTANCE    (4 MB)
22998c2ecf20Sopenharmony_ci * TIPC_HIGH_IMPORTANCE      (8 MB)
23008c2ecf20Sopenharmony_ci * TIPC_CRITICAL_IMPORTANCE  (16 MB)
23018c2ecf20Sopenharmony_ci *
23028c2ecf20Sopenharmony_ci * Returns overload limit according to corresponding message importance
23038c2ecf20Sopenharmony_ci */
23048c2ecf20Sopenharmony_cistatic unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *skb)
23058c2ecf20Sopenharmony_ci{
23068c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
23078c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = buf_msg(skb);
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	if (unlikely(msg_in_group(hdr)))
23108c2ecf20Sopenharmony_ci		return READ_ONCE(sk->sk_rcvbuf);
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	if (unlikely(!msg_connected(hdr)))
23138c2ecf20Sopenharmony_ci		return READ_ONCE(sk->sk_rcvbuf) << msg_importance(hdr);
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci	if (likely(tsk->peer_caps & TIPC_BLOCK_FLOWCTL))
23168c2ecf20Sopenharmony_ci		return READ_ONCE(sk->sk_rcvbuf);
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	return FLOWCTL_MSG_LIM;
23198c2ecf20Sopenharmony_ci}
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci/**
23228c2ecf20Sopenharmony_ci * tipc_sk_filter_rcv - validate incoming message
23238c2ecf20Sopenharmony_ci * @sk: socket
23248c2ecf20Sopenharmony_ci * @skb: pointer to message.
23258c2ecf20Sopenharmony_ci *
23268c2ecf20Sopenharmony_ci * Enqueues message on receive queue if acceptable; optionally handles
23278c2ecf20Sopenharmony_ci * disconnect indication for a connected socket.
23288c2ecf20Sopenharmony_ci *
23298c2ecf20Sopenharmony_ci * Called with socket lock already taken
23308c2ecf20Sopenharmony_ci *
23318c2ecf20Sopenharmony_ci */
23328c2ecf20Sopenharmony_cistatic void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb,
23338c2ecf20Sopenharmony_ci			       struct sk_buff_head *xmitq)
23348c2ecf20Sopenharmony_ci{
23358c2ecf20Sopenharmony_ci	bool sk_conn = !tipc_sk_type_connectionless(sk);
23368c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
23378c2ecf20Sopenharmony_ci	struct tipc_group *grp = tsk->group;
23388c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = buf_msg(skb);
23398c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
23408c2ecf20Sopenharmony_ci	struct sk_buff_head inputq;
23418c2ecf20Sopenharmony_ci	int mtyp = msg_type(hdr);
23428c2ecf20Sopenharmony_ci	int limit, err = TIPC_OK;
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	trace_tipc_sk_filter_rcv(sk, skb, TIPC_DUMP_ALL, " ");
23458c2ecf20Sopenharmony_ci	TIPC_SKB_CB(skb)->bytes_read = 0;
23468c2ecf20Sopenharmony_ci	__skb_queue_head_init(&inputq);
23478c2ecf20Sopenharmony_ci	__skb_queue_tail(&inputq, skb);
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	if (unlikely(!msg_isdata(hdr)))
23508c2ecf20Sopenharmony_ci		tipc_sk_proto_rcv(sk, &inputq, xmitq);
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci	if (unlikely(grp))
23538c2ecf20Sopenharmony_ci		tipc_group_filter_msg(grp, &inputq, xmitq);
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	if (unlikely(!grp) && mtyp == TIPC_MCAST_MSG)
23568c2ecf20Sopenharmony_ci		tipc_mcast_filter_msg(net, &tsk->mc_method.deferredq, &inputq);
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	/* Validate and add to receive buffer if there is space */
23598c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&inputq))) {
23608c2ecf20Sopenharmony_ci		hdr = buf_msg(skb);
23618c2ecf20Sopenharmony_ci		limit = rcvbuf_limit(sk, skb);
23628c2ecf20Sopenharmony_ci		if ((sk_conn && !tipc_sk_filter_connect(tsk, skb, xmitq)) ||
23638c2ecf20Sopenharmony_ci		    (!sk_conn && msg_connected(hdr)) ||
23648c2ecf20Sopenharmony_ci		    (!grp && msg_in_group(hdr)))
23658c2ecf20Sopenharmony_ci			err = TIPC_ERR_NO_PORT;
23668c2ecf20Sopenharmony_ci		else if (sk_rmem_alloc_get(sk) + skb->truesize >= limit) {
23678c2ecf20Sopenharmony_ci			trace_tipc_sk_dump(sk, skb, TIPC_DUMP_ALL,
23688c2ecf20Sopenharmony_ci					   "err_overload2!");
23698c2ecf20Sopenharmony_ci			atomic_inc(&sk->sk_drops);
23708c2ecf20Sopenharmony_ci			err = TIPC_ERR_OVERLOAD;
23718c2ecf20Sopenharmony_ci		}
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci		if (unlikely(err)) {
23748c2ecf20Sopenharmony_ci			if (tipc_msg_reverse(tipc_own_addr(net), &skb, err)) {
23758c2ecf20Sopenharmony_ci				trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_NONE,
23768c2ecf20Sopenharmony_ci						      "@filter_rcv!");
23778c2ecf20Sopenharmony_ci				__skb_queue_tail(xmitq, skb);
23788c2ecf20Sopenharmony_ci			}
23798c2ecf20Sopenharmony_ci			err = TIPC_OK;
23808c2ecf20Sopenharmony_ci			continue;
23818c2ecf20Sopenharmony_ci		}
23828c2ecf20Sopenharmony_ci		__skb_queue_tail(&sk->sk_receive_queue, skb);
23838c2ecf20Sopenharmony_ci		skb_set_owner_r(skb, sk);
23848c2ecf20Sopenharmony_ci		trace_tipc_sk_overlimit2(sk, skb, TIPC_DUMP_ALL,
23858c2ecf20Sopenharmony_ci					 "rcvq >90% allocated!");
23868c2ecf20Sopenharmony_ci		sk->sk_data_ready(sk);
23878c2ecf20Sopenharmony_ci	}
23888c2ecf20Sopenharmony_ci}
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci/**
23918c2ecf20Sopenharmony_ci * tipc_sk_backlog_rcv - handle incoming message from backlog queue
23928c2ecf20Sopenharmony_ci * @sk: socket
23938c2ecf20Sopenharmony_ci * @skb: message
23948c2ecf20Sopenharmony_ci *
23958c2ecf20Sopenharmony_ci * Caller must hold socket lock
23968c2ecf20Sopenharmony_ci */
23978c2ecf20Sopenharmony_cistatic int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
23988c2ecf20Sopenharmony_ci{
23998c2ecf20Sopenharmony_ci	unsigned int before = sk_rmem_alloc_get(sk);
24008c2ecf20Sopenharmony_ci	struct sk_buff_head xmitq;
24018c2ecf20Sopenharmony_ci	unsigned int added;
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	__skb_queue_head_init(&xmitq);
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	tipc_sk_filter_rcv(sk, skb, &xmitq);
24068c2ecf20Sopenharmony_ci	added = sk_rmem_alloc_get(sk) - before;
24078c2ecf20Sopenharmony_ci	atomic_add(added, &tipc_sk(sk)->dupl_rcvcnt);
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	/* Send pending response/rejected messages, if any */
24108c2ecf20Sopenharmony_ci	tipc_node_distr_xmit(sock_net(sk), &xmitq);
24118c2ecf20Sopenharmony_ci	return 0;
24128c2ecf20Sopenharmony_ci}
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci/**
24158c2ecf20Sopenharmony_ci * tipc_sk_enqueue - extract all buffers with destination 'dport' from
24168c2ecf20Sopenharmony_ci *                   inputq and try adding them to socket or backlog queue
24178c2ecf20Sopenharmony_ci * @inputq: list of incoming buffers with potentially different destinations
24188c2ecf20Sopenharmony_ci * @sk: socket where the buffers should be enqueued
24198c2ecf20Sopenharmony_ci * @dport: port number for the socket
24208c2ecf20Sopenharmony_ci *
24218c2ecf20Sopenharmony_ci * Caller must hold socket lock
24228c2ecf20Sopenharmony_ci */
24238c2ecf20Sopenharmony_cistatic void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
24248c2ecf20Sopenharmony_ci			    u32 dport, struct sk_buff_head *xmitq)
24258c2ecf20Sopenharmony_ci{
24268c2ecf20Sopenharmony_ci	unsigned long time_limit = jiffies + usecs_to_jiffies(20000);
24278c2ecf20Sopenharmony_ci	struct sk_buff *skb;
24288c2ecf20Sopenharmony_ci	unsigned int lim;
24298c2ecf20Sopenharmony_ci	atomic_t *dcnt;
24308c2ecf20Sopenharmony_ci	u32 onode;
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	while (skb_queue_len(inputq)) {
24338c2ecf20Sopenharmony_ci		if (unlikely(time_after_eq(jiffies, time_limit)))
24348c2ecf20Sopenharmony_ci			return;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci		skb = tipc_skb_dequeue(inputq, dport);
24378c2ecf20Sopenharmony_ci		if (unlikely(!skb))
24388c2ecf20Sopenharmony_ci			return;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci		/* Add message directly to receive queue if possible */
24418c2ecf20Sopenharmony_ci		if (!sock_owned_by_user(sk)) {
24428c2ecf20Sopenharmony_ci			tipc_sk_filter_rcv(sk, skb, xmitq);
24438c2ecf20Sopenharmony_ci			continue;
24448c2ecf20Sopenharmony_ci		}
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci		/* Try backlog, compensating for double-counted bytes */
24478c2ecf20Sopenharmony_ci		dcnt = &tipc_sk(sk)->dupl_rcvcnt;
24488c2ecf20Sopenharmony_ci		if (!sk->sk_backlog.len)
24498c2ecf20Sopenharmony_ci			atomic_set(dcnt, 0);
24508c2ecf20Sopenharmony_ci		lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt);
24518c2ecf20Sopenharmony_ci		if (likely(!sk_add_backlog(sk, skb, lim))) {
24528c2ecf20Sopenharmony_ci			trace_tipc_sk_overlimit1(sk, skb, TIPC_DUMP_ALL,
24538c2ecf20Sopenharmony_ci						 "bklg & rcvq >90% allocated!");
24548c2ecf20Sopenharmony_ci			continue;
24558c2ecf20Sopenharmony_ci		}
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci		trace_tipc_sk_dump(sk, skb, TIPC_DUMP_ALL, "err_overload!");
24588c2ecf20Sopenharmony_ci		/* Overload => reject message back to sender */
24598c2ecf20Sopenharmony_ci		onode = tipc_own_addr(sock_net(sk));
24608c2ecf20Sopenharmony_ci		atomic_inc(&sk->sk_drops);
24618c2ecf20Sopenharmony_ci		if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD)) {
24628c2ecf20Sopenharmony_ci			trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_ALL,
24638c2ecf20Sopenharmony_ci					      "@sk_enqueue!");
24648c2ecf20Sopenharmony_ci			__skb_queue_tail(xmitq, skb);
24658c2ecf20Sopenharmony_ci		}
24668c2ecf20Sopenharmony_ci		break;
24678c2ecf20Sopenharmony_ci	}
24688c2ecf20Sopenharmony_ci}
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci/**
24718c2ecf20Sopenharmony_ci * tipc_sk_rcv - handle a chain of incoming buffers
24728c2ecf20Sopenharmony_ci * @inputq: buffer list containing the buffers
24738c2ecf20Sopenharmony_ci * Consumes all buffers in list until inputq is empty
24748c2ecf20Sopenharmony_ci * Note: may be called in multiple threads referring to the same queue
24758c2ecf20Sopenharmony_ci */
24768c2ecf20Sopenharmony_civoid tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
24778c2ecf20Sopenharmony_ci{
24788c2ecf20Sopenharmony_ci	struct sk_buff_head xmitq;
24798c2ecf20Sopenharmony_ci	u32 dnode, dport = 0;
24808c2ecf20Sopenharmony_ci	int err;
24818c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
24828c2ecf20Sopenharmony_ci	struct sock *sk;
24838c2ecf20Sopenharmony_ci	struct sk_buff *skb;
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	__skb_queue_head_init(&xmitq);
24868c2ecf20Sopenharmony_ci	while (skb_queue_len(inputq)) {
24878c2ecf20Sopenharmony_ci		dport = tipc_skb_peek_port(inputq, dport);
24888c2ecf20Sopenharmony_ci		tsk = tipc_sk_lookup(net, dport);
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci		if (likely(tsk)) {
24918c2ecf20Sopenharmony_ci			sk = &tsk->sk;
24928c2ecf20Sopenharmony_ci			if (likely(spin_trylock_bh(&sk->sk_lock.slock))) {
24938c2ecf20Sopenharmony_ci				tipc_sk_enqueue(inputq, sk, dport, &xmitq);
24948c2ecf20Sopenharmony_ci				spin_unlock_bh(&sk->sk_lock.slock);
24958c2ecf20Sopenharmony_ci			}
24968c2ecf20Sopenharmony_ci			/* Send pending response/rejected messages, if any */
24978c2ecf20Sopenharmony_ci			tipc_node_distr_xmit(sock_net(sk), &xmitq);
24988c2ecf20Sopenharmony_ci			sock_put(sk);
24998c2ecf20Sopenharmony_ci			continue;
25008c2ecf20Sopenharmony_ci		}
25018c2ecf20Sopenharmony_ci		/* No destination socket => dequeue skb if still there */
25028c2ecf20Sopenharmony_ci		skb = tipc_skb_dequeue(inputq, dport);
25038c2ecf20Sopenharmony_ci		if (!skb)
25048c2ecf20Sopenharmony_ci			return;
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci		/* Try secondary lookup if unresolved named message */
25078c2ecf20Sopenharmony_ci		err = TIPC_ERR_NO_PORT;
25088c2ecf20Sopenharmony_ci		if (tipc_msg_lookup_dest(net, skb, &err))
25098c2ecf20Sopenharmony_ci			goto xmit;
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci		/* Prepare for message rejection */
25128c2ecf20Sopenharmony_ci		if (!tipc_msg_reverse(tipc_own_addr(net), &skb, err))
25138c2ecf20Sopenharmony_ci			continue;
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci		trace_tipc_sk_rej_msg(NULL, skb, TIPC_DUMP_NONE, "@sk_rcv!");
25168c2ecf20Sopenharmony_cixmit:
25178c2ecf20Sopenharmony_ci		dnode = msg_destnode(buf_msg(skb));
25188c2ecf20Sopenharmony_ci		tipc_node_xmit_skb(net, skb, dnode, dport);
25198c2ecf20Sopenharmony_ci	}
25208c2ecf20Sopenharmony_ci}
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_cistatic int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
25238c2ecf20Sopenharmony_ci{
25248c2ecf20Sopenharmony_ci	DEFINE_WAIT_FUNC(wait, woken_wake_function);
25258c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
25268c2ecf20Sopenharmony_ci	int done;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	do {
25298c2ecf20Sopenharmony_ci		int err = sock_error(sk);
25308c2ecf20Sopenharmony_ci		if (err)
25318c2ecf20Sopenharmony_ci			return err;
25328c2ecf20Sopenharmony_ci		if (!*timeo_p)
25338c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
25348c2ecf20Sopenharmony_ci		if (signal_pending(current))
25358c2ecf20Sopenharmony_ci			return sock_intr_errno(*timeo_p);
25368c2ecf20Sopenharmony_ci		if (sk->sk_state == TIPC_DISCONNECTING)
25378c2ecf20Sopenharmony_ci			break;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci		add_wait_queue(sk_sleep(sk), &wait);
25408c2ecf20Sopenharmony_ci		done = sk_wait_event(sk, timeo_p, tipc_sk_connected(sk),
25418c2ecf20Sopenharmony_ci				     &wait);
25428c2ecf20Sopenharmony_ci		remove_wait_queue(sk_sleep(sk), &wait);
25438c2ecf20Sopenharmony_ci	} while (!done);
25448c2ecf20Sopenharmony_ci	return 0;
25458c2ecf20Sopenharmony_ci}
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_cistatic bool tipc_sockaddr_is_sane(struct sockaddr_tipc *addr)
25488c2ecf20Sopenharmony_ci{
25498c2ecf20Sopenharmony_ci	if (addr->family != AF_TIPC)
25508c2ecf20Sopenharmony_ci		return false;
25518c2ecf20Sopenharmony_ci	if (addr->addrtype == TIPC_SERVICE_RANGE)
25528c2ecf20Sopenharmony_ci		return (addr->addr.nameseq.lower <= addr->addr.nameseq.upper);
25538c2ecf20Sopenharmony_ci	return (addr->addrtype == TIPC_SERVICE_ADDR ||
25548c2ecf20Sopenharmony_ci		addr->addrtype == TIPC_SOCKET_ADDR);
25558c2ecf20Sopenharmony_ci}
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci/**
25588c2ecf20Sopenharmony_ci * tipc_connect - establish a connection to another TIPC port
25598c2ecf20Sopenharmony_ci * @sock: socket structure
25608c2ecf20Sopenharmony_ci * @dest: socket address for destination port
25618c2ecf20Sopenharmony_ci * @destlen: size of socket address data structure
25628c2ecf20Sopenharmony_ci * @flags: file-related flags associated with socket
25638c2ecf20Sopenharmony_ci *
25648c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
25658c2ecf20Sopenharmony_ci */
25668c2ecf20Sopenharmony_cistatic int tipc_connect(struct socket *sock, struct sockaddr *dest,
25678c2ecf20Sopenharmony_ci			int destlen, int flags)
25688c2ecf20Sopenharmony_ci{
25698c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
25708c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
25718c2ecf20Sopenharmony_ci	struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;
25728c2ecf20Sopenharmony_ci	struct msghdr m = {NULL,};
25738c2ecf20Sopenharmony_ci	long timeout = (flags & O_NONBLOCK) ? 0 : tsk->conn_timeout;
25748c2ecf20Sopenharmony_ci	int previous;
25758c2ecf20Sopenharmony_ci	int res = 0;
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	if (destlen != sizeof(struct sockaddr_tipc))
25788c2ecf20Sopenharmony_ci		return -EINVAL;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	lock_sock(sk);
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci	if (tsk->group) {
25838c2ecf20Sopenharmony_ci		res = -EINVAL;
25848c2ecf20Sopenharmony_ci		goto exit;
25858c2ecf20Sopenharmony_ci	}
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci	if (dst->family == AF_UNSPEC) {
25888c2ecf20Sopenharmony_ci		memset(&tsk->peer, 0, sizeof(struct sockaddr_tipc));
25898c2ecf20Sopenharmony_ci		if (!tipc_sk_type_connectionless(sk))
25908c2ecf20Sopenharmony_ci			res = -EINVAL;
25918c2ecf20Sopenharmony_ci		goto exit;
25928c2ecf20Sopenharmony_ci	}
25938c2ecf20Sopenharmony_ci	if (!tipc_sockaddr_is_sane(dst)) {
25948c2ecf20Sopenharmony_ci		res = -EINVAL;
25958c2ecf20Sopenharmony_ci		goto exit;
25968c2ecf20Sopenharmony_ci	}
25978c2ecf20Sopenharmony_ci	/* DGRAM/RDM connect(), just save the destaddr */
25988c2ecf20Sopenharmony_ci	if (tipc_sk_type_connectionless(sk)) {
25998c2ecf20Sopenharmony_ci		memcpy(&tsk->peer, dest, destlen);
26008c2ecf20Sopenharmony_ci		goto exit;
26018c2ecf20Sopenharmony_ci	} else if (dst->addrtype == TIPC_SERVICE_RANGE) {
26028c2ecf20Sopenharmony_ci		res = -EINVAL;
26038c2ecf20Sopenharmony_ci		goto exit;
26048c2ecf20Sopenharmony_ci	}
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	previous = sk->sk_state;
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
26098c2ecf20Sopenharmony_ci	case TIPC_OPEN:
26108c2ecf20Sopenharmony_ci		/* Send a 'SYN-' to destination */
26118c2ecf20Sopenharmony_ci		m.msg_name = dest;
26128c2ecf20Sopenharmony_ci		m.msg_namelen = destlen;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci		/* If connect is in non-blocking case, set MSG_DONTWAIT to
26158c2ecf20Sopenharmony_ci		 * indicate send_msg() is never blocked.
26168c2ecf20Sopenharmony_ci		 */
26178c2ecf20Sopenharmony_ci		if (!timeout)
26188c2ecf20Sopenharmony_ci			m.msg_flags = MSG_DONTWAIT;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci		res = __tipc_sendmsg(sock, &m, 0);
26218c2ecf20Sopenharmony_ci		if ((res < 0) && (res != -EWOULDBLOCK))
26228c2ecf20Sopenharmony_ci			goto exit;
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci		/* Just entered TIPC_CONNECTING state; the only
26258c2ecf20Sopenharmony_ci		 * difference is that return value in non-blocking
26268c2ecf20Sopenharmony_ci		 * case is EINPROGRESS, rather than EALREADY.
26278c2ecf20Sopenharmony_ci		 */
26288c2ecf20Sopenharmony_ci		res = -EINPROGRESS;
26298c2ecf20Sopenharmony_ci		fallthrough;
26308c2ecf20Sopenharmony_ci	case TIPC_CONNECTING:
26318c2ecf20Sopenharmony_ci		if (!timeout) {
26328c2ecf20Sopenharmony_ci			if (previous == TIPC_CONNECTING)
26338c2ecf20Sopenharmony_ci				res = -EALREADY;
26348c2ecf20Sopenharmony_ci			goto exit;
26358c2ecf20Sopenharmony_ci		}
26368c2ecf20Sopenharmony_ci		timeout = msecs_to_jiffies(timeout);
26378c2ecf20Sopenharmony_ci		/* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */
26388c2ecf20Sopenharmony_ci		res = tipc_wait_for_connect(sock, &timeout);
26398c2ecf20Sopenharmony_ci		break;
26408c2ecf20Sopenharmony_ci	case TIPC_ESTABLISHED:
26418c2ecf20Sopenharmony_ci		res = -EISCONN;
26428c2ecf20Sopenharmony_ci		break;
26438c2ecf20Sopenharmony_ci	default:
26448c2ecf20Sopenharmony_ci		res = -EINVAL;
26458c2ecf20Sopenharmony_ci	}
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ciexit:
26488c2ecf20Sopenharmony_ci	release_sock(sk);
26498c2ecf20Sopenharmony_ci	return res;
26508c2ecf20Sopenharmony_ci}
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci/**
26538c2ecf20Sopenharmony_ci * tipc_listen - allow socket to listen for incoming connections
26548c2ecf20Sopenharmony_ci * @sock: socket structure
26558c2ecf20Sopenharmony_ci * @len: (unused)
26568c2ecf20Sopenharmony_ci *
26578c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
26588c2ecf20Sopenharmony_ci */
26598c2ecf20Sopenharmony_cistatic int tipc_listen(struct socket *sock, int len)
26608c2ecf20Sopenharmony_ci{
26618c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
26628c2ecf20Sopenharmony_ci	int res;
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci	lock_sock(sk);
26658c2ecf20Sopenharmony_ci	res = tipc_set_sk_state(sk, TIPC_LISTEN);
26668c2ecf20Sopenharmony_ci	release_sock(sk);
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	return res;
26698c2ecf20Sopenharmony_ci}
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_cistatic int tipc_wait_for_accept(struct socket *sock, long timeo)
26728c2ecf20Sopenharmony_ci{
26738c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
26748c2ecf20Sopenharmony_ci	DEFINE_WAIT_FUNC(wait, woken_wake_function);
26758c2ecf20Sopenharmony_ci	int err;
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_ci	/* True wake-one mechanism for incoming connections: only
26788c2ecf20Sopenharmony_ci	 * one process gets woken up, not the 'whole herd'.
26798c2ecf20Sopenharmony_ci	 * Since we do not 'race & poll' for established sockets
26808c2ecf20Sopenharmony_ci	 * anymore, the common case will execute the loop only once.
26818c2ecf20Sopenharmony_ci	*/
26828c2ecf20Sopenharmony_ci	for (;;) {
26838c2ecf20Sopenharmony_ci		if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
26848c2ecf20Sopenharmony_ci			add_wait_queue(sk_sleep(sk), &wait);
26858c2ecf20Sopenharmony_ci			release_sock(sk);
26868c2ecf20Sopenharmony_ci			timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
26878c2ecf20Sopenharmony_ci			lock_sock(sk);
26888c2ecf20Sopenharmony_ci			remove_wait_queue(sk_sleep(sk), &wait);
26898c2ecf20Sopenharmony_ci		}
26908c2ecf20Sopenharmony_ci		err = 0;
26918c2ecf20Sopenharmony_ci		if (!skb_queue_empty(&sk->sk_receive_queue))
26928c2ecf20Sopenharmony_ci			break;
26938c2ecf20Sopenharmony_ci		err = -EAGAIN;
26948c2ecf20Sopenharmony_ci		if (!timeo)
26958c2ecf20Sopenharmony_ci			break;
26968c2ecf20Sopenharmony_ci		err = sock_intr_errno(timeo);
26978c2ecf20Sopenharmony_ci		if (signal_pending(current))
26988c2ecf20Sopenharmony_ci			break;
26998c2ecf20Sopenharmony_ci	}
27008c2ecf20Sopenharmony_ci	return err;
27018c2ecf20Sopenharmony_ci}
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_ci/**
27048c2ecf20Sopenharmony_ci * tipc_accept - wait for connection request
27058c2ecf20Sopenharmony_ci * @sock: listening socket
27068c2ecf20Sopenharmony_ci * @new_sock: new socket that is to be connected
27078c2ecf20Sopenharmony_ci * @flags: file-related flags associated with socket
27088c2ecf20Sopenharmony_ci *
27098c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
27108c2ecf20Sopenharmony_ci */
27118c2ecf20Sopenharmony_cistatic int tipc_accept(struct socket *sock, struct socket *new_sock, int flags,
27128c2ecf20Sopenharmony_ci		       bool kern)
27138c2ecf20Sopenharmony_ci{
27148c2ecf20Sopenharmony_ci	struct sock *new_sk, *sk = sock->sk;
27158c2ecf20Sopenharmony_ci	struct tipc_sock *new_tsock;
27168c2ecf20Sopenharmony_ci	struct msghdr m = {NULL,};
27178c2ecf20Sopenharmony_ci	struct tipc_msg *msg;
27188c2ecf20Sopenharmony_ci	struct sk_buff *buf;
27198c2ecf20Sopenharmony_ci	long timeo;
27208c2ecf20Sopenharmony_ci	int res;
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci	lock_sock(sk);
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci	if (sk->sk_state != TIPC_LISTEN) {
27258c2ecf20Sopenharmony_ci		res = -EINVAL;
27268c2ecf20Sopenharmony_ci		goto exit;
27278c2ecf20Sopenharmony_ci	}
27288c2ecf20Sopenharmony_ci	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
27298c2ecf20Sopenharmony_ci	res = tipc_wait_for_accept(sock, timeo);
27308c2ecf20Sopenharmony_ci	if (res)
27318c2ecf20Sopenharmony_ci		goto exit;
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	buf = skb_peek(&sk->sk_receive_queue);
27348c2ecf20Sopenharmony_ci
27358c2ecf20Sopenharmony_ci	res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, kern);
27368c2ecf20Sopenharmony_ci	if (res)
27378c2ecf20Sopenharmony_ci		goto exit;
27388c2ecf20Sopenharmony_ci	security_sk_clone(sock->sk, new_sock->sk);
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci	new_sk = new_sock->sk;
27418c2ecf20Sopenharmony_ci	new_tsock = tipc_sk(new_sk);
27428c2ecf20Sopenharmony_ci	msg = buf_msg(buf);
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	/* we lock on new_sk; but lockdep sees the lock on sk */
27458c2ecf20Sopenharmony_ci	lock_sock_nested(new_sk, SINGLE_DEPTH_NESTING);
27468c2ecf20Sopenharmony_ci
27478c2ecf20Sopenharmony_ci	/*
27488c2ecf20Sopenharmony_ci	 * Reject any stray messages received by new socket
27498c2ecf20Sopenharmony_ci	 * before the socket lock was taken (very, very unlikely)
27508c2ecf20Sopenharmony_ci	 */
27518c2ecf20Sopenharmony_ci	tsk_rej_rx_queue(new_sk, TIPC_ERR_NO_PORT);
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	/* Connect new socket to it's peer */
27548c2ecf20Sopenharmony_ci	tipc_sk_finish_conn(new_tsock, msg_origport(msg), msg_orignode(msg));
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	tsk_set_importance(new_sk, msg_importance(msg));
27578c2ecf20Sopenharmony_ci	if (msg_named(msg)) {
27588c2ecf20Sopenharmony_ci		new_tsock->conn_type = msg_nametype(msg);
27598c2ecf20Sopenharmony_ci		new_tsock->conn_instance = msg_nameinst(msg);
27608c2ecf20Sopenharmony_ci	}
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci	/*
27638c2ecf20Sopenharmony_ci	 * Respond to 'SYN-' by discarding it & returning 'ACK'.
27648c2ecf20Sopenharmony_ci	 * Respond to 'SYN+' by queuing it on new socket & returning 'ACK'.
27658c2ecf20Sopenharmony_ci	 */
27668c2ecf20Sopenharmony_ci	if (!msg_data_sz(msg)) {
27678c2ecf20Sopenharmony_ci		tsk_advance_rx_queue(sk);
27688c2ecf20Sopenharmony_ci	} else {
27698c2ecf20Sopenharmony_ci		__skb_dequeue(&sk->sk_receive_queue);
27708c2ecf20Sopenharmony_ci		__skb_queue_head(&new_sk->sk_receive_queue, buf);
27718c2ecf20Sopenharmony_ci		skb_set_owner_r(buf, new_sk);
27728c2ecf20Sopenharmony_ci	}
27738c2ecf20Sopenharmony_ci	__tipc_sendstream(new_sock, &m, 0);
27748c2ecf20Sopenharmony_ci	release_sock(new_sk);
27758c2ecf20Sopenharmony_ciexit:
27768c2ecf20Sopenharmony_ci	release_sock(sk);
27778c2ecf20Sopenharmony_ci	return res;
27788c2ecf20Sopenharmony_ci}
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_ci/**
27818c2ecf20Sopenharmony_ci * tipc_shutdown - shutdown socket connection
27828c2ecf20Sopenharmony_ci * @sock: socket structure
27838c2ecf20Sopenharmony_ci * @how: direction to close (must be SHUT_RDWR)
27848c2ecf20Sopenharmony_ci *
27858c2ecf20Sopenharmony_ci * Terminates connection (if necessary), then purges socket's receive queue.
27868c2ecf20Sopenharmony_ci *
27878c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
27888c2ecf20Sopenharmony_ci */
27898c2ecf20Sopenharmony_cistatic int tipc_shutdown(struct socket *sock, int how)
27908c2ecf20Sopenharmony_ci{
27918c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
27928c2ecf20Sopenharmony_ci	int res;
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	if (how != SHUT_RDWR)
27958c2ecf20Sopenharmony_ci		return -EINVAL;
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	lock_sock(sk);
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	trace_tipc_sk_shutdown(sk, NULL, TIPC_DUMP_ALL, " ");
28008c2ecf20Sopenharmony_ci	__tipc_shutdown(sock, TIPC_CONN_SHUTDOWN);
28018c2ecf20Sopenharmony_ci	sk->sk_shutdown = SHUTDOWN_MASK;
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	if (sk->sk_state == TIPC_DISCONNECTING) {
28048c2ecf20Sopenharmony_ci		/* Discard any unreceived messages */
28058c2ecf20Sopenharmony_ci		__skb_queue_purge(&sk->sk_receive_queue);
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci		res = 0;
28088c2ecf20Sopenharmony_ci	} else {
28098c2ecf20Sopenharmony_ci		res = -ENOTCONN;
28108c2ecf20Sopenharmony_ci	}
28118c2ecf20Sopenharmony_ci	/* Wake up anyone sleeping in poll. */
28128c2ecf20Sopenharmony_ci	sk->sk_state_change(sk);
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	release_sock(sk);
28158c2ecf20Sopenharmony_ci	return res;
28168c2ecf20Sopenharmony_ci}
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_cistatic void tipc_sk_check_probing_state(struct sock *sk,
28198c2ecf20Sopenharmony_ci					struct sk_buff_head *list)
28208c2ecf20Sopenharmony_ci{
28218c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
28228c2ecf20Sopenharmony_ci	u32 pnode = tsk_peer_node(tsk);
28238c2ecf20Sopenharmony_ci	u32 pport = tsk_peer_port(tsk);
28248c2ecf20Sopenharmony_ci	u32 self = tsk_own_node(tsk);
28258c2ecf20Sopenharmony_ci	u32 oport = tsk->portid;
28268c2ecf20Sopenharmony_ci	struct sk_buff *skb;
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci	if (tsk->probe_unacked) {
28298c2ecf20Sopenharmony_ci		tipc_set_sk_state(sk, TIPC_DISCONNECTING);
28308c2ecf20Sopenharmony_ci		sk->sk_err = ECONNABORTED;
28318c2ecf20Sopenharmony_ci		tipc_node_remove_conn(sock_net(sk), pnode, pport);
28328c2ecf20Sopenharmony_ci		sk->sk_state_change(sk);
28338c2ecf20Sopenharmony_ci		return;
28348c2ecf20Sopenharmony_ci	}
28358c2ecf20Sopenharmony_ci	/* Prepare new probe */
28368c2ecf20Sopenharmony_ci	skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, INT_H_SIZE, 0,
28378c2ecf20Sopenharmony_ci			      pnode, self, pport, oport, TIPC_OK);
28388c2ecf20Sopenharmony_ci	if (skb)
28398c2ecf20Sopenharmony_ci		__skb_queue_tail(list, skb);
28408c2ecf20Sopenharmony_ci	tsk->probe_unacked = true;
28418c2ecf20Sopenharmony_ci	sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV);
28428c2ecf20Sopenharmony_ci}
28438c2ecf20Sopenharmony_ci
28448c2ecf20Sopenharmony_cistatic void tipc_sk_retry_connect(struct sock *sk, struct sk_buff_head *list)
28458c2ecf20Sopenharmony_ci{
28468c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	/* Try again later if dest link is congested */
28498c2ecf20Sopenharmony_ci	if (tsk->cong_link_cnt) {
28508c2ecf20Sopenharmony_ci		sk_reset_timer(sk, &sk->sk_timer,
28518c2ecf20Sopenharmony_ci			       jiffies + msecs_to_jiffies(100));
28528c2ecf20Sopenharmony_ci		return;
28538c2ecf20Sopenharmony_ci	}
28548c2ecf20Sopenharmony_ci	/* Prepare SYN for retransmit */
28558c2ecf20Sopenharmony_ci	tipc_msg_skb_clone(&sk->sk_write_queue, list);
28568c2ecf20Sopenharmony_ci}
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_cistatic void tipc_sk_timeout(struct timer_list *t)
28598c2ecf20Sopenharmony_ci{
28608c2ecf20Sopenharmony_ci	struct sock *sk = from_timer(sk, t, sk_timer);
28618c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
28628c2ecf20Sopenharmony_ci	u32 pnode = tsk_peer_node(tsk);
28638c2ecf20Sopenharmony_ci	struct sk_buff_head list;
28648c2ecf20Sopenharmony_ci	int rc = 0;
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci	__skb_queue_head_init(&list);
28678c2ecf20Sopenharmony_ci	bh_lock_sock(sk);
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci	/* Try again later if socket is busy */
28708c2ecf20Sopenharmony_ci	if (sock_owned_by_user(sk)) {
28718c2ecf20Sopenharmony_ci		sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ / 20);
28728c2ecf20Sopenharmony_ci		bh_unlock_sock(sk);
28738c2ecf20Sopenharmony_ci		sock_put(sk);
28748c2ecf20Sopenharmony_ci		return;
28758c2ecf20Sopenharmony_ci	}
28768c2ecf20Sopenharmony_ci
28778c2ecf20Sopenharmony_ci	if (sk->sk_state == TIPC_ESTABLISHED)
28788c2ecf20Sopenharmony_ci		tipc_sk_check_probing_state(sk, &list);
28798c2ecf20Sopenharmony_ci	else if (sk->sk_state == TIPC_CONNECTING)
28808c2ecf20Sopenharmony_ci		tipc_sk_retry_connect(sk, &list);
28818c2ecf20Sopenharmony_ci
28828c2ecf20Sopenharmony_ci	bh_unlock_sock(sk);
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	if (!skb_queue_empty(&list))
28858c2ecf20Sopenharmony_ci		rc = tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid);
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci	/* SYN messages may cause link congestion */
28888c2ecf20Sopenharmony_ci	if (rc == -ELINKCONG) {
28898c2ecf20Sopenharmony_ci		tipc_dest_push(&tsk->cong_links, pnode, 0);
28908c2ecf20Sopenharmony_ci		tsk->cong_link_cnt = 1;
28918c2ecf20Sopenharmony_ci	}
28928c2ecf20Sopenharmony_ci	sock_put(sk);
28938c2ecf20Sopenharmony_ci}
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_cistatic int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
28968c2ecf20Sopenharmony_ci			   struct tipc_name_seq const *seq)
28978c2ecf20Sopenharmony_ci{
28988c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
28998c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
29008c2ecf20Sopenharmony_ci	struct publication *publ;
29018c2ecf20Sopenharmony_ci	u32 key;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	if (scope != TIPC_NODE_SCOPE)
29048c2ecf20Sopenharmony_ci		scope = TIPC_CLUSTER_SCOPE;
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci	if (tipc_sk_connected(sk))
29078c2ecf20Sopenharmony_ci		return -EINVAL;
29088c2ecf20Sopenharmony_ci	key = tsk->portid + tsk->pub_count + 1;
29098c2ecf20Sopenharmony_ci	if (key == tsk->portid)
29108c2ecf20Sopenharmony_ci		return -EADDRINUSE;
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci	publ = tipc_nametbl_publish(net, seq->type, seq->lower, seq->upper,
29138c2ecf20Sopenharmony_ci				    scope, tsk->portid, key);
29148c2ecf20Sopenharmony_ci	if (unlikely(!publ))
29158c2ecf20Sopenharmony_ci		return -EINVAL;
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	list_add(&publ->binding_sock, &tsk->publications);
29188c2ecf20Sopenharmony_ci	tsk->pub_count++;
29198c2ecf20Sopenharmony_ci	tsk->published = 1;
29208c2ecf20Sopenharmony_ci	return 0;
29218c2ecf20Sopenharmony_ci}
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_cistatic int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
29248c2ecf20Sopenharmony_ci			    struct tipc_name_seq const *seq)
29258c2ecf20Sopenharmony_ci{
29268c2ecf20Sopenharmony_ci	struct net *net = sock_net(&tsk->sk);
29278c2ecf20Sopenharmony_ci	struct publication *publ;
29288c2ecf20Sopenharmony_ci	struct publication *safe;
29298c2ecf20Sopenharmony_ci	int rc = -EINVAL;
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_ci	if (scope != TIPC_NODE_SCOPE)
29328c2ecf20Sopenharmony_ci		scope = TIPC_CLUSTER_SCOPE;
29338c2ecf20Sopenharmony_ci
29348c2ecf20Sopenharmony_ci	list_for_each_entry_safe(publ, safe, &tsk->publications, binding_sock) {
29358c2ecf20Sopenharmony_ci		if (seq) {
29368c2ecf20Sopenharmony_ci			if (publ->scope != scope)
29378c2ecf20Sopenharmony_ci				continue;
29388c2ecf20Sopenharmony_ci			if (publ->type != seq->type)
29398c2ecf20Sopenharmony_ci				continue;
29408c2ecf20Sopenharmony_ci			if (publ->lower != seq->lower)
29418c2ecf20Sopenharmony_ci				continue;
29428c2ecf20Sopenharmony_ci			if (publ->upper != seq->upper)
29438c2ecf20Sopenharmony_ci				break;
29448c2ecf20Sopenharmony_ci			tipc_nametbl_withdraw(net, publ->type, publ->lower,
29458c2ecf20Sopenharmony_ci					      publ->upper, publ->key);
29468c2ecf20Sopenharmony_ci			rc = 0;
29478c2ecf20Sopenharmony_ci			break;
29488c2ecf20Sopenharmony_ci		}
29498c2ecf20Sopenharmony_ci		tipc_nametbl_withdraw(net, publ->type, publ->lower,
29508c2ecf20Sopenharmony_ci				      publ->upper, publ->key);
29518c2ecf20Sopenharmony_ci		rc = 0;
29528c2ecf20Sopenharmony_ci	}
29538c2ecf20Sopenharmony_ci	if (list_empty(&tsk->publications))
29548c2ecf20Sopenharmony_ci		tsk->published = 0;
29558c2ecf20Sopenharmony_ci	return rc;
29568c2ecf20Sopenharmony_ci}
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci/* tipc_sk_reinit: set non-zero address in all existing sockets
29598c2ecf20Sopenharmony_ci *                 when we go from standalone to network mode.
29608c2ecf20Sopenharmony_ci */
29618c2ecf20Sopenharmony_civoid tipc_sk_reinit(struct net *net)
29628c2ecf20Sopenharmony_ci{
29638c2ecf20Sopenharmony_ci	struct tipc_net *tn = net_generic(net, tipc_net_id);
29648c2ecf20Sopenharmony_ci	struct rhashtable_iter iter;
29658c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
29668c2ecf20Sopenharmony_ci	struct tipc_msg *msg;
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci	rhashtable_walk_enter(&tn->sk_rht, &iter);
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	do {
29718c2ecf20Sopenharmony_ci		rhashtable_walk_start(&iter);
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci		while ((tsk = rhashtable_walk_next(&iter)) && !IS_ERR(tsk)) {
29748c2ecf20Sopenharmony_ci			sock_hold(&tsk->sk);
29758c2ecf20Sopenharmony_ci			rhashtable_walk_stop(&iter);
29768c2ecf20Sopenharmony_ci			lock_sock(&tsk->sk);
29778c2ecf20Sopenharmony_ci			msg = &tsk->phdr;
29788c2ecf20Sopenharmony_ci			msg_set_prevnode(msg, tipc_own_addr(net));
29798c2ecf20Sopenharmony_ci			msg_set_orignode(msg, tipc_own_addr(net));
29808c2ecf20Sopenharmony_ci			release_sock(&tsk->sk);
29818c2ecf20Sopenharmony_ci			rhashtable_walk_start(&iter);
29828c2ecf20Sopenharmony_ci			sock_put(&tsk->sk);
29838c2ecf20Sopenharmony_ci		}
29848c2ecf20Sopenharmony_ci
29858c2ecf20Sopenharmony_ci		rhashtable_walk_stop(&iter);
29868c2ecf20Sopenharmony_ci	} while (tsk == ERR_PTR(-EAGAIN));
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	rhashtable_walk_exit(&iter);
29898c2ecf20Sopenharmony_ci}
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_cistatic struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid)
29928c2ecf20Sopenharmony_ci{
29938c2ecf20Sopenharmony_ci	struct tipc_net *tn = net_generic(net, tipc_net_id);
29948c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	rcu_read_lock();
29978c2ecf20Sopenharmony_ci	tsk = rhashtable_lookup(&tn->sk_rht, &portid, tsk_rht_params);
29988c2ecf20Sopenharmony_ci	if (tsk)
29998c2ecf20Sopenharmony_ci		sock_hold(&tsk->sk);
30008c2ecf20Sopenharmony_ci	rcu_read_unlock();
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci	return tsk;
30038c2ecf20Sopenharmony_ci}
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_cistatic int tipc_sk_insert(struct tipc_sock *tsk)
30068c2ecf20Sopenharmony_ci{
30078c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
30088c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
30098c2ecf20Sopenharmony_ci	struct tipc_net *tn = net_generic(net, tipc_net_id);
30108c2ecf20Sopenharmony_ci	u32 remaining = (TIPC_MAX_PORT - TIPC_MIN_PORT) + 1;
30118c2ecf20Sopenharmony_ci	u32 portid = prandom_u32() % remaining + TIPC_MIN_PORT;
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_ci	while (remaining--) {
30148c2ecf20Sopenharmony_ci		portid++;
30158c2ecf20Sopenharmony_ci		if ((portid < TIPC_MIN_PORT) || (portid > TIPC_MAX_PORT))
30168c2ecf20Sopenharmony_ci			portid = TIPC_MIN_PORT;
30178c2ecf20Sopenharmony_ci		tsk->portid = portid;
30188c2ecf20Sopenharmony_ci		sock_hold(&tsk->sk);
30198c2ecf20Sopenharmony_ci		if (!rhashtable_lookup_insert_fast(&tn->sk_rht, &tsk->node,
30208c2ecf20Sopenharmony_ci						   tsk_rht_params))
30218c2ecf20Sopenharmony_ci			return 0;
30228c2ecf20Sopenharmony_ci		sock_put(&tsk->sk);
30238c2ecf20Sopenharmony_ci	}
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	return -1;
30268c2ecf20Sopenharmony_ci}
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_cistatic void tipc_sk_remove(struct tipc_sock *tsk)
30298c2ecf20Sopenharmony_ci{
30308c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
30318c2ecf20Sopenharmony_ci	struct tipc_net *tn = net_generic(sock_net(sk), tipc_net_id);
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci	if (!rhashtable_remove_fast(&tn->sk_rht, &tsk->node, tsk_rht_params)) {
30348c2ecf20Sopenharmony_ci		WARN_ON(refcount_read(&sk->sk_refcnt) == 1);
30358c2ecf20Sopenharmony_ci		__sock_put(sk);
30368c2ecf20Sopenharmony_ci	}
30378c2ecf20Sopenharmony_ci}
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_cistatic const struct rhashtable_params tsk_rht_params = {
30408c2ecf20Sopenharmony_ci	.nelem_hint = 192,
30418c2ecf20Sopenharmony_ci	.head_offset = offsetof(struct tipc_sock, node),
30428c2ecf20Sopenharmony_ci	.key_offset = offsetof(struct tipc_sock, portid),
30438c2ecf20Sopenharmony_ci	.key_len = sizeof(u32), /* portid */
30448c2ecf20Sopenharmony_ci	.max_size = 1048576,
30458c2ecf20Sopenharmony_ci	.min_size = 256,
30468c2ecf20Sopenharmony_ci	.automatic_shrinking = true,
30478c2ecf20Sopenharmony_ci};
30488c2ecf20Sopenharmony_ci
30498c2ecf20Sopenharmony_ciint tipc_sk_rht_init(struct net *net)
30508c2ecf20Sopenharmony_ci{
30518c2ecf20Sopenharmony_ci	struct tipc_net *tn = net_generic(net, tipc_net_id);
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci	return rhashtable_init(&tn->sk_rht, &tsk_rht_params);
30548c2ecf20Sopenharmony_ci}
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_civoid tipc_sk_rht_destroy(struct net *net)
30578c2ecf20Sopenharmony_ci{
30588c2ecf20Sopenharmony_ci	struct tipc_net *tn = net_generic(net, tipc_net_id);
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci	/* Wait for socket readers to complete */
30618c2ecf20Sopenharmony_ci	synchronize_net();
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	rhashtable_destroy(&tn->sk_rht);
30648c2ecf20Sopenharmony_ci}
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_cistatic int tipc_sk_join(struct tipc_sock *tsk, struct tipc_group_req *mreq)
30678c2ecf20Sopenharmony_ci{
30688c2ecf20Sopenharmony_ci	struct net *net = sock_net(&tsk->sk);
30698c2ecf20Sopenharmony_ci	struct tipc_group *grp = tsk->group;
30708c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = &tsk->phdr;
30718c2ecf20Sopenharmony_ci	struct tipc_name_seq seq;
30728c2ecf20Sopenharmony_ci	int rc;
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci	if (mreq->type < TIPC_RESERVED_TYPES)
30758c2ecf20Sopenharmony_ci		return -EACCES;
30768c2ecf20Sopenharmony_ci	if (mreq->scope > TIPC_NODE_SCOPE)
30778c2ecf20Sopenharmony_ci		return -EINVAL;
30788c2ecf20Sopenharmony_ci	if (grp)
30798c2ecf20Sopenharmony_ci		return -EACCES;
30808c2ecf20Sopenharmony_ci	grp = tipc_group_create(net, tsk->portid, mreq, &tsk->group_is_open);
30818c2ecf20Sopenharmony_ci	if (!grp)
30828c2ecf20Sopenharmony_ci		return -ENOMEM;
30838c2ecf20Sopenharmony_ci	tsk->group = grp;
30848c2ecf20Sopenharmony_ci	msg_set_lookup_scope(hdr, mreq->scope);
30858c2ecf20Sopenharmony_ci	msg_set_nametype(hdr, mreq->type);
30868c2ecf20Sopenharmony_ci	msg_set_dest_droppable(hdr, true);
30878c2ecf20Sopenharmony_ci	seq.type = mreq->type;
30888c2ecf20Sopenharmony_ci	seq.lower = mreq->instance;
30898c2ecf20Sopenharmony_ci	seq.upper = seq.lower;
30908c2ecf20Sopenharmony_ci	tipc_nametbl_build_group(net, grp, mreq->type, mreq->scope);
30918c2ecf20Sopenharmony_ci	rc = tipc_sk_publish(tsk, mreq->scope, &seq);
30928c2ecf20Sopenharmony_ci	if (rc) {
30938c2ecf20Sopenharmony_ci		tipc_group_delete(net, grp);
30948c2ecf20Sopenharmony_ci		tsk->group = NULL;
30958c2ecf20Sopenharmony_ci		return rc;
30968c2ecf20Sopenharmony_ci	}
30978c2ecf20Sopenharmony_ci	/* Eliminate any risk that a broadcast overtakes sent JOINs */
30988c2ecf20Sopenharmony_ci	tsk->mc_method.rcast = true;
30998c2ecf20Sopenharmony_ci	tsk->mc_method.mandatory = true;
31008c2ecf20Sopenharmony_ci	tipc_group_join(net, grp, &tsk->sk.sk_rcvbuf);
31018c2ecf20Sopenharmony_ci	return rc;
31028c2ecf20Sopenharmony_ci}
31038c2ecf20Sopenharmony_ci
31048c2ecf20Sopenharmony_cistatic int tipc_sk_leave(struct tipc_sock *tsk)
31058c2ecf20Sopenharmony_ci{
31068c2ecf20Sopenharmony_ci	struct net *net = sock_net(&tsk->sk);
31078c2ecf20Sopenharmony_ci	struct tipc_group *grp = tsk->group;
31088c2ecf20Sopenharmony_ci	struct tipc_name_seq seq;
31098c2ecf20Sopenharmony_ci	int scope;
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_ci	if (!grp)
31128c2ecf20Sopenharmony_ci		return -EINVAL;
31138c2ecf20Sopenharmony_ci	tipc_group_self(grp, &seq, &scope);
31148c2ecf20Sopenharmony_ci	tipc_group_delete(net, grp);
31158c2ecf20Sopenharmony_ci	tsk->group = NULL;
31168c2ecf20Sopenharmony_ci	tipc_sk_withdraw(tsk, scope, &seq);
31178c2ecf20Sopenharmony_ci	return 0;
31188c2ecf20Sopenharmony_ci}
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_ci/**
31218c2ecf20Sopenharmony_ci * tipc_setsockopt - set socket option
31228c2ecf20Sopenharmony_ci * @sock: socket structure
31238c2ecf20Sopenharmony_ci * @lvl: option level
31248c2ecf20Sopenharmony_ci * @opt: option identifier
31258c2ecf20Sopenharmony_ci * @ov: pointer to new option value
31268c2ecf20Sopenharmony_ci * @ol: length of option value
31278c2ecf20Sopenharmony_ci *
31288c2ecf20Sopenharmony_ci * For stream sockets only, accepts and ignores all IPPROTO_TCP options
31298c2ecf20Sopenharmony_ci * (to ease compatibility).
31308c2ecf20Sopenharmony_ci *
31318c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
31328c2ecf20Sopenharmony_ci */
31338c2ecf20Sopenharmony_cistatic int tipc_setsockopt(struct socket *sock, int lvl, int opt,
31348c2ecf20Sopenharmony_ci			   sockptr_t ov, unsigned int ol)
31358c2ecf20Sopenharmony_ci{
31368c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
31378c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
31388c2ecf20Sopenharmony_ci	struct tipc_group_req mreq;
31398c2ecf20Sopenharmony_ci	u32 value = 0;
31408c2ecf20Sopenharmony_ci	int res = 0;
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM))
31438c2ecf20Sopenharmony_ci		return 0;
31448c2ecf20Sopenharmony_ci	if (lvl != SOL_TIPC)
31458c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
31468c2ecf20Sopenharmony_ci
31478c2ecf20Sopenharmony_ci	switch (opt) {
31488c2ecf20Sopenharmony_ci	case TIPC_IMPORTANCE:
31498c2ecf20Sopenharmony_ci	case TIPC_SRC_DROPPABLE:
31508c2ecf20Sopenharmony_ci	case TIPC_DEST_DROPPABLE:
31518c2ecf20Sopenharmony_ci	case TIPC_CONN_TIMEOUT:
31528c2ecf20Sopenharmony_ci	case TIPC_NODELAY:
31538c2ecf20Sopenharmony_ci		if (ol < sizeof(value))
31548c2ecf20Sopenharmony_ci			return -EINVAL;
31558c2ecf20Sopenharmony_ci		if (copy_from_sockptr(&value, ov, sizeof(u32)))
31568c2ecf20Sopenharmony_ci			return -EFAULT;
31578c2ecf20Sopenharmony_ci		break;
31588c2ecf20Sopenharmony_ci	case TIPC_GROUP_JOIN:
31598c2ecf20Sopenharmony_ci		if (ol < sizeof(mreq))
31608c2ecf20Sopenharmony_ci			return -EINVAL;
31618c2ecf20Sopenharmony_ci		if (copy_from_sockptr(&mreq, ov, sizeof(mreq)))
31628c2ecf20Sopenharmony_ci			return -EFAULT;
31638c2ecf20Sopenharmony_ci		break;
31648c2ecf20Sopenharmony_ci	default:
31658c2ecf20Sopenharmony_ci		if (!sockptr_is_null(ov) || ol)
31668c2ecf20Sopenharmony_ci			return -EINVAL;
31678c2ecf20Sopenharmony_ci	}
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci	lock_sock(sk);
31708c2ecf20Sopenharmony_ci
31718c2ecf20Sopenharmony_ci	switch (opt) {
31728c2ecf20Sopenharmony_ci	case TIPC_IMPORTANCE:
31738c2ecf20Sopenharmony_ci		res = tsk_set_importance(sk, value);
31748c2ecf20Sopenharmony_ci		break;
31758c2ecf20Sopenharmony_ci	case TIPC_SRC_DROPPABLE:
31768c2ecf20Sopenharmony_ci		if (sock->type != SOCK_STREAM)
31778c2ecf20Sopenharmony_ci			tsk_set_unreliable(tsk, value);
31788c2ecf20Sopenharmony_ci		else
31798c2ecf20Sopenharmony_ci			res = -ENOPROTOOPT;
31808c2ecf20Sopenharmony_ci		break;
31818c2ecf20Sopenharmony_ci	case TIPC_DEST_DROPPABLE:
31828c2ecf20Sopenharmony_ci		tsk_set_unreturnable(tsk, value);
31838c2ecf20Sopenharmony_ci		break;
31848c2ecf20Sopenharmony_ci	case TIPC_CONN_TIMEOUT:
31858c2ecf20Sopenharmony_ci		tipc_sk(sk)->conn_timeout = value;
31868c2ecf20Sopenharmony_ci		break;
31878c2ecf20Sopenharmony_ci	case TIPC_MCAST_BROADCAST:
31888c2ecf20Sopenharmony_ci		tsk->mc_method.rcast = false;
31898c2ecf20Sopenharmony_ci		tsk->mc_method.mandatory = true;
31908c2ecf20Sopenharmony_ci		break;
31918c2ecf20Sopenharmony_ci	case TIPC_MCAST_REPLICAST:
31928c2ecf20Sopenharmony_ci		tsk->mc_method.rcast = true;
31938c2ecf20Sopenharmony_ci		tsk->mc_method.mandatory = true;
31948c2ecf20Sopenharmony_ci		break;
31958c2ecf20Sopenharmony_ci	case TIPC_GROUP_JOIN:
31968c2ecf20Sopenharmony_ci		res = tipc_sk_join(tsk, &mreq);
31978c2ecf20Sopenharmony_ci		break;
31988c2ecf20Sopenharmony_ci	case TIPC_GROUP_LEAVE:
31998c2ecf20Sopenharmony_ci		res = tipc_sk_leave(tsk);
32008c2ecf20Sopenharmony_ci		break;
32018c2ecf20Sopenharmony_ci	case TIPC_NODELAY:
32028c2ecf20Sopenharmony_ci		tsk->nodelay = !!value;
32038c2ecf20Sopenharmony_ci		tsk_set_nagle(tsk);
32048c2ecf20Sopenharmony_ci		break;
32058c2ecf20Sopenharmony_ci	default:
32068c2ecf20Sopenharmony_ci		res = -EINVAL;
32078c2ecf20Sopenharmony_ci	}
32088c2ecf20Sopenharmony_ci
32098c2ecf20Sopenharmony_ci	release_sock(sk);
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci	return res;
32128c2ecf20Sopenharmony_ci}
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_ci/**
32158c2ecf20Sopenharmony_ci * tipc_getsockopt - get socket option
32168c2ecf20Sopenharmony_ci * @sock: socket structure
32178c2ecf20Sopenharmony_ci * @lvl: option level
32188c2ecf20Sopenharmony_ci * @opt: option identifier
32198c2ecf20Sopenharmony_ci * @ov: receptacle for option value
32208c2ecf20Sopenharmony_ci * @ol: receptacle for length of option value
32218c2ecf20Sopenharmony_ci *
32228c2ecf20Sopenharmony_ci * For stream sockets only, returns 0 length result for all IPPROTO_TCP options
32238c2ecf20Sopenharmony_ci * (to ease compatibility).
32248c2ecf20Sopenharmony_ci *
32258c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
32268c2ecf20Sopenharmony_ci */
32278c2ecf20Sopenharmony_cistatic int tipc_getsockopt(struct socket *sock, int lvl, int opt,
32288c2ecf20Sopenharmony_ci			   char __user *ov, int __user *ol)
32298c2ecf20Sopenharmony_ci{
32308c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
32318c2ecf20Sopenharmony_ci	struct tipc_sock *tsk = tipc_sk(sk);
32328c2ecf20Sopenharmony_ci	struct tipc_name_seq seq;
32338c2ecf20Sopenharmony_ci	int len, scope;
32348c2ecf20Sopenharmony_ci	u32 value;
32358c2ecf20Sopenharmony_ci	int res;
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_ci	if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM))
32388c2ecf20Sopenharmony_ci		return put_user(0, ol);
32398c2ecf20Sopenharmony_ci	if (lvl != SOL_TIPC)
32408c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
32418c2ecf20Sopenharmony_ci	res = get_user(len, ol);
32428c2ecf20Sopenharmony_ci	if (res)
32438c2ecf20Sopenharmony_ci		return res;
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci	lock_sock(sk);
32468c2ecf20Sopenharmony_ci
32478c2ecf20Sopenharmony_ci	switch (opt) {
32488c2ecf20Sopenharmony_ci	case TIPC_IMPORTANCE:
32498c2ecf20Sopenharmony_ci		value = tsk_importance(tsk);
32508c2ecf20Sopenharmony_ci		break;
32518c2ecf20Sopenharmony_ci	case TIPC_SRC_DROPPABLE:
32528c2ecf20Sopenharmony_ci		value = tsk_unreliable(tsk);
32538c2ecf20Sopenharmony_ci		break;
32548c2ecf20Sopenharmony_ci	case TIPC_DEST_DROPPABLE:
32558c2ecf20Sopenharmony_ci		value = tsk_unreturnable(tsk);
32568c2ecf20Sopenharmony_ci		break;
32578c2ecf20Sopenharmony_ci	case TIPC_CONN_TIMEOUT:
32588c2ecf20Sopenharmony_ci		value = tsk->conn_timeout;
32598c2ecf20Sopenharmony_ci		/* no need to set "res", since already 0 at this point */
32608c2ecf20Sopenharmony_ci		break;
32618c2ecf20Sopenharmony_ci	case TIPC_NODE_RECVQ_DEPTH:
32628c2ecf20Sopenharmony_ci		value = 0; /* was tipc_queue_size, now obsolete */
32638c2ecf20Sopenharmony_ci		break;
32648c2ecf20Sopenharmony_ci	case TIPC_SOCK_RECVQ_DEPTH:
32658c2ecf20Sopenharmony_ci		value = skb_queue_len(&sk->sk_receive_queue);
32668c2ecf20Sopenharmony_ci		break;
32678c2ecf20Sopenharmony_ci	case TIPC_SOCK_RECVQ_USED:
32688c2ecf20Sopenharmony_ci		value = sk_rmem_alloc_get(sk);
32698c2ecf20Sopenharmony_ci		break;
32708c2ecf20Sopenharmony_ci	case TIPC_GROUP_JOIN:
32718c2ecf20Sopenharmony_ci		seq.type = 0;
32728c2ecf20Sopenharmony_ci		if (tsk->group)
32738c2ecf20Sopenharmony_ci			tipc_group_self(tsk->group, &seq, &scope);
32748c2ecf20Sopenharmony_ci		value = seq.type;
32758c2ecf20Sopenharmony_ci		break;
32768c2ecf20Sopenharmony_ci	default:
32778c2ecf20Sopenharmony_ci		res = -EINVAL;
32788c2ecf20Sopenharmony_ci	}
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci	release_sock(sk);
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_ci	if (res)
32838c2ecf20Sopenharmony_ci		return res;	/* "get" failed */
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ci	if (len < sizeof(value))
32868c2ecf20Sopenharmony_ci		return -EINVAL;
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_ci	if (copy_to_user(ov, &value, sizeof(value)))
32898c2ecf20Sopenharmony_ci		return -EFAULT;
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_ci	return put_user(sizeof(value), ol);
32928c2ecf20Sopenharmony_ci}
32938c2ecf20Sopenharmony_ci
32948c2ecf20Sopenharmony_cistatic int tipc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
32958c2ecf20Sopenharmony_ci{
32968c2ecf20Sopenharmony_ci	struct net *net = sock_net(sock->sk);
32978c2ecf20Sopenharmony_ci	struct tipc_sioc_nodeid_req nr = {0};
32988c2ecf20Sopenharmony_ci	struct tipc_sioc_ln_req lnr;
32998c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
33008c2ecf20Sopenharmony_ci
33018c2ecf20Sopenharmony_ci	switch (cmd) {
33028c2ecf20Sopenharmony_ci	case SIOCGETLINKNAME:
33038c2ecf20Sopenharmony_ci		if (copy_from_user(&lnr, argp, sizeof(lnr)))
33048c2ecf20Sopenharmony_ci			return -EFAULT;
33058c2ecf20Sopenharmony_ci		if (!tipc_node_get_linkname(net,
33068c2ecf20Sopenharmony_ci					    lnr.bearer_id & 0xffff, lnr.peer,
33078c2ecf20Sopenharmony_ci					    lnr.linkname, TIPC_MAX_LINK_NAME)) {
33088c2ecf20Sopenharmony_ci			if (copy_to_user(argp, &lnr, sizeof(lnr)))
33098c2ecf20Sopenharmony_ci				return -EFAULT;
33108c2ecf20Sopenharmony_ci			return 0;
33118c2ecf20Sopenharmony_ci		}
33128c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
33138c2ecf20Sopenharmony_ci	case SIOCGETNODEID:
33148c2ecf20Sopenharmony_ci		if (copy_from_user(&nr, argp, sizeof(nr)))
33158c2ecf20Sopenharmony_ci			return -EFAULT;
33168c2ecf20Sopenharmony_ci		if (!tipc_node_get_id(net, nr.peer, nr.node_id))
33178c2ecf20Sopenharmony_ci			return -EADDRNOTAVAIL;
33188c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &nr, sizeof(nr)))
33198c2ecf20Sopenharmony_ci			return -EFAULT;
33208c2ecf20Sopenharmony_ci		return 0;
33218c2ecf20Sopenharmony_ci	default:
33228c2ecf20Sopenharmony_ci		return -ENOIOCTLCMD;
33238c2ecf20Sopenharmony_ci	}
33248c2ecf20Sopenharmony_ci}
33258c2ecf20Sopenharmony_ci
33268c2ecf20Sopenharmony_cistatic int tipc_socketpair(struct socket *sock1, struct socket *sock2)
33278c2ecf20Sopenharmony_ci{
33288c2ecf20Sopenharmony_ci	struct tipc_sock *tsk2 = tipc_sk(sock2->sk);
33298c2ecf20Sopenharmony_ci	struct tipc_sock *tsk1 = tipc_sk(sock1->sk);
33308c2ecf20Sopenharmony_ci	u32 onode = tipc_own_addr(sock_net(sock1->sk));
33318c2ecf20Sopenharmony_ci
33328c2ecf20Sopenharmony_ci	tsk1->peer.family = AF_TIPC;
33338c2ecf20Sopenharmony_ci	tsk1->peer.addrtype = TIPC_ADDR_ID;
33348c2ecf20Sopenharmony_ci	tsk1->peer.scope = TIPC_NODE_SCOPE;
33358c2ecf20Sopenharmony_ci	tsk1->peer.addr.id.ref = tsk2->portid;
33368c2ecf20Sopenharmony_ci	tsk1->peer.addr.id.node = onode;
33378c2ecf20Sopenharmony_ci	tsk2->peer.family = AF_TIPC;
33388c2ecf20Sopenharmony_ci	tsk2->peer.addrtype = TIPC_ADDR_ID;
33398c2ecf20Sopenharmony_ci	tsk2->peer.scope = TIPC_NODE_SCOPE;
33408c2ecf20Sopenharmony_ci	tsk2->peer.addr.id.ref = tsk1->portid;
33418c2ecf20Sopenharmony_ci	tsk2->peer.addr.id.node = onode;
33428c2ecf20Sopenharmony_ci
33438c2ecf20Sopenharmony_ci	tipc_sk_finish_conn(tsk1, tsk2->portid, onode);
33448c2ecf20Sopenharmony_ci	tipc_sk_finish_conn(tsk2, tsk1->portid, onode);
33458c2ecf20Sopenharmony_ci	return 0;
33468c2ecf20Sopenharmony_ci}
33478c2ecf20Sopenharmony_ci
33488c2ecf20Sopenharmony_ci/* Protocol switches for the various types of TIPC sockets */
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_cistatic const struct proto_ops msg_ops = {
33518c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
33528c2ecf20Sopenharmony_ci	.family		= AF_TIPC,
33538c2ecf20Sopenharmony_ci	.release	= tipc_release,
33548c2ecf20Sopenharmony_ci	.bind		= tipc_bind,
33558c2ecf20Sopenharmony_ci	.connect	= tipc_connect,
33568c2ecf20Sopenharmony_ci	.socketpair	= tipc_socketpair,
33578c2ecf20Sopenharmony_ci	.accept		= sock_no_accept,
33588c2ecf20Sopenharmony_ci	.getname	= tipc_getname,
33598c2ecf20Sopenharmony_ci	.poll		= tipc_poll,
33608c2ecf20Sopenharmony_ci	.ioctl		= tipc_ioctl,
33618c2ecf20Sopenharmony_ci	.listen		= sock_no_listen,
33628c2ecf20Sopenharmony_ci	.shutdown	= tipc_shutdown,
33638c2ecf20Sopenharmony_ci	.setsockopt	= tipc_setsockopt,
33648c2ecf20Sopenharmony_ci	.getsockopt	= tipc_getsockopt,
33658c2ecf20Sopenharmony_ci	.sendmsg	= tipc_sendmsg,
33668c2ecf20Sopenharmony_ci	.recvmsg	= tipc_recvmsg,
33678c2ecf20Sopenharmony_ci	.mmap		= sock_no_mmap,
33688c2ecf20Sopenharmony_ci	.sendpage	= sock_no_sendpage
33698c2ecf20Sopenharmony_ci};
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_cistatic const struct proto_ops packet_ops = {
33728c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
33738c2ecf20Sopenharmony_ci	.family		= AF_TIPC,
33748c2ecf20Sopenharmony_ci	.release	= tipc_release,
33758c2ecf20Sopenharmony_ci	.bind		= tipc_bind,
33768c2ecf20Sopenharmony_ci	.connect	= tipc_connect,
33778c2ecf20Sopenharmony_ci	.socketpair	= tipc_socketpair,
33788c2ecf20Sopenharmony_ci	.accept		= tipc_accept,
33798c2ecf20Sopenharmony_ci	.getname	= tipc_getname,
33808c2ecf20Sopenharmony_ci	.poll		= tipc_poll,
33818c2ecf20Sopenharmony_ci	.ioctl		= tipc_ioctl,
33828c2ecf20Sopenharmony_ci	.listen		= tipc_listen,
33838c2ecf20Sopenharmony_ci	.shutdown	= tipc_shutdown,
33848c2ecf20Sopenharmony_ci	.setsockopt	= tipc_setsockopt,
33858c2ecf20Sopenharmony_ci	.getsockopt	= tipc_getsockopt,
33868c2ecf20Sopenharmony_ci	.sendmsg	= tipc_send_packet,
33878c2ecf20Sopenharmony_ci	.recvmsg	= tipc_recvmsg,
33888c2ecf20Sopenharmony_ci	.mmap		= sock_no_mmap,
33898c2ecf20Sopenharmony_ci	.sendpage	= sock_no_sendpage
33908c2ecf20Sopenharmony_ci};
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_cistatic const struct proto_ops stream_ops = {
33938c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
33948c2ecf20Sopenharmony_ci	.family		= AF_TIPC,
33958c2ecf20Sopenharmony_ci	.release	= tipc_release,
33968c2ecf20Sopenharmony_ci	.bind		= tipc_bind,
33978c2ecf20Sopenharmony_ci	.connect	= tipc_connect,
33988c2ecf20Sopenharmony_ci	.socketpair	= tipc_socketpair,
33998c2ecf20Sopenharmony_ci	.accept		= tipc_accept,
34008c2ecf20Sopenharmony_ci	.getname	= tipc_getname,
34018c2ecf20Sopenharmony_ci	.poll		= tipc_poll,
34028c2ecf20Sopenharmony_ci	.ioctl		= tipc_ioctl,
34038c2ecf20Sopenharmony_ci	.listen		= tipc_listen,
34048c2ecf20Sopenharmony_ci	.shutdown	= tipc_shutdown,
34058c2ecf20Sopenharmony_ci	.setsockopt	= tipc_setsockopt,
34068c2ecf20Sopenharmony_ci	.getsockopt	= tipc_getsockopt,
34078c2ecf20Sopenharmony_ci	.sendmsg	= tipc_sendstream,
34088c2ecf20Sopenharmony_ci	.recvmsg	= tipc_recvstream,
34098c2ecf20Sopenharmony_ci	.mmap		= sock_no_mmap,
34108c2ecf20Sopenharmony_ci	.sendpage	= sock_no_sendpage
34118c2ecf20Sopenharmony_ci};
34128c2ecf20Sopenharmony_ci
34138c2ecf20Sopenharmony_cistatic const struct net_proto_family tipc_family_ops = {
34148c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
34158c2ecf20Sopenharmony_ci	.family		= AF_TIPC,
34168c2ecf20Sopenharmony_ci	.create		= tipc_sk_create
34178c2ecf20Sopenharmony_ci};
34188c2ecf20Sopenharmony_ci
34198c2ecf20Sopenharmony_cistatic struct proto tipc_proto = {
34208c2ecf20Sopenharmony_ci	.name		= "TIPC",
34218c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
34228c2ecf20Sopenharmony_ci	.obj_size	= sizeof(struct tipc_sock),
34238c2ecf20Sopenharmony_ci	.sysctl_rmem	= sysctl_tipc_rmem
34248c2ecf20Sopenharmony_ci};
34258c2ecf20Sopenharmony_ci
34268c2ecf20Sopenharmony_ci/**
34278c2ecf20Sopenharmony_ci * tipc_socket_init - initialize TIPC socket interface
34288c2ecf20Sopenharmony_ci *
34298c2ecf20Sopenharmony_ci * Returns 0 on success, errno otherwise
34308c2ecf20Sopenharmony_ci */
34318c2ecf20Sopenharmony_ciint tipc_socket_init(void)
34328c2ecf20Sopenharmony_ci{
34338c2ecf20Sopenharmony_ci	int res;
34348c2ecf20Sopenharmony_ci
34358c2ecf20Sopenharmony_ci	res = proto_register(&tipc_proto, 1);
34368c2ecf20Sopenharmony_ci	if (res) {
34378c2ecf20Sopenharmony_ci		pr_err("Failed to register TIPC protocol type\n");
34388c2ecf20Sopenharmony_ci		goto out;
34398c2ecf20Sopenharmony_ci	}
34408c2ecf20Sopenharmony_ci
34418c2ecf20Sopenharmony_ci	res = sock_register(&tipc_family_ops);
34428c2ecf20Sopenharmony_ci	if (res) {
34438c2ecf20Sopenharmony_ci		pr_err("Failed to register TIPC socket type\n");
34448c2ecf20Sopenharmony_ci		proto_unregister(&tipc_proto);
34458c2ecf20Sopenharmony_ci		goto out;
34468c2ecf20Sopenharmony_ci	}
34478c2ecf20Sopenharmony_ci out:
34488c2ecf20Sopenharmony_ci	return res;
34498c2ecf20Sopenharmony_ci}
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_ci/**
34528c2ecf20Sopenharmony_ci * tipc_socket_stop - stop TIPC socket interface
34538c2ecf20Sopenharmony_ci */
34548c2ecf20Sopenharmony_civoid tipc_socket_stop(void)
34558c2ecf20Sopenharmony_ci{
34568c2ecf20Sopenharmony_ci	sock_unregister(tipc_family_ops.family);
34578c2ecf20Sopenharmony_ci	proto_unregister(&tipc_proto);
34588c2ecf20Sopenharmony_ci}
34598c2ecf20Sopenharmony_ci
34608c2ecf20Sopenharmony_ci/* Caller should hold socket lock for the passed tipc socket. */
34618c2ecf20Sopenharmony_cistatic int __tipc_nl_add_sk_con(struct sk_buff *skb, struct tipc_sock *tsk)
34628c2ecf20Sopenharmony_ci{
34638c2ecf20Sopenharmony_ci	u32 peer_node;
34648c2ecf20Sopenharmony_ci	u32 peer_port;
34658c2ecf20Sopenharmony_ci	struct nlattr *nest;
34668c2ecf20Sopenharmony_ci
34678c2ecf20Sopenharmony_ci	peer_node = tsk_peer_node(tsk);
34688c2ecf20Sopenharmony_ci	peer_port = tsk_peer_port(tsk);
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_ci	nest = nla_nest_start_noflag(skb, TIPC_NLA_SOCK_CON);
34718c2ecf20Sopenharmony_ci	if (!nest)
34728c2ecf20Sopenharmony_ci		return -EMSGSIZE;
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_CON_NODE, peer_node))
34758c2ecf20Sopenharmony_ci		goto msg_full;
34768c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_CON_SOCK, peer_port))
34778c2ecf20Sopenharmony_ci		goto msg_full;
34788c2ecf20Sopenharmony_ci
34798c2ecf20Sopenharmony_ci	if (tsk->conn_type != 0) {
34808c2ecf20Sopenharmony_ci		if (nla_put_flag(skb, TIPC_NLA_CON_FLAG))
34818c2ecf20Sopenharmony_ci			goto msg_full;
34828c2ecf20Sopenharmony_ci		if (nla_put_u32(skb, TIPC_NLA_CON_TYPE, tsk->conn_type))
34838c2ecf20Sopenharmony_ci			goto msg_full;
34848c2ecf20Sopenharmony_ci		if (nla_put_u32(skb, TIPC_NLA_CON_INST, tsk->conn_instance))
34858c2ecf20Sopenharmony_ci			goto msg_full;
34868c2ecf20Sopenharmony_ci	}
34878c2ecf20Sopenharmony_ci	nla_nest_end(skb, nest);
34888c2ecf20Sopenharmony_ci
34898c2ecf20Sopenharmony_ci	return 0;
34908c2ecf20Sopenharmony_ci
34918c2ecf20Sopenharmony_cimsg_full:
34928c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, nest);
34938c2ecf20Sopenharmony_ci
34948c2ecf20Sopenharmony_ci	return -EMSGSIZE;
34958c2ecf20Sopenharmony_ci}
34968c2ecf20Sopenharmony_ci
34978c2ecf20Sopenharmony_cistatic int __tipc_nl_add_sk_info(struct sk_buff *skb, struct tipc_sock
34988c2ecf20Sopenharmony_ci			  *tsk)
34998c2ecf20Sopenharmony_ci{
35008c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
35018c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
35028c2ecf20Sopenharmony_ci
35038c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_SOCK_REF, tsk->portid) ||
35048c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TIPC_NLA_SOCK_ADDR, tipc_own_addr(net)))
35058c2ecf20Sopenharmony_ci		return -EMSGSIZE;
35068c2ecf20Sopenharmony_ci
35078c2ecf20Sopenharmony_ci	if (tipc_sk_connected(sk)) {
35088c2ecf20Sopenharmony_ci		if (__tipc_nl_add_sk_con(skb, tsk))
35098c2ecf20Sopenharmony_ci			return -EMSGSIZE;
35108c2ecf20Sopenharmony_ci	} else if (!list_empty(&tsk->publications)) {
35118c2ecf20Sopenharmony_ci		if (nla_put_flag(skb, TIPC_NLA_SOCK_HAS_PUBL))
35128c2ecf20Sopenharmony_ci			return -EMSGSIZE;
35138c2ecf20Sopenharmony_ci	}
35148c2ecf20Sopenharmony_ci	return 0;
35158c2ecf20Sopenharmony_ci}
35168c2ecf20Sopenharmony_ci
35178c2ecf20Sopenharmony_ci/* Caller should hold socket lock for the passed tipc socket. */
35188c2ecf20Sopenharmony_cistatic int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
35198c2ecf20Sopenharmony_ci			    struct tipc_sock *tsk)
35208c2ecf20Sopenharmony_ci{
35218c2ecf20Sopenharmony_ci	struct nlattr *attrs;
35228c2ecf20Sopenharmony_ci	void *hdr;
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
35258c2ecf20Sopenharmony_ci			  &tipc_genl_family, NLM_F_MULTI, TIPC_NL_SOCK_GET);
35268c2ecf20Sopenharmony_ci	if (!hdr)
35278c2ecf20Sopenharmony_ci		goto msg_cancel;
35288c2ecf20Sopenharmony_ci
35298c2ecf20Sopenharmony_ci	attrs = nla_nest_start_noflag(skb, TIPC_NLA_SOCK);
35308c2ecf20Sopenharmony_ci	if (!attrs)
35318c2ecf20Sopenharmony_ci		goto genlmsg_cancel;
35328c2ecf20Sopenharmony_ci
35338c2ecf20Sopenharmony_ci	if (__tipc_nl_add_sk_info(skb, tsk))
35348c2ecf20Sopenharmony_ci		goto attr_msg_cancel;
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci	nla_nest_end(skb, attrs);
35378c2ecf20Sopenharmony_ci	genlmsg_end(skb, hdr);
35388c2ecf20Sopenharmony_ci
35398c2ecf20Sopenharmony_ci	return 0;
35408c2ecf20Sopenharmony_ci
35418c2ecf20Sopenharmony_ciattr_msg_cancel:
35428c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, attrs);
35438c2ecf20Sopenharmony_cigenlmsg_cancel:
35448c2ecf20Sopenharmony_ci	genlmsg_cancel(skb, hdr);
35458c2ecf20Sopenharmony_cimsg_cancel:
35468c2ecf20Sopenharmony_ci	return -EMSGSIZE;
35478c2ecf20Sopenharmony_ci}
35488c2ecf20Sopenharmony_ci
35498c2ecf20Sopenharmony_ciint tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb,
35508c2ecf20Sopenharmony_ci		    int (*skb_handler)(struct sk_buff *skb,
35518c2ecf20Sopenharmony_ci				       struct netlink_callback *cb,
35528c2ecf20Sopenharmony_ci				       struct tipc_sock *tsk))
35538c2ecf20Sopenharmony_ci{
35548c2ecf20Sopenharmony_ci	struct rhashtable_iter *iter = (void *)cb->args[4];
35558c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
35568c2ecf20Sopenharmony_ci	int err;
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_ci	rhashtable_walk_start(iter);
35598c2ecf20Sopenharmony_ci	while ((tsk = rhashtable_walk_next(iter)) != NULL) {
35608c2ecf20Sopenharmony_ci		if (IS_ERR(tsk)) {
35618c2ecf20Sopenharmony_ci			err = PTR_ERR(tsk);
35628c2ecf20Sopenharmony_ci			if (err == -EAGAIN) {
35638c2ecf20Sopenharmony_ci				err = 0;
35648c2ecf20Sopenharmony_ci				continue;
35658c2ecf20Sopenharmony_ci			}
35668c2ecf20Sopenharmony_ci			break;
35678c2ecf20Sopenharmony_ci		}
35688c2ecf20Sopenharmony_ci
35698c2ecf20Sopenharmony_ci		sock_hold(&tsk->sk);
35708c2ecf20Sopenharmony_ci		rhashtable_walk_stop(iter);
35718c2ecf20Sopenharmony_ci		lock_sock(&tsk->sk);
35728c2ecf20Sopenharmony_ci		err = skb_handler(skb, cb, tsk);
35738c2ecf20Sopenharmony_ci		if (err) {
35748c2ecf20Sopenharmony_ci			release_sock(&tsk->sk);
35758c2ecf20Sopenharmony_ci			sock_put(&tsk->sk);
35768c2ecf20Sopenharmony_ci			goto out;
35778c2ecf20Sopenharmony_ci		}
35788c2ecf20Sopenharmony_ci		release_sock(&tsk->sk);
35798c2ecf20Sopenharmony_ci		rhashtable_walk_start(iter);
35808c2ecf20Sopenharmony_ci		sock_put(&tsk->sk);
35818c2ecf20Sopenharmony_ci	}
35828c2ecf20Sopenharmony_ci	rhashtable_walk_stop(iter);
35838c2ecf20Sopenharmony_ciout:
35848c2ecf20Sopenharmony_ci	return skb->len;
35858c2ecf20Sopenharmony_ci}
35868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tipc_nl_sk_walk);
35878c2ecf20Sopenharmony_ci
35888c2ecf20Sopenharmony_ciint tipc_dump_start(struct netlink_callback *cb)
35898c2ecf20Sopenharmony_ci{
35908c2ecf20Sopenharmony_ci	return __tipc_dump_start(cb, sock_net(cb->skb->sk));
35918c2ecf20Sopenharmony_ci}
35928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tipc_dump_start);
35938c2ecf20Sopenharmony_ci
35948c2ecf20Sopenharmony_ciint __tipc_dump_start(struct netlink_callback *cb, struct net *net)
35958c2ecf20Sopenharmony_ci{
35968c2ecf20Sopenharmony_ci	/* tipc_nl_name_table_dump() uses cb->args[0...3]. */
35978c2ecf20Sopenharmony_ci	struct rhashtable_iter *iter = (void *)cb->args[4];
35988c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(net);
35998c2ecf20Sopenharmony_ci
36008c2ecf20Sopenharmony_ci	if (!iter) {
36018c2ecf20Sopenharmony_ci		iter = kmalloc(sizeof(*iter), GFP_KERNEL);
36028c2ecf20Sopenharmony_ci		if (!iter)
36038c2ecf20Sopenharmony_ci			return -ENOMEM;
36048c2ecf20Sopenharmony_ci
36058c2ecf20Sopenharmony_ci		cb->args[4] = (long)iter;
36068c2ecf20Sopenharmony_ci	}
36078c2ecf20Sopenharmony_ci
36088c2ecf20Sopenharmony_ci	rhashtable_walk_enter(&tn->sk_rht, iter);
36098c2ecf20Sopenharmony_ci	return 0;
36108c2ecf20Sopenharmony_ci}
36118c2ecf20Sopenharmony_ci
36128c2ecf20Sopenharmony_ciint tipc_dump_done(struct netlink_callback *cb)
36138c2ecf20Sopenharmony_ci{
36148c2ecf20Sopenharmony_ci	struct rhashtable_iter *hti = (void *)cb->args[4];
36158c2ecf20Sopenharmony_ci
36168c2ecf20Sopenharmony_ci	rhashtable_walk_exit(hti);
36178c2ecf20Sopenharmony_ci	kfree(hti);
36188c2ecf20Sopenharmony_ci	return 0;
36198c2ecf20Sopenharmony_ci}
36208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tipc_dump_done);
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ciint tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb,
36238c2ecf20Sopenharmony_ci			   struct tipc_sock *tsk, u32 sk_filter_state,
36248c2ecf20Sopenharmony_ci			   u64 (*tipc_diag_gen_cookie)(struct sock *sk))
36258c2ecf20Sopenharmony_ci{
36268c2ecf20Sopenharmony_ci	struct sock *sk = &tsk->sk;
36278c2ecf20Sopenharmony_ci	struct nlattr *attrs;
36288c2ecf20Sopenharmony_ci	struct nlattr *stat;
36298c2ecf20Sopenharmony_ci
36308c2ecf20Sopenharmony_ci	/*filter response w.r.t sk_state*/
36318c2ecf20Sopenharmony_ci	if (!(sk_filter_state & (1 << sk->sk_state)))
36328c2ecf20Sopenharmony_ci		return 0;
36338c2ecf20Sopenharmony_ci
36348c2ecf20Sopenharmony_ci	attrs = nla_nest_start_noflag(skb, TIPC_NLA_SOCK);
36358c2ecf20Sopenharmony_ci	if (!attrs)
36368c2ecf20Sopenharmony_ci		goto msg_cancel;
36378c2ecf20Sopenharmony_ci
36388c2ecf20Sopenharmony_ci	if (__tipc_nl_add_sk_info(skb, tsk))
36398c2ecf20Sopenharmony_ci		goto attr_msg_cancel;
36408c2ecf20Sopenharmony_ci
36418c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_SOCK_TYPE, (u32)sk->sk_type) ||
36428c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TIPC_NLA_SOCK_TIPC_STATE, (u32)sk->sk_state) ||
36438c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TIPC_NLA_SOCK_INO, sock_i_ino(sk)) ||
36448c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TIPC_NLA_SOCK_UID,
36458c2ecf20Sopenharmony_ci			from_kuid_munged(sk_user_ns(NETLINK_CB(cb->skb).sk),
36468c2ecf20Sopenharmony_ci					 sock_i_uid(sk))) ||
36478c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(skb, TIPC_NLA_SOCK_COOKIE,
36488c2ecf20Sopenharmony_ci			      tipc_diag_gen_cookie(sk),
36498c2ecf20Sopenharmony_ci			      TIPC_NLA_SOCK_PAD))
36508c2ecf20Sopenharmony_ci		goto attr_msg_cancel;
36518c2ecf20Sopenharmony_ci
36528c2ecf20Sopenharmony_ci	stat = nla_nest_start_noflag(skb, TIPC_NLA_SOCK_STAT);
36538c2ecf20Sopenharmony_ci	if (!stat)
36548c2ecf20Sopenharmony_ci		goto attr_msg_cancel;
36558c2ecf20Sopenharmony_ci
36568c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_SOCK_STAT_RCVQ,
36578c2ecf20Sopenharmony_ci			skb_queue_len(&sk->sk_receive_queue)) ||
36588c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TIPC_NLA_SOCK_STAT_SENDQ,
36598c2ecf20Sopenharmony_ci			skb_queue_len(&sk->sk_write_queue)) ||
36608c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TIPC_NLA_SOCK_STAT_DROP,
36618c2ecf20Sopenharmony_ci			atomic_read(&sk->sk_drops)))
36628c2ecf20Sopenharmony_ci		goto stat_msg_cancel;
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci	if (tsk->cong_link_cnt &&
36658c2ecf20Sopenharmony_ci	    nla_put_flag(skb, TIPC_NLA_SOCK_STAT_LINK_CONG))
36668c2ecf20Sopenharmony_ci		goto stat_msg_cancel;
36678c2ecf20Sopenharmony_ci
36688c2ecf20Sopenharmony_ci	if (tsk_conn_cong(tsk) &&
36698c2ecf20Sopenharmony_ci	    nla_put_flag(skb, TIPC_NLA_SOCK_STAT_CONN_CONG))
36708c2ecf20Sopenharmony_ci		goto stat_msg_cancel;
36718c2ecf20Sopenharmony_ci
36728c2ecf20Sopenharmony_ci	nla_nest_end(skb, stat);
36738c2ecf20Sopenharmony_ci
36748c2ecf20Sopenharmony_ci	if (tsk->group)
36758c2ecf20Sopenharmony_ci		if (tipc_group_fill_sock_diag(tsk->group, skb))
36768c2ecf20Sopenharmony_ci			goto stat_msg_cancel;
36778c2ecf20Sopenharmony_ci
36788c2ecf20Sopenharmony_ci	nla_nest_end(skb, attrs);
36798c2ecf20Sopenharmony_ci
36808c2ecf20Sopenharmony_ci	return 0;
36818c2ecf20Sopenharmony_ci
36828c2ecf20Sopenharmony_cistat_msg_cancel:
36838c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, stat);
36848c2ecf20Sopenharmony_ciattr_msg_cancel:
36858c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, attrs);
36868c2ecf20Sopenharmony_cimsg_cancel:
36878c2ecf20Sopenharmony_ci	return -EMSGSIZE;
36888c2ecf20Sopenharmony_ci}
36898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tipc_sk_fill_sock_diag);
36908c2ecf20Sopenharmony_ci
36918c2ecf20Sopenharmony_ciint tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
36928c2ecf20Sopenharmony_ci{
36938c2ecf20Sopenharmony_ci	return tipc_nl_sk_walk(skb, cb, __tipc_nl_add_sk);
36948c2ecf20Sopenharmony_ci}
36958c2ecf20Sopenharmony_ci
36968c2ecf20Sopenharmony_ci/* Caller should hold socket lock for the passed tipc socket. */
36978c2ecf20Sopenharmony_cistatic int __tipc_nl_add_sk_publ(struct sk_buff *skb,
36988c2ecf20Sopenharmony_ci				 struct netlink_callback *cb,
36998c2ecf20Sopenharmony_ci				 struct publication *publ)
37008c2ecf20Sopenharmony_ci{
37018c2ecf20Sopenharmony_ci	void *hdr;
37028c2ecf20Sopenharmony_ci	struct nlattr *attrs;
37038c2ecf20Sopenharmony_ci
37048c2ecf20Sopenharmony_ci	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
37058c2ecf20Sopenharmony_ci			  &tipc_genl_family, NLM_F_MULTI, TIPC_NL_PUBL_GET);
37068c2ecf20Sopenharmony_ci	if (!hdr)
37078c2ecf20Sopenharmony_ci		goto msg_cancel;
37088c2ecf20Sopenharmony_ci
37098c2ecf20Sopenharmony_ci	attrs = nla_nest_start_noflag(skb, TIPC_NLA_PUBL);
37108c2ecf20Sopenharmony_ci	if (!attrs)
37118c2ecf20Sopenharmony_ci		goto genlmsg_cancel;
37128c2ecf20Sopenharmony_ci
37138c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_PUBL_KEY, publ->key))
37148c2ecf20Sopenharmony_ci		goto attr_msg_cancel;
37158c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_PUBL_TYPE, publ->type))
37168c2ecf20Sopenharmony_ci		goto attr_msg_cancel;
37178c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_PUBL_LOWER, publ->lower))
37188c2ecf20Sopenharmony_ci		goto attr_msg_cancel;
37198c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_PUBL_UPPER, publ->upper))
37208c2ecf20Sopenharmony_ci		goto attr_msg_cancel;
37218c2ecf20Sopenharmony_ci
37228c2ecf20Sopenharmony_ci	nla_nest_end(skb, attrs);
37238c2ecf20Sopenharmony_ci	genlmsg_end(skb, hdr);
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci	return 0;
37268c2ecf20Sopenharmony_ci
37278c2ecf20Sopenharmony_ciattr_msg_cancel:
37288c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, attrs);
37298c2ecf20Sopenharmony_cigenlmsg_cancel:
37308c2ecf20Sopenharmony_ci	genlmsg_cancel(skb, hdr);
37318c2ecf20Sopenharmony_cimsg_cancel:
37328c2ecf20Sopenharmony_ci	return -EMSGSIZE;
37338c2ecf20Sopenharmony_ci}
37348c2ecf20Sopenharmony_ci
37358c2ecf20Sopenharmony_ci/* Caller should hold socket lock for the passed tipc socket. */
37368c2ecf20Sopenharmony_cistatic int __tipc_nl_list_sk_publ(struct sk_buff *skb,
37378c2ecf20Sopenharmony_ci				  struct netlink_callback *cb,
37388c2ecf20Sopenharmony_ci				  struct tipc_sock *tsk, u32 *last_publ)
37398c2ecf20Sopenharmony_ci{
37408c2ecf20Sopenharmony_ci	int err;
37418c2ecf20Sopenharmony_ci	struct publication *p;
37428c2ecf20Sopenharmony_ci
37438c2ecf20Sopenharmony_ci	if (*last_publ) {
37448c2ecf20Sopenharmony_ci		list_for_each_entry(p, &tsk->publications, binding_sock) {
37458c2ecf20Sopenharmony_ci			if (p->key == *last_publ)
37468c2ecf20Sopenharmony_ci				break;
37478c2ecf20Sopenharmony_ci		}
37488c2ecf20Sopenharmony_ci		if (list_entry_is_head(p, &tsk->publications, binding_sock)) {
37498c2ecf20Sopenharmony_ci			/* We never set seq or call nl_dump_check_consistent()
37508c2ecf20Sopenharmony_ci			 * this means that setting prev_seq here will cause the
37518c2ecf20Sopenharmony_ci			 * consistence check to fail in the netlink callback
37528c2ecf20Sopenharmony_ci			 * handler. Resulting in the last NLMSG_DONE message
37538c2ecf20Sopenharmony_ci			 * having the NLM_F_DUMP_INTR flag set.
37548c2ecf20Sopenharmony_ci			 */
37558c2ecf20Sopenharmony_ci			cb->prev_seq = 1;
37568c2ecf20Sopenharmony_ci			*last_publ = 0;
37578c2ecf20Sopenharmony_ci			return -EPIPE;
37588c2ecf20Sopenharmony_ci		}
37598c2ecf20Sopenharmony_ci	} else {
37608c2ecf20Sopenharmony_ci		p = list_first_entry(&tsk->publications, struct publication,
37618c2ecf20Sopenharmony_ci				     binding_sock);
37628c2ecf20Sopenharmony_ci	}
37638c2ecf20Sopenharmony_ci
37648c2ecf20Sopenharmony_ci	list_for_each_entry_from(p, &tsk->publications, binding_sock) {
37658c2ecf20Sopenharmony_ci		err = __tipc_nl_add_sk_publ(skb, cb, p);
37668c2ecf20Sopenharmony_ci		if (err) {
37678c2ecf20Sopenharmony_ci			*last_publ = p->key;
37688c2ecf20Sopenharmony_ci			return err;
37698c2ecf20Sopenharmony_ci		}
37708c2ecf20Sopenharmony_ci	}
37718c2ecf20Sopenharmony_ci	*last_publ = 0;
37728c2ecf20Sopenharmony_ci
37738c2ecf20Sopenharmony_ci	return 0;
37748c2ecf20Sopenharmony_ci}
37758c2ecf20Sopenharmony_ci
37768c2ecf20Sopenharmony_ciint tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb)
37778c2ecf20Sopenharmony_ci{
37788c2ecf20Sopenharmony_ci	int err;
37798c2ecf20Sopenharmony_ci	u32 tsk_portid = cb->args[0];
37808c2ecf20Sopenharmony_ci	u32 last_publ = cb->args[1];
37818c2ecf20Sopenharmony_ci	u32 done = cb->args[2];
37828c2ecf20Sopenharmony_ci	struct net *net = sock_net(skb->sk);
37838c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
37848c2ecf20Sopenharmony_ci
37858c2ecf20Sopenharmony_ci	if (!tsk_portid) {
37868c2ecf20Sopenharmony_ci		struct nlattr **attrs = genl_dumpit_info(cb)->attrs;
37878c2ecf20Sopenharmony_ci		struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1];
37888c2ecf20Sopenharmony_ci
37898c2ecf20Sopenharmony_ci		if (!attrs[TIPC_NLA_SOCK])
37908c2ecf20Sopenharmony_ci			return -EINVAL;
37918c2ecf20Sopenharmony_ci
37928c2ecf20Sopenharmony_ci		err = nla_parse_nested_deprecated(sock, TIPC_NLA_SOCK_MAX,
37938c2ecf20Sopenharmony_ci						  attrs[TIPC_NLA_SOCK],
37948c2ecf20Sopenharmony_ci						  tipc_nl_sock_policy, NULL);
37958c2ecf20Sopenharmony_ci		if (err)
37968c2ecf20Sopenharmony_ci			return err;
37978c2ecf20Sopenharmony_ci
37988c2ecf20Sopenharmony_ci		if (!sock[TIPC_NLA_SOCK_REF])
37998c2ecf20Sopenharmony_ci			return -EINVAL;
38008c2ecf20Sopenharmony_ci
38018c2ecf20Sopenharmony_ci		tsk_portid = nla_get_u32(sock[TIPC_NLA_SOCK_REF]);
38028c2ecf20Sopenharmony_ci	}
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_ci	if (done)
38058c2ecf20Sopenharmony_ci		return 0;
38068c2ecf20Sopenharmony_ci
38078c2ecf20Sopenharmony_ci	tsk = tipc_sk_lookup(net, tsk_portid);
38088c2ecf20Sopenharmony_ci	if (!tsk)
38098c2ecf20Sopenharmony_ci		return -EINVAL;
38108c2ecf20Sopenharmony_ci
38118c2ecf20Sopenharmony_ci	lock_sock(&tsk->sk);
38128c2ecf20Sopenharmony_ci	err = __tipc_nl_list_sk_publ(skb, cb, tsk, &last_publ);
38138c2ecf20Sopenharmony_ci	if (!err)
38148c2ecf20Sopenharmony_ci		done = 1;
38158c2ecf20Sopenharmony_ci	release_sock(&tsk->sk);
38168c2ecf20Sopenharmony_ci	sock_put(&tsk->sk);
38178c2ecf20Sopenharmony_ci
38188c2ecf20Sopenharmony_ci	cb->args[0] = tsk_portid;
38198c2ecf20Sopenharmony_ci	cb->args[1] = last_publ;
38208c2ecf20Sopenharmony_ci	cb->args[2] = done;
38218c2ecf20Sopenharmony_ci
38228c2ecf20Sopenharmony_ci	return skb->len;
38238c2ecf20Sopenharmony_ci}
38248c2ecf20Sopenharmony_ci
38258c2ecf20Sopenharmony_ci/**
38268c2ecf20Sopenharmony_ci * tipc_sk_filtering - check if a socket should be traced
38278c2ecf20Sopenharmony_ci * @sk: the socket to be examined
38288c2ecf20Sopenharmony_ci * @sysctl_tipc_sk_filter[]: the socket tuple for filtering,
38298c2ecf20Sopenharmony_ci *  (portid, sock type, name type, name lower, name upper)
38308c2ecf20Sopenharmony_ci *
38318c2ecf20Sopenharmony_ci * Returns true if the socket meets the socket tuple data
38328c2ecf20Sopenharmony_ci * (value 0 = 'any') or when there is no tuple set (all = 0),
38338c2ecf20Sopenharmony_ci * otherwise false
38348c2ecf20Sopenharmony_ci */
38358c2ecf20Sopenharmony_cibool tipc_sk_filtering(struct sock *sk)
38368c2ecf20Sopenharmony_ci{
38378c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
38388c2ecf20Sopenharmony_ci	struct publication *p;
38398c2ecf20Sopenharmony_ci	u32 _port, _sktype, _type, _lower, _upper;
38408c2ecf20Sopenharmony_ci	u32 type = 0, lower = 0, upper = 0;
38418c2ecf20Sopenharmony_ci
38428c2ecf20Sopenharmony_ci	if (!sk)
38438c2ecf20Sopenharmony_ci		return true;
38448c2ecf20Sopenharmony_ci
38458c2ecf20Sopenharmony_ci	tsk = tipc_sk(sk);
38468c2ecf20Sopenharmony_ci
38478c2ecf20Sopenharmony_ci	_port = sysctl_tipc_sk_filter[0];
38488c2ecf20Sopenharmony_ci	_sktype = sysctl_tipc_sk_filter[1];
38498c2ecf20Sopenharmony_ci	_type = sysctl_tipc_sk_filter[2];
38508c2ecf20Sopenharmony_ci	_lower = sysctl_tipc_sk_filter[3];
38518c2ecf20Sopenharmony_ci	_upper = sysctl_tipc_sk_filter[4];
38528c2ecf20Sopenharmony_ci
38538c2ecf20Sopenharmony_ci	if (!_port && !_sktype && !_type && !_lower && !_upper)
38548c2ecf20Sopenharmony_ci		return true;
38558c2ecf20Sopenharmony_ci
38568c2ecf20Sopenharmony_ci	if (_port)
38578c2ecf20Sopenharmony_ci		return (_port == tsk->portid);
38588c2ecf20Sopenharmony_ci
38598c2ecf20Sopenharmony_ci	if (_sktype && _sktype != sk->sk_type)
38608c2ecf20Sopenharmony_ci		return false;
38618c2ecf20Sopenharmony_ci
38628c2ecf20Sopenharmony_ci	if (tsk->published) {
38638c2ecf20Sopenharmony_ci		p = list_first_entry_or_null(&tsk->publications,
38648c2ecf20Sopenharmony_ci					     struct publication, binding_sock);
38658c2ecf20Sopenharmony_ci		if (p) {
38668c2ecf20Sopenharmony_ci			type = p->type;
38678c2ecf20Sopenharmony_ci			lower = p->lower;
38688c2ecf20Sopenharmony_ci			upper = p->upper;
38698c2ecf20Sopenharmony_ci		}
38708c2ecf20Sopenharmony_ci	}
38718c2ecf20Sopenharmony_ci
38728c2ecf20Sopenharmony_ci	if (!tipc_sk_type_connectionless(sk)) {
38738c2ecf20Sopenharmony_ci		type = tsk->conn_type;
38748c2ecf20Sopenharmony_ci		lower = tsk->conn_instance;
38758c2ecf20Sopenharmony_ci		upper = tsk->conn_instance;
38768c2ecf20Sopenharmony_ci	}
38778c2ecf20Sopenharmony_ci
38788c2ecf20Sopenharmony_ci	if ((_type && _type != type) || (_lower && _lower != lower) ||
38798c2ecf20Sopenharmony_ci	    (_upper && _upper != upper))
38808c2ecf20Sopenharmony_ci		return false;
38818c2ecf20Sopenharmony_ci
38828c2ecf20Sopenharmony_ci	return true;
38838c2ecf20Sopenharmony_ci}
38848c2ecf20Sopenharmony_ci
38858c2ecf20Sopenharmony_ciu32 tipc_sock_get_portid(struct sock *sk)
38868c2ecf20Sopenharmony_ci{
38878c2ecf20Sopenharmony_ci	return (sk) ? (tipc_sk(sk))->portid : 0;
38888c2ecf20Sopenharmony_ci}
38898c2ecf20Sopenharmony_ci
38908c2ecf20Sopenharmony_ci/**
38918c2ecf20Sopenharmony_ci * tipc_sk_overlimit1 - check if socket rx queue is about to be overloaded,
38928c2ecf20Sopenharmony_ci *			both the rcv and backlog queues are considered
38938c2ecf20Sopenharmony_ci * @sk: tipc sk to be checked
38948c2ecf20Sopenharmony_ci * @skb: tipc msg to be checked
38958c2ecf20Sopenharmony_ci *
38968c2ecf20Sopenharmony_ci * Returns true if the socket rx queue allocation is > 90%, otherwise false
38978c2ecf20Sopenharmony_ci */
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_cibool tipc_sk_overlimit1(struct sock *sk, struct sk_buff *skb)
39008c2ecf20Sopenharmony_ci{
39018c2ecf20Sopenharmony_ci	atomic_t *dcnt = &tipc_sk(sk)->dupl_rcvcnt;
39028c2ecf20Sopenharmony_ci	unsigned int lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt);
39038c2ecf20Sopenharmony_ci	unsigned int qsize = sk->sk_backlog.len + sk_rmem_alloc_get(sk);
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_ci	return (qsize > lim * 90 / 100);
39068c2ecf20Sopenharmony_ci}
39078c2ecf20Sopenharmony_ci
39088c2ecf20Sopenharmony_ci/**
39098c2ecf20Sopenharmony_ci * tipc_sk_overlimit2 - check if socket rx queue is about to be overloaded,
39108c2ecf20Sopenharmony_ci *			only the rcv queue is considered
39118c2ecf20Sopenharmony_ci * @sk: tipc sk to be checked
39128c2ecf20Sopenharmony_ci * @skb: tipc msg to be checked
39138c2ecf20Sopenharmony_ci *
39148c2ecf20Sopenharmony_ci * Returns true if the socket rx queue allocation is > 90%, otherwise false
39158c2ecf20Sopenharmony_ci */
39168c2ecf20Sopenharmony_ci
39178c2ecf20Sopenharmony_cibool tipc_sk_overlimit2(struct sock *sk, struct sk_buff *skb)
39188c2ecf20Sopenharmony_ci{
39198c2ecf20Sopenharmony_ci	unsigned int lim = rcvbuf_limit(sk, skb);
39208c2ecf20Sopenharmony_ci	unsigned int qsize = sk_rmem_alloc_get(sk);
39218c2ecf20Sopenharmony_ci
39228c2ecf20Sopenharmony_ci	return (qsize > lim * 90 / 100);
39238c2ecf20Sopenharmony_ci}
39248c2ecf20Sopenharmony_ci
39258c2ecf20Sopenharmony_ci/**
39268c2ecf20Sopenharmony_ci * tipc_sk_dump - dump TIPC socket
39278c2ecf20Sopenharmony_ci * @sk: tipc sk to be dumped
39288c2ecf20Sopenharmony_ci * @dqueues: bitmask to decide if any socket queue to be dumped?
39298c2ecf20Sopenharmony_ci *           - TIPC_DUMP_NONE: don't dump socket queues
39308c2ecf20Sopenharmony_ci *           - TIPC_DUMP_SK_SNDQ: dump socket send queue
39318c2ecf20Sopenharmony_ci *           - TIPC_DUMP_SK_RCVQ: dump socket rcv queue
39328c2ecf20Sopenharmony_ci *           - TIPC_DUMP_SK_BKLGQ: dump socket backlog queue
39338c2ecf20Sopenharmony_ci *           - TIPC_DUMP_ALL: dump all the socket queues above
39348c2ecf20Sopenharmony_ci * @buf: returned buffer of dump data in format
39358c2ecf20Sopenharmony_ci */
39368c2ecf20Sopenharmony_ciint tipc_sk_dump(struct sock *sk, u16 dqueues, char *buf)
39378c2ecf20Sopenharmony_ci{
39388c2ecf20Sopenharmony_ci	int i = 0;
39398c2ecf20Sopenharmony_ci	size_t sz = (dqueues) ? SK_LMAX : SK_LMIN;
39408c2ecf20Sopenharmony_ci	struct tipc_sock *tsk;
39418c2ecf20Sopenharmony_ci	struct publication *p;
39428c2ecf20Sopenharmony_ci	bool tsk_connected;
39438c2ecf20Sopenharmony_ci
39448c2ecf20Sopenharmony_ci	if (!sk) {
39458c2ecf20Sopenharmony_ci		i += scnprintf(buf, sz, "sk data: (null)\n");
39468c2ecf20Sopenharmony_ci		return i;
39478c2ecf20Sopenharmony_ci	}
39488c2ecf20Sopenharmony_ci
39498c2ecf20Sopenharmony_ci	tsk = tipc_sk(sk);
39508c2ecf20Sopenharmony_ci	tsk_connected = !tipc_sk_type_connectionless(sk);
39518c2ecf20Sopenharmony_ci
39528c2ecf20Sopenharmony_ci	i += scnprintf(buf, sz, "sk data: %u", sk->sk_type);
39538c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %d", sk->sk_state);
39548c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %x", tsk_own_node(tsk));
39558c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %u", tsk->portid);
39568c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " | %u", tsk_connected);
39578c2ecf20Sopenharmony_ci	if (tsk_connected) {
39588c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, " %x", tsk_peer_node(tsk));
39598c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, " %u", tsk_peer_port(tsk));
39608c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, " %u", tsk->conn_type);
39618c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, " %u", tsk->conn_instance);
39628c2ecf20Sopenharmony_ci	}
39638c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " | %u", tsk->published);
39648c2ecf20Sopenharmony_ci	if (tsk->published) {
39658c2ecf20Sopenharmony_ci		p = list_first_entry_or_null(&tsk->publications,
39668c2ecf20Sopenharmony_ci					     struct publication, binding_sock);
39678c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, " %u", (p) ? p->type : 0);
39688c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, " %u", (p) ? p->lower : 0);
39698c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, " %u", (p) ? p->upper : 0);
39708c2ecf20Sopenharmony_ci	}
39718c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " | %u", tsk->snd_win);
39728c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %u", tsk->rcv_win);
39738c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %u", tsk->max_pkt);
39748c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %x", tsk->peer_caps);
39758c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %u", tsk->cong_link_cnt);
39768c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %u", tsk->snt_unacked);
39778c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %u", tsk->rcv_unacked);
39788c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %u", atomic_read(&tsk->dupl_rcvcnt));
39798c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %u", sk->sk_shutdown);
39808c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " | %d", sk_wmem_alloc_get(sk));
39818c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %d", sk->sk_sndbuf);
39828c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " | %d", sk_rmem_alloc_get(sk));
39838c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " %d", sk->sk_rcvbuf);
39848c2ecf20Sopenharmony_ci	i += scnprintf(buf + i, sz - i, " | %d\n", READ_ONCE(sk->sk_backlog.len));
39858c2ecf20Sopenharmony_ci
39868c2ecf20Sopenharmony_ci	if (dqueues & TIPC_DUMP_SK_SNDQ) {
39878c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, "sk_write_queue: ");
39888c2ecf20Sopenharmony_ci		i += tipc_list_dump(&sk->sk_write_queue, false, buf + i);
39898c2ecf20Sopenharmony_ci	}
39908c2ecf20Sopenharmony_ci
39918c2ecf20Sopenharmony_ci	if (dqueues & TIPC_DUMP_SK_RCVQ) {
39928c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, "sk_receive_queue: ");
39938c2ecf20Sopenharmony_ci		i += tipc_list_dump(&sk->sk_receive_queue, false, buf + i);
39948c2ecf20Sopenharmony_ci	}
39958c2ecf20Sopenharmony_ci
39968c2ecf20Sopenharmony_ci	if (dqueues & TIPC_DUMP_SK_BKLGQ) {
39978c2ecf20Sopenharmony_ci		i += scnprintf(buf + i, sz - i, "sk_backlog:\n  head ");
39988c2ecf20Sopenharmony_ci		i += tipc_skb_dump(sk->sk_backlog.head, false, buf + i);
39998c2ecf20Sopenharmony_ci		if (sk->sk_backlog.tail != sk->sk_backlog.head) {
40008c2ecf20Sopenharmony_ci			i += scnprintf(buf + i, sz - i, "  tail ");
40018c2ecf20Sopenharmony_ci			i += tipc_skb_dump(sk->sk_backlog.tail, false,
40028c2ecf20Sopenharmony_ci					   buf + i);
40038c2ecf20Sopenharmony_ci		}
40048c2ecf20Sopenharmony_ci	}
40058c2ecf20Sopenharmony_ci
40068c2ecf20Sopenharmony_ci	return i;
40078c2ecf20Sopenharmony_ci}
4008