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