1b97bf3fdSPer Liden /* 2b97bf3fdSPer Liden * net/tipc/socket.c: TIPC socket API 3b97bf3fdSPer Liden * 43c724acdSJon Paul Maloy * Copyright (c) 2001-2007, 2012-2015, Ericsson AB 5c5fa7b3cSYing Xue * Copyright (c) 2004-2008, 2010-2013, Wind River Systems 6b97bf3fdSPer Liden * All rights reserved. 7b97bf3fdSPer Liden * 8b97bf3fdSPer Liden * Redistribution and use in source and binary forms, with or without 9b97bf3fdSPer Liden * modification, are permitted provided that the following conditions are met: 10b97bf3fdSPer Liden * 119ea1fd3cSPer Liden * 1. Redistributions of source code must retain the above copyright 129ea1fd3cSPer Liden * notice, this list of conditions and the following disclaimer. 139ea1fd3cSPer Liden * 2. Redistributions in binary form must reproduce the above copyright 149ea1fd3cSPer Liden * notice, this list of conditions and the following disclaimer in the 159ea1fd3cSPer Liden * documentation and/or other materials provided with the distribution. 169ea1fd3cSPer Liden * 3. Neither the names of the copyright holders nor the names of its 179ea1fd3cSPer Liden * contributors may be used to endorse or promote products derived from 189ea1fd3cSPer Liden * this software without specific prior written permission. 199ea1fd3cSPer Liden * 209ea1fd3cSPer Liden * Alternatively, this software may be distributed under the terms of the 219ea1fd3cSPer Liden * GNU General Public License ("GPL") version 2 as published by the Free 229ea1fd3cSPer Liden * Software Foundation. 23b97bf3fdSPer Liden * 24b97bf3fdSPer Liden * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25b97bf3fdSPer Liden * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26b97bf3fdSPer Liden * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27b97bf3fdSPer Liden * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 28b97bf3fdSPer Liden * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29b97bf3fdSPer Liden * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30b97bf3fdSPer Liden * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31b97bf3fdSPer Liden * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32b97bf3fdSPer Liden * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33b97bf3fdSPer Liden * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34b97bf3fdSPer Liden * POSSIBILITY OF SUCH DAMAGE. 35b97bf3fdSPer Liden */ 36b97bf3fdSPer Liden 3707f6c4bcSYing Xue #include <linux/rhashtable.h> 38b97bf3fdSPer Liden #include "core.h" 39e2dafe87SJon Paul Maloy #include "name_table.h" 4078acb1f9SErik Hugne #include "node.h" 41e2dafe87SJon Paul Maloy #include "link.h" 42c637c103SJon Paul Maloy #include "name_distr.h" 432e84c60bSJon Paul Maloy #include "socket.h" 44a6bf70f7SJon Paul Maloy #include "bcast.h" 4549cc66eaSRichard Alpe #include "netlink.h" 462cf8aa19SErik Hugne 47b97bf3fdSPer Liden #define SS_LISTENING -1 /* socket is listening */ 48b97bf3fdSPer Liden #define SS_READY -2 /* socket is connectionless */ 49b97bf3fdSPer Liden 503654ea02SAllan Stephens #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ 512f55c437SYing Xue #define CONN_PROBING_INTERVAL msecs_to_jiffies(3600000) /* [ms] => 1 h */ 52ac0074eeSJon Paul Maloy #define TIPC_FWD_MSG 1 53301bae56SJon Paul Maloy #define TIPC_CONN_OK 0 54301bae56SJon Paul Maloy #define TIPC_CONN_PROBING 1 5507f6c4bcSYing Xue #define TIPC_MAX_PORT 0xffffffff 5607f6c4bcSYing Xue #define TIPC_MIN_PORT 1 57301bae56SJon Paul Maloy 58301bae56SJon Paul Maloy /** 59301bae56SJon Paul Maloy * struct tipc_sock - TIPC socket structure 60301bae56SJon Paul Maloy * @sk: socket - interacts with 'port' and with user via the socket API 61301bae56SJon Paul Maloy * @connected: non-zero if port is currently connected to a peer port 62301bae56SJon Paul Maloy * @conn_type: TIPC type used when connection was established 63301bae56SJon Paul Maloy * @conn_instance: TIPC instance used when connection was established 64301bae56SJon Paul Maloy * @published: non-zero if port has one or more associated names 65301bae56SJon Paul Maloy * @max_pkt: maximum packet size "hint" used when building messages sent by port 6607f6c4bcSYing Xue * @portid: unique port identity in TIPC socket hash table 67301bae56SJon Paul Maloy * @phdr: preformatted message header used when sending messages 68301bae56SJon Paul Maloy * @port_list: adjacent ports in TIPC's global list of ports 69301bae56SJon Paul Maloy * @publications: list of publications for port 70301bae56SJon Paul Maloy * @pub_count: total # of publications port has made during its lifetime 71301bae56SJon Paul Maloy * @probing_state: 722f55c437SYing Xue * @probing_intv: 73301bae56SJon Paul Maloy * @conn_timeout: the time we can wait for an unresponded setup request 74301bae56SJon Paul Maloy * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue 75301bae56SJon Paul Maloy * @link_cong: non-zero if owner must sleep because of link congestion 76301bae56SJon Paul Maloy * @sent_unacked: # messages sent by socket, and not yet acked by peer 77301bae56SJon Paul Maloy * @rcv_unacked: # messages read by user, but not yet acked back to peer 78f2f8036eSErik Hugne * @remote: 'connected' peer for dgram/rdm 7907f6c4bcSYing Xue * @node: hash table node 8007f6c4bcSYing Xue * @rcu: rcu struct for tipc_sock 81301bae56SJon Paul Maloy */ 82301bae56SJon Paul Maloy struct tipc_sock { 83301bae56SJon Paul Maloy struct sock sk; 84301bae56SJon Paul Maloy int connected; 85301bae56SJon Paul Maloy u32 conn_type; 86301bae56SJon Paul Maloy u32 conn_instance; 87301bae56SJon Paul Maloy int published; 88301bae56SJon Paul Maloy u32 max_pkt; 8907f6c4bcSYing Xue u32 portid; 90301bae56SJon Paul Maloy struct tipc_msg phdr; 91301bae56SJon Paul Maloy struct list_head sock_list; 92301bae56SJon Paul Maloy struct list_head publications; 93301bae56SJon Paul Maloy u32 pub_count; 94301bae56SJon Paul Maloy u32 probing_state; 952f55c437SYing Xue unsigned long probing_intv; 96301bae56SJon Paul Maloy uint conn_timeout; 97301bae56SJon Paul Maloy atomic_t dupl_rcvcnt; 98301bae56SJon Paul Maloy bool link_cong; 99301bae56SJon Paul Maloy uint sent_unacked; 100301bae56SJon Paul Maloy uint rcv_unacked; 101f2f8036eSErik Hugne struct sockaddr_tipc remote; 10207f6c4bcSYing Xue struct rhash_head node; 10307f6c4bcSYing Xue struct rcu_head rcu; 104301bae56SJon Paul Maloy }; 105b97bf3fdSPer Liden 1064f4482dcSJon Paul Maloy static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); 107676d2369SDavid S. Miller static void tipc_data_ready(struct sock *sk); 108f288bef4SYing Xue static void tipc_write_space(struct sock *sk); 109f4195d1eSYing Xue static void tipc_sock_destruct(struct sock *sk); 110247f0f3cSYing Xue static int tipc_release(struct socket *sock); 111247f0f3cSYing Xue static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags); 1120abd8ff2SJon Paul Maloy static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p); 113f2f2a96aSYing Xue static void tipc_sk_timeout(unsigned long data); 114301bae56SJon Paul Maloy static int tipc_sk_publish(struct tipc_sock *tsk, uint scope, 1150fc87aaeSJon Paul Maloy struct tipc_name_seq const *seq); 116301bae56SJon Paul Maloy static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope, 1170fc87aaeSJon Paul Maloy struct tipc_name_seq const *seq); 118e05b31f4SYing Xue static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid); 11907f6c4bcSYing Xue static int tipc_sk_insert(struct tipc_sock *tsk); 12007f6c4bcSYing Xue static void tipc_sk_remove(struct tipc_sock *tsk); 12139a0295fSYing Xue static int __tipc_send_stream(struct socket *sock, struct msghdr *m, 12239a0295fSYing Xue size_t dsz); 12339a0295fSYing Xue static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz); 124b97bf3fdSPer Liden 125bca65eaeSFlorian Westphal static const struct proto_ops packet_ops; 126bca65eaeSFlorian Westphal static const struct proto_ops stream_ops; 127bca65eaeSFlorian Westphal static const struct proto_ops msg_ops; 128b97bf3fdSPer Liden static struct proto tipc_proto; 129b97bf3fdSPer Liden 1306cca7289SHerbert Xu static const struct rhashtable_params tsk_rht_params; 1316cca7289SHerbert Xu 132b97bf3fdSPer Liden /* 1330c3141e9SAllan Stephens * Revised TIPC socket locking policy: 1340c3141e9SAllan Stephens * 1350c3141e9SAllan Stephens * Most socket operations take the standard socket lock when they start 1360c3141e9SAllan Stephens * and hold it until they finish (or until they need to sleep). Acquiring 1370c3141e9SAllan Stephens * this lock grants the owner exclusive access to the fields of the socket 1380c3141e9SAllan Stephens * data structures, with the exception of the backlog queue. A few socket 1390c3141e9SAllan Stephens * operations can be done without taking the socket lock because they only 1400c3141e9SAllan Stephens * read socket information that never changes during the life of the socket. 1410c3141e9SAllan Stephens * 1420c3141e9SAllan Stephens * Socket operations may acquire the lock for the associated TIPC port if they 1430c3141e9SAllan Stephens * need to perform an operation on the port. If any routine needs to acquire 1440c3141e9SAllan Stephens * both the socket lock and the port lock it must take the socket lock first 1450c3141e9SAllan Stephens * to avoid the risk of deadlock. 1460c3141e9SAllan Stephens * 1470c3141e9SAllan Stephens * The dispatcher handling incoming messages cannot grab the socket lock in 1480c3141e9SAllan Stephens * the standard fashion, since invoked it runs at the BH level and cannot block. 1490c3141e9SAllan Stephens * Instead, it checks to see if the socket lock is currently owned by someone, 1500c3141e9SAllan Stephens * and either handles the message itself or adds it to the socket's backlog 1510c3141e9SAllan Stephens * queue; in the latter case the queued message is processed once the process 1520c3141e9SAllan Stephens * owning the socket lock releases it. 1530c3141e9SAllan Stephens * 1540c3141e9SAllan Stephens * NOTE: Releasing the socket lock while an operation is sleeping overcomes 1550c3141e9SAllan Stephens * the problem of a blocked socket operation preventing any other operations 1560c3141e9SAllan Stephens * from occurring. However, applications must be careful if they have 1570c3141e9SAllan Stephens * multiple threads trying to send (or receive) on the same socket, as these 1580c3141e9SAllan Stephens * operations might interfere with each other. For example, doing a connect 1590c3141e9SAllan Stephens * and a receive at the same time might allow the receive to consume the 1600c3141e9SAllan Stephens * ACK message meant for the connect. While additional work could be done 1610c3141e9SAllan Stephens * to try and overcome this, it doesn't seem to be worthwhile at the present. 1620c3141e9SAllan Stephens * 1630c3141e9SAllan Stephens * NOTE: Releasing the socket lock while an operation is sleeping also ensures 1640c3141e9SAllan Stephens * that another operation that must be performed in a non-blocking manner is 1650c3141e9SAllan Stephens * not delayed for very long because the lock has already been taken. 1660c3141e9SAllan Stephens * 1670c3141e9SAllan Stephens * NOTE: This code assumes that certain fields of a port/socket pair are 1680c3141e9SAllan Stephens * constant over its lifetime; such fields can be examined without taking 1690c3141e9SAllan Stephens * the socket lock and/or port lock, and do not need to be re-read even 1700c3141e9SAllan Stephens * after resuming processing after waiting. These fields include: 1710c3141e9SAllan Stephens * - socket type 1720c3141e9SAllan Stephens * - pointer to socket sk structure (aka tipc_sock structure) 1730c3141e9SAllan Stephens * - pointer to port structure 1740c3141e9SAllan Stephens * - port reference 175b97bf3fdSPer Liden */ 176b97bf3fdSPer Liden 177c5898636SJon Paul Maloy static u32 tsk_own_node(struct tipc_sock *tsk) 178c5898636SJon Paul Maloy { 179c5898636SJon Paul Maloy return msg_prevnode(&tsk->phdr); 180c5898636SJon Paul Maloy } 181c5898636SJon Paul Maloy 182301bae56SJon Paul Maloy static u32 tsk_peer_node(struct tipc_sock *tsk) 1832e84c60bSJon Paul Maloy { 184301bae56SJon Paul Maloy return msg_destnode(&tsk->phdr); 1852e84c60bSJon Paul Maloy } 1862e84c60bSJon Paul Maloy 187301bae56SJon Paul Maloy static u32 tsk_peer_port(struct tipc_sock *tsk) 1882e84c60bSJon Paul Maloy { 189301bae56SJon Paul Maloy return msg_destport(&tsk->phdr); 1902e84c60bSJon Paul Maloy } 1912e84c60bSJon Paul Maloy 192301bae56SJon Paul Maloy static bool tsk_unreliable(struct tipc_sock *tsk) 1932e84c60bSJon Paul Maloy { 194301bae56SJon Paul Maloy return msg_src_droppable(&tsk->phdr) != 0; 1952e84c60bSJon Paul Maloy } 1962e84c60bSJon Paul Maloy 197301bae56SJon Paul Maloy static void tsk_set_unreliable(struct tipc_sock *tsk, bool unreliable) 1982e84c60bSJon Paul Maloy { 199301bae56SJon Paul Maloy msg_set_src_droppable(&tsk->phdr, unreliable ? 1 : 0); 2002e84c60bSJon Paul Maloy } 2012e84c60bSJon Paul Maloy 202301bae56SJon Paul Maloy static bool tsk_unreturnable(struct tipc_sock *tsk) 2032e84c60bSJon Paul Maloy { 204301bae56SJon Paul Maloy return msg_dest_droppable(&tsk->phdr) != 0; 2052e84c60bSJon Paul Maloy } 2062e84c60bSJon Paul Maloy 207301bae56SJon Paul Maloy static void tsk_set_unreturnable(struct tipc_sock *tsk, bool unreturnable) 2082e84c60bSJon Paul Maloy { 209301bae56SJon Paul Maloy msg_set_dest_droppable(&tsk->phdr, unreturnable ? 1 : 0); 2102e84c60bSJon Paul Maloy } 2112e84c60bSJon Paul Maloy 212301bae56SJon Paul Maloy static int tsk_importance(struct tipc_sock *tsk) 2132e84c60bSJon Paul Maloy { 214301bae56SJon Paul Maloy return msg_importance(&tsk->phdr); 2152e84c60bSJon Paul Maloy } 2162e84c60bSJon Paul Maloy 217301bae56SJon Paul Maloy static int tsk_set_importance(struct tipc_sock *tsk, int imp) 2182e84c60bSJon Paul Maloy { 2192e84c60bSJon Paul Maloy if (imp > TIPC_CRITICAL_IMPORTANCE) 2202e84c60bSJon Paul Maloy return -EINVAL; 221301bae56SJon Paul Maloy msg_set_importance(&tsk->phdr, (u32)imp); 2222e84c60bSJon Paul Maloy return 0; 2232e84c60bSJon Paul Maloy } 2248826cde6SJon Paul Maloy 225301bae56SJon Paul Maloy static struct tipc_sock *tipc_sk(const struct sock *sk) 226301bae56SJon Paul Maloy { 227301bae56SJon Paul Maloy return container_of(sk, struct tipc_sock, sk); 228301bae56SJon Paul Maloy } 229301bae56SJon Paul Maloy 230301bae56SJon Paul Maloy static int tsk_conn_cong(struct tipc_sock *tsk) 231301bae56SJon Paul Maloy { 232301bae56SJon Paul Maloy return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN; 233301bae56SJon Paul Maloy } 234301bae56SJon Paul Maloy 235b97bf3fdSPer Liden /** 2362e84c60bSJon Paul Maloy * tsk_advance_rx_queue - discard first buffer in socket receive queue 2370c3141e9SAllan Stephens * 2380c3141e9SAllan Stephens * Caller must hold socket lock 239b97bf3fdSPer Liden */ 2402e84c60bSJon Paul Maloy static void tsk_advance_rx_queue(struct sock *sk) 241b97bf3fdSPer Liden { 2425f6d9123SAllan Stephens kfree_skb(__skb_dequeue(&sk->sk_receive_queue)); 243b97bf3fdSPer Liden } 244b97bf3fdSPer Liden 245bcd3ffd4SJon Paul Maloy /* tipc_sk_respond() : send response message back to sender 246bcd3ffd4SJon Paul Maloy */ 247bcd3ffd4SJon Paul Maloy static void tipc_sk_respond(struct sock *sk, struct sk_buff *skb, int err) 248bcd3ffd4SJon Paul Maloy { 249bcd3ffd4SJon Paul Maloy u32 selector; 250bcd3ffd4SJon Paul Maloy u32 dnode; 251bcd3ffd4SJon Paul Maloy u32 onode = tipc_own_addr(sock_net(sk)); 252bcd3ffd4SJon Paul Maloy 253bcd3ffd4SJon Paul Maloy if (!tipc_msg_reverse(onode, &skb, err)) 254bcd3ffd4SJon Paul Maloy return; 255bcd3ffd4SJon Paul Maloy 256bcd3ffd4SJon Paul Maloy dnode = msg_destnode(buf_msg(skb)); 257bcd3ffd4SJon Paul Maloy selector = msg_origport(buf_msg(skb)); 258bcd3ffd4SJon Paul Maloy tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector); 259bcd3ffd4SJon Paul Maloy } 260bcd3ffd4SJon Paul Maloy 261b97bf3fdSPer Liden /** 2622e84c60bSJon Paul Maloy * tsk_rej_rx_queue - reject all buffers in socket receive queue 2630c3141e9SAllan Stephens * 2640c3141e9SAllan Stephens * Caller must hold socket lock 2650c3141e9SAllan Stephens */ 2662e84c60bSJon Paul Maloy static void tsk_rej_rx_queue(struct sock *sk) 2670c3141e9SAllan Stephens { 268a6ca1094SYing Xue struct sk_buff *skb; 2690c3141e9SAllan Stephens 270bcd3ffd4SJon Paul Maloy while ((skb = __skb_dequeue(&sk->sk_receive_queue))) 271bcd3ffd4SJon Paul Maloy tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT); 2720c3141e9SAllan Stephens } 2730c3141e9SAllan Stephens 2742e84c60bSJon Paul Maloy /* tsk_peer_msg - verify if message was sent by connected port's peer 2750fc87aaeSJon Paul Maloy * 2760fc87aaeSJon Paul Maloy * Handles cases where the node's network address has changed from 2770fc87aaeSJon Paul Maloy * the default of <0.0.0> to its configured setting. 2780fc87aaeSJon Paul Maloy */ 2792e84c60bSJon Paul Maloy static bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg) 2800fc87aaeSJon Paul Maloy { 28134747539SYing Xue struct tipc_net *tn = net_generic(sock_net(&tsk->sk), tipc_net_id); 282301bae56SJon Paul Maloy u32 peer_port = tsk_peer_port(tsk); 2830fc87aaeSJon Paul Maloy u32 orig_node; 2840fc87aaeSJon Paul Maloy u32 peer_node; 2850fc87aaeSJon Paul Maloy 286301bae56SJon Paul Maloy if (unlikely(!tsk->connected)) 2870fc87aaeSJon Paul Maloy return false; 2880fc87aaeSJon Paul Maloy 2890fc87aaeSJon Paul Maloy if (unlikely(msg_origport(msg) != peer_port)) 2900fc87aaeSJon Paul Maloy return false; 2910fc87aaeSJon Paul Maloy 2920fc87aaeSJon Paul Maloy orig_node = msg_orignode(msg); 293301bae56SJon Paul Maloy peer_node = tsk_peer_node(tsk); 2940fc87aaeSJon Paul Maloy 2950fc87aaeSJon Paul Maloy if (likely(orig_node == peer_node)) 2960fc87aaeSJon Paul Maloy return true; 2970fc87aaeSJon Paul Maloy 29834747539SYing Xue if (!orig_node && (peer_node == tn->own_addr)) 2990fc87aaeSJon Paul Maloy return true; 3000fc87aaeSJon Paul Maloy 30134747539SYing Xue if (!peer_node && (orig_node == tn->own_addr)) 3020fc87aaeSJon Paul Maloy return true; 3030fc87aaeSJon Paul Maloy 3040fc87aaeSJon Paul Maloy return false; 3050fc87aaeSJon Paul Maloy } 3060fc87aaeSJon Paul Maloy 3070c3141e9SAllan Stephens /** 308c5fa7b3cSYing Xue * tipc_sk_create - create a TIPC socket 3090c3141e9SAllan Stephens * @net: network namespace (must be default network) 310b97bf3fdSPer Liden * @sock: pre-allocated socket structure 311b97bf3fdSPer Liden * @protocol: protocol indicator (must be 0) 3123f378b68SEric Paris * @kern: caused by kernel or by userspace? 313b97bf3fdSPer Liden * 3140c3141e9SAllan Stephens * This routine creates additional data structures used by the TIPC socket, 3150c3141e9SAllan Stephens * initializes them, and links them together. 316b97bf3fdSPer Liden * 317b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 318b97bf3fdSPer Liden */ 31958ed9442SJon Paul Maloy static int tipc_sk_create(struct net *net, struct socket *sock, 32058ed9442SJon Paul Maloy int protocol, int kern) 321b97bf3fdSPer Liden { 322c5898636SJon Paul Maloy struct tipc_net *tn; 3230c3141e9SAllan Stephens const struct proto_ops *ops; 3240c3141e9SAllan Stephens socket_state state; 325b97bf3fdSPer Liden struct sock *sk; 32658ed9442SJon Paul Maloy struct tipc_sock *tsk; 3275b8fa7ceSJon Paul Maloy struct tipc_msg *msg; 3280c3141e9SAllan Stephens 3290c3141e9SAllan Stephens /* Validate arguments */ 330b97bf3fdSPer Liden if (unlikely(protocol != 0)) 331b97bf3fdSPer Liden return -EPROTONOSUPPORT; 332b97bf3fdSPer Liden 333b97bf3fdSPer Liden switch (sock->type) { 334b97bf3fdSPer Liden case SOCK_STREAM: 3350c3141e9SAllan Stephens ops = &stream_ops; 3360c3141e9SAllan Stephens state = SS_UNCONNECTED; 337b97bf3fdSPer Liden break; 338b97bf3fdSPer Liden case SOCK_SEQPACKET: 3390c3141e9SAllan Stephens ops = &packet_ops; 3400c3141e9SAllan Stephens state = SS_UNCONNECTED; 341b97bf3fdSPer Liden break; 342b97bf3fdSPer Liden case SOCK_DGRAM: 343b97bf3fdSPer Liden case SOCK_RDM: 3440c3141e9SAllan Stephens ops = &msg_ops; 3450c3141e9SAllan Stephens state = SS_READY; 346b97bf3fdSPer Liden break; 34749978651SAllan Stephens default: 34849978651SAllan Stephens return -EPROTOTYPE; 349b97bf3fdSPer Liden } 350b97bf3fdSPer Liden 3510c3141e9SAllan Stephens /* Allocate socket's protocol area */ 35211aa9c28SEric W. Biederman sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto, kern); 3530c3141e9SAllan Stephens if (sk == NULL) 3540c3141e9SAllan Stephens return -ENOMEM; 3550c3141e9SAllan Stephens 35658ed9442SJon Paul Maloy tsk = tipc_sk(sk); 357301bae56SJon Paul Maloy tsk->max_pkt = MAX_PKT_DEFAULT; 358301bae56SJon Paul Maloy INIT_LIST_HEAD(&tsk->publications); 359301bae56SJon Paul Maloy msg = &tsk->phdr; 360c5898636SJon Paul Maloy tn = net_generic(sock_net(sk), tipc_net_id); 361c5898636SJon Paul Maloy tipc_msg_init(tn->own_addr, msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, 3625b8fa7ceSJon Paul Maloy NAMED_H_SIZE, 0); 363b97bf3fdSPer Liden 3640c3141e9SAllan Stephens /* Finish initializing socket data structures */ 3650c3141e9SAllan Stephens sock->ops = ops; 3660c3141e9SAllan Stephens sock->state = state; 367b97bf3fdSPer Liden sock_init_data(sock, sk); 36807f6c4bcSYing Xue if (tipc_sk_insert(tsk)) { 369*c19ca6cbSMasanari Iida pr_warn("Socket create failed; port number exhausted\n"); 37007f6c4bcSYing Xue return -EINVAL; 37107f6c4bcSYing Xue } 37207f6c4bcSYing Xue msg_set_origport(msg, tsk->portid); 3733721e9c7SYing Xue setup_timer(&sk->sk_timer, tipc_sk_timeout, (unsigned long)tsk); 3744f4482dcSJon Paul Maloy sk->sk_backlog_rcv = tipc_backlog_rcv; 375cc79dd1bSYing Xue sk->sk_rcvbuf = sysctl_tipc_rmem[1]; 376f288bef4SYing Xue sk->sk_data_ready = tipc_data_ready; 377f288bef4SYing Xue sk->sk_write_space = tipc_write_space; 378f4195d1eSYing Xue sk->sk_destruct = tipc_sock_destruct; 3794f4482dcSJon Paul Maloy tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; 38060120526SJon Paul Maloy tsk->sent_unacked = 0; 3814f4482dcSJon Paul Maloy atomic_set(&tsk->dupl_rcvcnt, 0); 3827ef43ebaSAllan Stephens 3830c3141e9SAllan Stephens if (sock->state == SS_READY) { 384301bae56SJon Paul Maloy tsk_set_unreturnable(tsk, true); 3850c3141e9SAllan Stephens if (sock->type == SOCK_DGRAM) 386301bae56SJon Paul Maloy tsk_set_unreliable(tsk, true); 3870c3141e9SAllan Stephens } 388b97bf3fdSPer Liden return 0; 389b97bf3fdSPer Liden } 390b97bf3fdSPer Liden 39107f6c4bcSYing Xue static void tipc_sk_callback(struct rcu_head *head) 39207f6c4bcSYing Xue { 39307f6c4bcSYing Xue struct tipc_sock *tsk = container_of(head, struct tipc_sock, rcu); 39407f6c4bcSYing Xue 39507f6c4bcSYing Xue sock_put(&tsk->sk); 39607f6c4bcSYing Xue } 39707f6c4bcSYing Xue 398c5fa7b3cSYing Xue /** 399247f0f3cSYing Xue * tipc_release - destroy a TIPC socket 400b97bf3fdSPer Liden * @sock: socket to destroy 401b97bf3fdSPer Liden * 402b97bf3fdSPer Liden * This routine cleans up any messages that are still queued on the socket. 403b97bf3fdSPer Liden * For DGRAM and RDM socket types, all queued messages are rejected. 404b97bf3fdSPer Liden * For SEQPACKET and STREAM socket types, the first message is rejected 405b97bf3fdSPer Liden * and any others are discarded. (If the first message on a STREAM socket 406b97bf3fdSPer Liden * is partially-read, it is discarded and the next one is rejected instead.) 407b97bf3fdSPer Liden * 408b97bf3fdSPer Liden * NOTE: Rejected messages are not necessarily returned to the sender! They 409b97bf3fdSPer Liden * are returned or discarded according to the "destination droppable" setting 410b97bf3fdSPer Liden * specified for the message by the sender. 411b97bf3fdSPer Liden * 412b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 413b97bf3fdSPer Liden */ 414247f0f3cSYing Xue static int tipc_release(struct socket *sock) 415b97bf3fdSPer Liden { 416b97bf3fdSPer Liden struct sock *sk = sock->sk; 417357c4774SSasha Levin struct net *net; 41858ed9442SJon Paul Maloy struct tipc_sock *tsk; 419a6ca1094SYing Xue struct sk_buff *skb; 4201ea23a21SYing Xue u32 dnode; 421b97bf3fdSPer Liden 4220c3141e9SAllan Stephens /* 4230c3141e9SAllan Stephens * Exit if socket isn't fully initialized (occurs when a failed accept() 4240c3141e9SAllan Stephens * releases a pre-allocated child socket that was never used) 4250c3141e9SAllan Stephens */ 4260c3141e9SAllan Stephens if (sk == NULL) 4270c3141e9SAllan Stephens return 0; 4280c3141e9SAllan Stephens 429357c4774SSasha Levin net = sock_net(sk); 43058ed9442SJon Paul Maloy tsk = tipc_sk(sk); 4310c3141e9SAllan Stephens lock_sock(sk); 4320c3141e9SAllan Stephens 4330c3141e9SAllan Stephens /* 4340c3141e9SAllan Stephens * Reject all unreceived messages, except on an active connection 4350c3141e9SAllan Stephens * (which disconnects locally & sends a 'FIN+' to peer) 4360c3141e9SAllan Stephens */ 437301bae56SJon Paul Maloy dnode = tsk_peer_node(tsk); 438b97bf3fdSPer Liden while (sock->state != SS_DISCONNECTING) { 439a6ca1094SYing Xue skb = __skb_dequeue(&sk->sk_receive_queue); 440a6ca1094SYing Xue if (skb == NULL) 441b97bf3fdSPer Liden break; 442a6ca1094SYing Xue if (TIPC_SKB_CB(skb)->handle != NULL) 443a6ca1094SYing Xue kfree_skb(skb); 4440c3141e9SAllan Stephens else { 4450c3141e9SAllan Stephens if ((sock->state == SS_CONNECTING) || 4460c3141e9SAllan Stephens (sock->state == SS_CONNECTED)) { 4470c3141e9SAllan Stephens sock->state = SS_DISCONNECTING; 448301bae56SJon Paul Maloy tsk->connected = 0; 449f2f9800dSYing Xue tipc_node_remove_conn(net, dnode, tsk->portid); 4500c3141e9SAllan Stephens } 451bcd3ffd4SJon Paul Maloy tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT); 4520c3141e9SAllan Stephens } 453b97bf3fdSPer Liden } 454b97bf3fdSPer Liden 455301bae56SJon Paul Maloy tipc_sk_withdraw(tsk, 0, NULL); 4561ea23a21SYing Xue sk_stop_timer(sk, &sk->sk_timer); 45707f6c4bcSYing Xue tipc_sk_remove(tsk); 458301bae56SJon Paul Maloy if (tsk->connected) { 459c5898636SJon Paul Maloy skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, 46034747539SYing Xue TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode, 461c5898636SJon Paul Maloy tsk_own_node(tsk), tsk_peer_port(tsk), 46207f6c4bcSYing Xue tsk->portid, TIPC_ERR_NO_PORT); 463a6ca1094SYing Xue if (skb) 464af9b028eSJon Paul Maloy tipc_node_xmit_skb(net, skb, dnode, tsk->portid); 465f2f9800dSYing Xue tipc_node_remove_conn(net, dnode, tsk->portid); 4665b8fa7ceSJon Paul Maloy } 467b97bf3fdSPer Liden 4680c3141e9SAllan Stephens /* Reject any messages that accumulated in backlog queue */ 4690c3141e9SAllan Stephens sock->state = SS_DISCONNECTING; 4700c3141e9SAllan Stephens release_sock(sk); 47107f6c4bcSYing Xue 47207f6c4bcSYing Xue call_rcu(&tsk->rcu, tipc_sk_callback); 4730c3141e9SAllan Stephens sock->sk = NULL; 474b97bf3fdSPer Liden 475065d7e39SGeert Uytterhoeven return 0; 476b97bf3fdSPer Liden } 477b97bf3fdSPer Liden 478b97bf3fdSPer Liden /** 479247f0f3cSYing Xue * tipc_bind - associate or disassocate TIPC name(s) with a socket 480b97bf3fdSPer Liden * @sock: socket structure 481b97bf3fdSPer Liden * @uaddr: socket address describing name(s) and desired operation 482b97bf3fdSPer Liden * @uaddr_len: size of socket address data structure 483b97bf3fdSPer Liden * 484b97bf3fdSPer Liden * Name and name sequence binding is indicated using a positive scope value; 485b97bf3fdSPer Liden * a negative scope value unbinds the specified name. Specifying no name 486b97bf3fdSPer Liden * (i.e. a socket address length of 0) unbinds all names from the socket. 487b97bf3fdSPer Liden * 488b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 4890c3141e9SAllan Stephens * 4900c3141e9SAllan Stephens * NOTE: This routine doesn't need to take the socket lock since it doesn't 4910c3141e9SAllan Stephens * access any non-constant socket information. 492b97bf3fdSPer Liden */ 493247f0f3cSYing Xue static int tipc_bind(struct socket *sock, struct sockaddr *uaddr, 494247f0f3cSYing Xue int uaddr_len) 495b97bf3fdSPer Liden { 49684602761SYing Xue struct sock *sk = sock->sk; 497b97bf3fdSPer Liden struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; 49858ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 49984602761SYing Xue int res = -EINVAL; 500b97bf3fdSPer Liden 50184602761SYing Xue lock_sock(sk); 50284602761SYing Xue if (unlikely(!uaddr_len)) { 503301bae56SJon Paul Maloy res = tipc_sk_withdraw(tsk, 0, NULL); 50484602761SYing Xue goto exit; 50584602761SYing Xue } 506b97bf3fdSPer Liden 50784602761SYing Xue if (uaddr_len < sizeof(struct sockaddr_tipc)) { 50884602761SYing Xue res = -EINVAL; 50984602761SYing Xue goto exit; 51084602761SYing Xue } 51184602761SYing Xue if (addr->family != AF_TIPC) { 51284602761SYing Xue res = -EAFNOSUPPORT; 51384602761SYing Xue goto exit; 51484602761SYing Xue } 515b97bf3fdSPer Liden 516b97bf3fdSPer Liden if (addr->addrtype == TIPC_ADDR_NAME) 517b97bf3fdSPer Liden addr->addr.nameseq.upper = addr->addr.nameseq.lower; 51884602761SYing Xue else if (addr->addrtype != TIPC_ADDR_NAMESEQ) { 51984602761SYing Xue res = -EAFNOSUPPORT; 52084602761SYing Xue goto exit; 52184602761SYing Xue } 522b97bf3fdSPer Liden 52313a2e898SYing Xue if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) && 5247d0ab17bSYing Xue (addr->addr.nameseq.type != TIPC_TOP_SRV) && 52584602761SYing Xue (addr->addr.nameseq.type != TIPC_CFG_SRV)) { 52684602761SYing Xue res = -EACCES; 52784602761SYing Xue goto exit; 52884602761SYing Xue } 529c422f1bdSAllan Stephens 53084602761SYing Xue res = (addr->scope > 0) ? 531301bae56SJon Paul Maloy tipc_sk_publish(tsk, addr->scope, &addr->addr.nameseq) : 532301bae56SJon Paul Maloy tipc_sk_withdraw(tsk, -addr->scope, &addr->addr.nameseq); 53384602761SYing Xue exit: 53484602761SYing Xue release_sock(sk); 53584602761SYing Xue return res; 536b97bf3fdSPer Liden } 537b97bf3fdSPer Liden 538b97bf3fdSPer Liden /** 539247f0f3cSYing Xue * tipc_getname - get port ID of socket or peer socket 540b97bf3fdSPer Liden * @sock: socket structure 541b97bf3fdSPer Liden * @uaddr: area for returned socket address 542b97bf3fdSPer Liden * @uaddr_len: area for returned length of socket address 5432da59918SAllan Stephens * @peer: 0 = own ID, 1 = current peer ID, 2 = current/former peer ID 544b97bf3fdSPer Liden * 545b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 5460c3141e9SAllan Stephens * 5472da59918SAllan Stephens * NOTE: This routine doesn't need to take the socket lock since it only 5482da59918SAllan Stephens * accesses socket information that is unchanging (or which changes in 5492da59918SAllan Stephens * a completely predictable manner). 550b97bf3fdSPer Liden */ 551247f0f3cSYing Xue static int tipc_getname(struct socket *sock, struct sockaddr *uaddr, 552b97bf3fdSPer Liden int *uaddr_len, int peer) 553b97bf3fdSPer Liden { 554b97bf3fdSPer Liden struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; 55558ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sock->sk); 55634747539SYing Xue struct tipc_net *tn = net_generic(sock_net(sock->sk), tipc_net_id); 557b97bf3fdSPer Liden 55888f8a5e3SKulikov Vasiliy memset(addr, 0, sizeof(*addr)); 5590c3141e9SAllan Stephens if (peer) { 5602da59918SAllan Stephens if ((sock->state != SS_CONNECTED) && 5612da59918SAllan Stephens ((peer != 2) || (sock->state != SS_DISCONNECTING))) 5622da59918SAllan Stephens return -ENOTCONN; 563301bae56SJon Paul Maloy addr->addr.id.ref = tsk_peer_port(tsk); 564301bae56SJon Paul Maloy addr->addr.id.node = tsk_peer_node(tsk); 5650c3141e9SAllan Stephens } else { 56607f6c4bcSYing Xue addr->addr.id.ref = tsk->portid; 56734747539SYing Xue addr->addr.id.node = tn->own_addr; 5680c3141e9SAllan Stephens } 569b97bf3fdSPer Liden 570b97bf3fdSPer Liden *uaddr_len = sizeof(*addr); 571b97bf3fdSPer Liden addr->addrtype = TIPC_ADDR_ID; 572b97bf3fdSPer Liden addr->family = AF_TIPC; 573b97bf3fdSPer Liden addr->scope = 0; 574b97bf3fdSPer Liden addr->addr.name.domain = 0; 575b97bf3fdSPer Liden 5760c3141e9SAllan Stephens return 0; 577b97bf3fdSPer Liden } 578b97bf3fdSPer Liden 579b97bf3fdSPer Liden /** 580247f0f3cSYing Xue * tipc_poll - read and possibly block on pollmask 581b97bf3fdSPer Liden * @file: file structure associated with the socket 582b97bf3fdSPer Liden * @sock: socket for which to calculate the poll bits 583b97bf3fdSPer Liden * @wait: ??? 584b97bf3fdSPer Liden * 5859b674e82SAllan Stephens * Returns pollmask value 5869b674e82SAllan Stephens * 5879b674e82SAllan Stephens * COMMENTARY: 5889b674e82SAllan Stephens * It appears that the usual socket locking mechanisms are not useful here 5899b674e82SAllan Stephens * since the pollmask info is potentially out-of-date the moment this routine 5909b674e82SAllan Stephens * exits. TCP and other protocols seem to rely on higher level poll routines 5919b674e82SAllan Stephens * to handle any preventable race conditions, so TIPC will do the same ... 5929b674e82SAllan Stephens * 5939b674e82SAllan Stephens * TIPC sets the returned events as follows: 5949b674e82SAllan Stephens * 595f662c070SAllan Stephens * socket state flags set 596f662c070SAllan Stephens * ------------ --------- 597f662c070SAllan Stephens * unconnected no read flags 598c4fc298aSErik Hugne * POLLOUT if port is not congested 599f662c070SAllan Stephens * 600f662c070SAllan Stephens * connecting POLLIN/POLLRDNORM if ACK/NACK in rx queue 601f662c070SAllan Stephens * no write flags 602f662c070SAllan Stephens * 603f662c070SAllan Stephens * connected POLLIN/POLLRDNORM if data in rx queue 604f662c070SAllan Stephens * POLLOUT if port is not congested 605f662c070SAllan Stephens * 606f662c070SAllan Stephens * disconnecting POLLIN/POLLRDNORM/POLLHUP 607f662c070SAllan Stephens * no write flags 608f662c070SAllan Stephens * 609f662c070SAllan Stephens * listening POLLIN if SYN in rx queue 610f662c070SAllan Stephens * no write flags 611f662c070SAllan Stephens * 612f662c070SAllan Stephens * ready POLLIN/POLLRDNORM if data in rx queue 613f662c070SAllan Stephens * [connectionless] POLLOUT (since port cannot be congested) 614f662c070SAllan Stephens * 615f662c070SAllan Stephens * IMPORTANT: The fact that a read or write operation is indicated does NOT 616f662c070SAllan Stephens * imply that the operation will succeed, merely that it should be performed 617f662c070SAllan Stephens * and will not block. 618b97bf3fdSPer Liden */ 619247f0f3cSYing Xue static unsigned int tipc_poll(struct file *file, struct socket *sock, 620b97bf3fdSPer Liden poll_table *wait) 621b97bf3fdSPer Liden { 6229b674e82SAllan Stephens struct sock *sk = sock->sk; 62358ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 624f662c070SAllan Stephens u32 mask = 0; 6259b674e82SAllan Stephens 626f288bef4SYing Xue sock_poll_wait(file, sk_sleep(sk), wait); 6279b674e82SAllan Stephens 628f662c070SAllan Stephens switch ((int)sock->state) { 629c4fc298aSErik Hugne case SS_UNCONNECTED: 63060120526SJon Paul Maloy if (!tsk->link_cong) 631c4fc298aSErik Hugne mask |= POLLOUT; 632c4fc298aSErik Hugne break; 633f662c070SAllan Stephens case SS_READY: 634f662c070SAllan Stephens case SS_CONNECTED: 635301bae56SJon Paul Maloy if (!tsk->link_cong && !tsk_conn_cong(tsk)) 6369b674e82SAllan Stephens mask |= POLLOUT; 637f662c070SAllan Stephens /* fall thru' */ 638f662c070SAllan Stephens case SS_CONNECTING: 639f662c070SAllan Stephens case SS_LISTENING: 640f662c070SAllan Stephens if (!skb_queue_empty(&sk->sk_receive_queue)) 641f662c070SAllan Stephens mask |= (POLLIN | POLLRDNORM); 642f662c070SAllan Stephens break; 643f662c070SAllan Stephens case SS_DISCONNECTING: 644f662c070SAllan Stephens mask = (POLLIN | POLLRDNORM | POLLHUP); 645f662c070SAllan Stephens break; 646f662c070SAllan Stephens } 6479b674e82SAllan Stephens 6489b674e82SAllan Stephens return mask; 649b97bf3fdSPer Liden } 650b97bf3fdSPer Liden 6510abd8ff2SJon Paul Maloy /** 6520abd8ff2SJon Paul Maloy * tipc_sendmcast - send multicast message 6530abd8ff2SJon Paul Maloy * @sock: socket structure 6540abd8ff2SJon Paul Maloy * @seq: destination address 655562640f3SAl Viro * @msg: message to send 6560abd8ff2SJon Paul Maloy * @dsz: total length of message data 6570abd8ff2SJon Paul Maloy * @timeo: timeout to wait for wakeup 6580abd8ff2SJon Paul Maloy * 6590abd8ff2SJon Paul Maloy * Called from function tipc_sendmsg(), which has done all sanity checks 6600abd8ff2SJon Paul Maloy * Returns the number of bytes sent on success, or errno 6610abd8ff2SJon Paul Maloy */ 6620abd8ff2SJon Paul Maloy static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, 663562640f3SAl Viro struct msghdr *msg, size_t dsz, long timeo) 6640abd8ff2SJon Paul Maloy { 6650abd8ff2SJon Paul Maloy struct sock *sk = sock->sk; 666c5898636SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 667f2f9800dSYing Xue struct net *net = sock_net(sk); 668c5898636SJon Paul Maloy struct tipc_msg *mhdr = &tsk->phdr; 669f214fc40SParthasarathy Bhuvaragan struct sk_buff_head pktchain; 670f25dcc76SAl Viro struct iov_iter save = msg->msg_iter; 6710abd8ff2SJon Paul Maloy uint mtu; 6720abd8ff2SJon Paul Maloy int rc; 6730abd8ff2SJon Paul Maloy 6740abd8ff2SJon Paul Maloy msg_set_type(mhdr, TIPC_MCAST_MSG); 6750abd8ff2SJon Paul Maloy msg_set_lookup_scope(mhdr, TIPC_CLUSTER_SCOPE); 6760abd8ff2SJon Paul Maloy msg_set_destport(mhdr, 0); 6770abd8ff2SJon Paul Maloy msg_set_destnode(mhdr, 0); 6780abd8ff2SJon Paul Maloy msg_set_nametype(mhdr, seq->type); 6790abd8ff2SJon Paul Maloy msg_set_namelower(mhdr, seq->lower); 6800abd8ff2SJon Paul Maloy msg_set_nameupper(mhdr, seq->upper); 6810abd8ff2SJon Paul Maloy msg_set_hdr_sz(mhdr, MCAST_H_SIZE); 6820abd8ff2SJon Paul Maloy 683f214fc40SParthasarathy Bhuvaragan skb_queue_head_init(&pktchain); 684f214fc40SParthasarathy Bhuvaragan 6850abd8ff2SJon Paul Maloy new_mtu: 686959e1781SJon Paul Maloy mtu = tipc_bcast_get_mtu(net); 687f214fc40SParthasarathy Bhuvaragan rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, &pktchain); 6880abd8ff2SJon Paul Maloy if (unlikely(rc < 0)) 6890abd8ff2SJon Paul Maloy return rc; 6900abd8ff2SJon Paul Maloy 6910abd8ff2SJon Paul Maloy do { 692f214fc40SParthasarathy Bhuvaragan rc = tipc_bcast_xmit(net, &pktchain); 69322d85c79SJon Paul Maloy if (likely(!rc)) 69422d85c79SJon Paul Maloy return dsz; 69522d85c79SJon Paul Maloy 69622d85c79SJon Paul Maloy if (rc == -ELINKCONG) { 69722d85c79SJon Paul Maloy tsk->link_cong = 1; 69822d85c79SJon Paul Maloy rc = tipc_wait_for_sndmsg(sock, &timeo); 69922d85c79SJon Paul Maloy if (!rc) 70022d85c79SJon Paul Maloy continue; 7010abd8ff2SJon Paul Maloy } 702f214fc40SParthasarathy Bhuvaragan __skb_queue_purge(&pktchain); 703f25dcc76SAl Viro if (rc == -EMSGSIZE) { 704f25dcc76SAl Viro msg->msg_iter = save; 7050abd8ff2SJon Paul Maloy goto new_mtu; 706f25dcc76SAl Viro } 7070abd8ff2SJon Paul Maloy break; 70822d85c79SJon Paul Maloy } while (1); 7090abd8ff2SJon Paul Maloy return rc; 7100abd8ff2SJon Paul Maloy } 7110abd8ff2SJon Paul Maloy 712cb1b7280SJon Paul Maloy /** 713cb1b7280SJon Paul Maloy * tipc_sk_mcast_rcv - Deliver multicast messages to all destination sockets 714cb1b7280SJon Paul Maloy * @arrvq: queue with arriving messages, to be cloned after destination lookup 715cb1b7280SJon Paul Maloy * @inputq: queue with cloned messages, delivered to socket after dest lookup 716cb1b7280SJon Paul Maloy * 717cb1b7280SJon Paul Maloy * Multi-threaded: parallel calls with reference to same queues may occur 718078bec82SJon Paul Maloy */ 719cb1b7280SJon Paul Maloy void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, 720cb1b7280SJon Paul Maloy struct sk_buff_head *inputq) 721078bec82SJon Paul Maloy { 722cb1b7280SJon Paul Maloy struct tipc_msg *msg; 7233c724acdSJon Paul Maloy struct tipc_plist dports; 7243c724acdSJon Paul Maloy u32 portid; 725078bec82SJon Paul Maloy u32 scope = TIPC_CLUSTER_SCOPE; 726cb1b7280SJon Paul Maloy struct sk_buff_head tmpq; 727cb1b7280SJon Paul Maloy uint hsz; 728cb1b7280SJon Paul Maloy struct sk_buff *skb, *_skb; 7293c724acdSJon Paul Maloy 730cb1b7280SJon Paul Maloy __skb_queue_head_init(&tmpq); 7313c724acdSJon Paul Maloy tipc_plist_init(&dports); 732078bec82SJon Paul Maloy 733cb1b7280SJon Paul Maloy skb = tipc_skb_peek(arrvq, &inputq->lock); 734cb1b7280SJon Paul Maloy for (; skb; skb = tipc_skb_peek(arrvq, &inputq->lock)) { 735cb1b7280SJon Paul Maloy msg = buf_msg(skb); 736cb1b7280SJon Paul Maloy hsz = skb_headroom(skb) + msg_hdr_sz(msg); 737cb1b7280SJon Paul Maloy 73834747539SYing Xue if (in_own_node(net, msg_orignode(msg))) 739078bec82SJon Paul Maloy scope = TIPC_NODE_SCOPE; 740078bec82SJon Paul Maloy 741cb1b7280SJon Paul Maloy /* Create destination port list and message clones: */ 742cb1b7280SJon Paul Maloy tipc_nametbl_mc_translate(net, 743cb1b7280SJon Paul Maloy msg_nametype(msg), msg_namelower(msg), 7444ac1c8d0SYing Xue msg_nameupper(msg), scope, &dports); 7453c724acdSJon Paul Maloy portid = tipc_plist_pop(&dports); 7463c724acdSJon Paul Maloy for (; portid; portid = tipc_plist_pop(&dports)) { 747cb1b7280SJon Paul Maloy _skb = __pskb_copy(skb, hsz, GFP_ATOMIC); 748cb1b7280SJon Paul Maloy if (_skb) { 749cb1b7280SJon Paul Maloy msg_set_destport(buf_msg(_skb), portid); 750cb1b7280SJon Paul Maloy __skb_queue_tail(&tmpq, _skb); 751078bec82SJon Paul Maloy continue; 752078bec82SJon Paul Maloy } 753cb1b7280SJon Paul Maloy pr_warn("Failed to clone mcast rcv buffer\n"); 754078bec82SJon Paul Maloy } 755cb1b7280SJon Paul Maloy /* Append to inputq if not already done by other thread */ 756cb1b7280SJon Paul Maloy spin_lock_bh(&inputq->lock); 757cb1b7280SJon Paul Maloy if (skb_peek(arrvq) == skb) { 758cb1b7280SJon Paul Maloy skb_queue_splice_tail_init(&tmpq, inputq); 759cb1b7280SJon Paul Maloy kfree_skb(__skb_dequeue(arrvq)); 760cb1b7280SJon Paul Maloy } 761cb1b7280SJon Paul Maloy spin_unlock_bh(&inputq->lock); 762cb1b7280SJon Paul Maloy __skb_queue_purge(&tmpq); 7633c724acdSJon Paul Maloy kfree_skb(skb); 764078bec82SJon Paul Maloy } 765cb1b7280SJon Paul Maloy tipc_sk_rcv(net, inputq); 766cb1b7280SJon Paul Maloy } 767078bec82SJon Paul Maloy 768b97bf3fdSPer Liden /** 769ac0074eeSJon Paul Maloy * tipc_sk_proto_rcv - receive a connection mng protocol message 770ac0074eeSJon Paul Maloy * @tsk: receiving socket 771bcd3ffd4SJon Paul Maloy * @skb: pointer to message buffer. 772ac0074eeSJon Paul Maloy */ 773bcd3ffd4SJon Paul Maloy static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb) 774ac0074eeSJon Paul Maloy { 775bcd3ffd4SJon Paul Maloy struct sock *sk = &tsk->sk; 776bcd3ffd4SJon Paul Maloy struct tipc_msg *hdr = buf_msg(skb); 777bcd3ffd4SJon Paul Maloy int mtyp = msg_type(hdr); 77860120526SJon Paul Maloy int conn_cong; 779bcd3ffd4SJon Paul Maloy 780ac0074eeSJon Paul Maloy /* Ignore if connection cannot be validated: */ 781bcd3ffd4SJon Paul Maloy if (!tsk_peer_msg(tsk, hdr)) 782ac0074eeSJon Paul Maloy goto exit; 783ac0074eeSJon Paul Maloy 784301bae56SJon Paul Maloy tsk->probing_state = TIPC_CONN_OK; 785ac0074eeSJon Paul Maloy 786bcd3ffd4SJon Paul Maloy if (mtyp == CONN_PROBE) { 787bcd3ffd4SJon Paul Maloy msg_set_type(hdr, CONN_PROBE_REPLY); 788bcd3ffd4SJon Paul Maloy tipc_sk_respond(sk, skb, TIPC_OK); 7891186adf7SJon Paul Maloy return; 790bcd3ffd4SJon Paul Maloy } else if (mtyp == CONN_ACK) { 791bcd3ffd4SJon Paul Maloy conn_cong = tsk_conn_cong(tsk); 792bcd3ffd4SJon Paul Maloy tsk->sent_unacked -= msg_msgcnt(hdr); 793bcd3ffd4SJon Paul Maloy if (conn_cong) 794bcd3ffd4SJon Paul Maloy sk->sk_write_space(sk); 795bcd3ffd4SJon Paul Maloy } else if (mtyp != CONN_PROBE_REPLY) { 796bcd3ffd4SJon Paul Maloy pr_warn("Received unknown CONN_PROTO msg\n"); 7971186adf7SJon Paul Maloy } 798ac0074eeSJon Paul Maloy exit: 799bcd3ffd4SJon Paul Maloy kfree_skb(skb); 800ac0074eeSJon Paul Maloy } 801ac0074eeSJon Paul Maloy 8023f40504fSYing Xue static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) 8033f40504fSYing Xue { 8043f40504fSYing Xue struct sock *sk = sock->sk; 80558ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 8063f40504fSYing Xue DEFINE_WAIT(wait); 8073f40504fSYing Xue int done; 8083f40504fSYing Xue 8093f40504fSYing Xue do { 8103f40504fSYing Xue int err = sock_error(sk); 8113f40504fSYing Xue if (err) 8123f40504fSYing Xue return err; 8133f40504fSYing Xue if (sock->state == SS_DISCONNECTING) 8143f40504fSYing Xue return -EPIPE; 8153f40504fSYing Xue if (!*timeo_p) 8163f40504fSYing Xue return -EAGAIN; 8173f40504fSYing Xue if (signal_pending(current)) 8183f40504fSYing Xue return sock_intr_errno(*timeo_p); 8193f40504fSYing Xue 8203f40504fSYing Xue prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 82160120526SJon Paul Maloy done = sk_wait_event(sk, timeo_p, !tsk->link_cong); 8223f40504fSYing Xue finish_wait(sk_sleep(sk), &wait); 8233f40504fSYing Xue } while (!done); 8243f40504fSYing Xue return 0; 8253f40504fSYing Xue } 8263f40504fSYing Xue 827e2dafe87SJon Paul Maloy /** 828247f0f3cSYing Xue * tipc_sendmsg - send message in connectionless manner 829b97bf3fdSPer Liden * @sock: socket structure 830b97bf3fdSPer Liden * @m: message to send 831e2dafe87SJon Paul Maloy * @dsz: amount of user data to be sent 832b97bf3fdSPer Liden * 833b97bf3fdSPer Liden * Message must have an destination specified explicitly. 834b97bf3fdSPer Liden * Used for SOCK_RDM and SOCK_DGRAM messages, 835b97bf3fdSPer Liden * and for 'SYN' messages on SOCK_SEQPACKET and SOCK_STREAM connections. 836b97bf3fdSPer Liden * (Note: 'SYN+' is prohibited on SOCK_STREAM.) 837b97bf3fdSPer Liden * 838b97bf3fdSPer Liden * Returns the number of bytes sent on success, or errno otherwise 839b97bf3fdSPer Liden */ 8401b784140SYing Xue static int tipc_sendmsg(struct socket *sock, 841e2dafe87SJon Paul Maloy struct msghdr *m, size_t dsz) 842b97bf3fdSPer Liden { 84339a0295fSYing Xue struct sock *sk = sock->sk; 84439a0295fSYing Xue int ret; 84539a0295fSYing Xue 84639a0295fSYing Xue lock_sock(sk); 84739a0295fSYing Xue ret = __tipc_sendmsg(sock, m, dsz); 84839a0295fSYing Xue release_sock(sk); 84939a0295fSYing Xue 85039a0295fSYing Xue return ret; 85139a0295fSYing Xue } 85239a0295fSYing Xue 85339a0295fSYing Xue static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz) 85439a0295fSYing Xue { 855e2dafe87SJon Paul Maloy DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); 8560c3141e9SAllan Stephens struct sock *sk = sock->sk; 85758ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 858f2f9800dSYing Xue struct net *net = sock_net(sk); 859301bae56SJon Paul Maloy struct tipc_msg *mhdr = &tsk->phdr; 860e2dafe87SJon Paul Maloy u32 dnode, dport; 861f214fc40SParthasarathy Bhuvaragan struct sk_buff_head pktchain; 862a6ca1094SYing Xue struct sk_buff *skb; 863f2f8036eSErik Hugne struct tipc_name_seq *seq; 864f25dcc76SAl Viro struct iov_iter save; 865e2dafe87SJon Paul Maloy u32 mtu; 8663f40504fSYing Xue long timeo; 86788b17b6aSErik Hugne int rc; 868b97bf3fdSPer Liden 869e2dafe87SJon Paul Maloy if (dsz > TIPC_MAX_USER_MSG_SIZE) 870c29c3f70SAllan Stephens return -EMSGSIZE; 871f2f8036eSErik Hugne if (unlikely(!dest)) { 872f2f8036eSErik Hugne if (tsk->connected && sock->state == SS_READY) 873f2f8036eSErik Hugne dest = &tsk->remote; 874f2f8036eSErik Hugne else 875f2f8036eSErik Hugne return -EDESTADDRREQ; 876f2f8036eSErik Hugne } else if (unlikely(m->msg_namelen < sizeof(*dest)) || 877f2f8036eSErik Hugne dest->family != AF_TIPC) { 878f2f8036eSErik Hugne return -EINVAL; 879f2f8036eSErik Hugne } 880e2dafe87SJon Paul Maloy if (unlikely(sock->state != SS_READY)) { 88139a0295fSYing Xue if (sock->state == SS_LISTENING) 88239a0295fSYing Xue return -EPIPE; 88339a0295fSYing Xue if (sock->state != SS_UNCONNECTED) 88439a0295fSYing Xue return -EISCONN; 88539a0295fSYing Xue if (tsk->published) 88639a0295fSYing Xue return -EOPNOTSUPP; 8873388007bSAllan Stephens if (dest->addrtype == TIPC_ADDR_NAME) { 888301bae56SJon Paul Maloy tsk->conn_type = dest->addr.name.name.type; 889301bae56SJon Paul Maloy tsk->conn_instance = dest->addr.name.name.instance; 8903388007bSAllan Stephens } 891b97bf3fdSPer Liden } 892f2f8036eSErik Hugne seq = &dest->addr.nameseq; 8933f40504fSYing Xue timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); 894e2dafe87SJon Paul Maloy 895e2dafe87SJon Paul Maloy if (dest->addrtype == TIPC_ADDR_MCAST) { 89639a0295fSYing Xue return tipc_sendmcast(sock, seq, m, dsz, timeo); 897e2dafe87SJon Paul Maloy } else if (dest->addrtype == TIPC_ADDR_NAME) { 898e2dafe87SJon Paul Maloy u32 type = dest->addr.name.name.type; 899e2dafe87SJon Paul Maloy u32 inst = dest->addr.name.name.instance; 900e2dafe87SJon Paul Maloy u32 domain = dest->addr.name.domain; 901e2dafe87SJon Paul Maloy 902e2dafe87SJon Paul Maloy dnode = domain; 903e2dafe87SJon Paul Maloy msg_set_type(mhdr, TIPC_NAMED_MSG); 904e2dafe87SJon Paul Maloy msg_set_hdr_sz(mhdr, NAMED_H_SIZE); 905e2dafe87SJon Paul Maloy msg_set_nametype(mhdr, type); 906e2dafe87SJon Paul Maloy msg_set_nameinst(mhdr, inst); 907e2dafe87SJon Paul Maloy msg_set_lookup_scope(mhdr, tipc_addr_scope(domain)); 9084ac1c8d0SYing Xue dport = tipc_nametbl_translate(net, type, inst, &dnode); 909e2dafe87SJon Paul Maloy msg_set_destnode(mhdr, dnode); 910e2dafe87SJon Paul Maloy msg_set_destport(mhdr, dport); 91139a0295fSYing Xue if (unlikely(!dport && !dnode)) 91239a0295fSYing Xue return -EHOSTUNREACH; 9130e65967eSAllan Stephens } else if (dest->addrtype == TIPC_ADDR_ID) { 914e2dafe87SJon Paul Maloy dnode = dest->addr.id.node; 915e2dafe87SJon Paul Maloy msg_set_type(mhdr, TIPC_DIRECT_MSG); 916e2dafe87SJon Paul Maloy msg_set_lookup_scope(mhdr, 0); 917e2dafe87SJon Paul Maloy msg_set_destnode(mhdr, dnode); 918e2dafe87SJon Paul Maloy msg_set_destport(mhdr, dest->addr.id.ref); 919e2dafe87SJon Paul Maloy msg_set_hdr_sz(mhdr, BASIC_H_SIZE); 920b97bf3fdSPer Liden } 921e2dafe87SJon Paul Maloy 922f214fc40SParthasarathy Bhuvaragan skb_queue_head_init(&pktchain); 923f25dcc76SAl Viro save = m->msg_iter; 924e2dafe87SJon Paul Maloy new_mtu: 925f2f9800dSYing Xue mtu = tipc_node_get_mtu(net, dnode, tsk->portid); 926f214fc40SParthasarathy Bhuvaragan rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, &pktchain); 927e2dafe87SJon Paul Maloy if (rc < 0) 92839a0295fSYing Xue return rc; 929e2dafe87SJon Paul Maloy 930e2dafe87SJon Paul Maloy do { 931f214fc40SParthasarathy Bhuvaragan skb = skb_peek(&pktchain); 932a6ca1094SYing Xue TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong; 933f214fc40SParthasarathy Bhuvaragan rc = tipc_node_xmit(net, &pktchain, dnode, tsk->portid); 93422d85c79SJon Paul Maloy if (likely(!rc)) { 935e2dafe87SJon Paul Maloy if (sock->state != SS_READY) 9360c3141e9SAllan Stephens sock->state = SS_CONNECTING; 93722d85c79SJon Paul Maloy return dsz; 938b97bf3fdSPer Liden } 93922d85c79SJon Paul Maloy if (rc == -ELINKCONG) { 94022d85c79SJon Paul Maloy tsk->link_cong = 1; 94122d85c79SJon Paul Maloy rc = tipc_wait_for_sndmsg(sock, &timeo); 94222d85c79SJon Paul Maloy if (!rc) 94322d85c79SJon Paul Maloy continue; 94422d85c79SJon Paul Maloy } 945f214fc40SParthasarathy Bhuvaragan __skb_queue_purge(&pktchain); 946f25dcc76SAl Viro if (rc == -EMSGSIZE) { 947f25dcc76SAl Viro m->msg_iter = save; 948e2dafe87SJon Paul Maloy goto new_mtu; 949f25dcc76SAl Viro } 9500c3141e9SAllan Stephens break; 95122d85c79SJon Paul Maloy } while (1); 952e2dafe87SJon Paul Maloy 953e2dafe87SJon Paul Maloy return rc; 954b97bf3fdSPer Liden } 955b97bf3fdSPer Liden 956391a6dd1SYing Xue static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) 957391a6dd1SYing Xue { 958391a6dd1SYing Xue struct sock *sk = sock->sk; 95958ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 960391a6dd1SYing Xue DEFINE_WAIT(wait); 961391a6dd1SYing Xue int done; 962391a6dd1SYing Xue 963391a6dd1SYing Xue do { 964391a6dd1SYing Xue int err = sock_error(sk); 965391a6dd1SYing Xue if (err) 966391a6dd1SYing Xue return err; 967391a6dd1SYing Xue if (sock->state == SS_DISCONNECTING) 968391a6dd1SYing Xue return -EPIPE; 969391a6dd1SYing Xue else if (sock->state != SS_CONNECTED) 970391a6dd1SYing Xue return -ENOTCONN; 971391a6dd1SYing Xue if (!*timeo_p) 972391a6dd1SYing Xue return -EAGAIN; 973391a6dd1SYing Xue if (signal_pending(current)) 974391a6dd1SYing Xue return sock_intr_errno(*timeo_p); 975391a6dd1SYing Xue 976391a6dd1SYing Xue prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 977391a6dd1SYing Xue done = sk_wait_event(sk, timeo_p, 97860120526SJon Paul Maloy (!tsk->link_cong && 979301bae56SJon Paul Maloy !tsk_conn_cong(tsk)) || 980301bae56SJon Paul Maloy !tsk->connected); 981391a6dd1SYing Xue finish_wait(sk_sleep(sk), &wait); 982391a6dd1SYing Xue } while (!done); 983391a6dd1SYing Xue return 0; 984391a6dd1SYing Xue } 985391a6dd1SYing Xue 986b97bf3fdSPer Liden /** 987247f0f3cSYing Xue * tipc_send_stream - send stream-oriented data 988b97bf3fdSPer Liden * @sock: socket structure 989b97bf3fdSPer Liden * @m: data to send 9904ccfe5e0SJon Paul Maloy * @dsz: total length of data to be transmitted 991b97bf3fdSPer Liden * 992b97bf3fdSPer Liden * Used for SOCK_STREAM data. 993b97bf3fdSPer Liden * 9941303e8f1SAllan Stephens * Returns the number of bytes sent on success (or partial success), 9951303e8f1SAllan Stephens * or errno if no data sent 996b97bf3fdSPer Liden */ 9971b784140SYing Xue static int tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz) 998b97bf3fdSPer Liden { 9990c3141e9SAllan Stephens struct sock *sk = sock->sk; 100039a0295fSYing Xue int ret; 100139a0295fSYing Xue 100239a0295fSYing Xue lock_sock(sk); 100339a0295fSYing Xue ret = __tipc_send_stream(sock, m, dsz); 100439a0295fSYing Xue release_sock(sk); 100539a0295fSYing Xue 100639a0295fSYing Xue return ret; 100739a0295fSYing Xue } 100839a0295fSYing Xue 100939a0295fSYing Xue static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz) 101039a0295fSYing Xue { 101139a0295fSYing Xue struct sock *sk = sock->sk; 1012f2f9800dSYing Xue struct net *net = sock_net(sk); 101358ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 1014301bae56SJon Paul Maloy struct tipc_msg *mhdr = &tsk->phdr; 1015f214fc40SParthasarathy Bhuvaragan struct sk_buff_head pktchain; 10164ccfe5e0SJon Paul Maloy DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); 101707f6c4bcSYing Xue u32 portid = tsk->portid; 10184ccfe5e0SJon Paul Maloy int rc = -EINVAL; 10194ccfe5e0SJon Paul Maloy long timeo; 10204ccfe5e0SJon Paul Maloy u32 dnode; 10214ccfe5e0SJon Paul Maloy uint mtu, send, sent = 0; 1022f25dcc76SAl Viro struct iov_iter save; 1023b97bf3fdSPer Liden 10244ccfe5e0SJon Paul Maloy /* Handle implied connection establishment */ 10254ccfe5e0SJon Paul Maloy if (unlikely(dest)) { 102639a0295fSYing Xue rc = __tipc_sendmsg(sock, m, dsz); 10274ccfe5e0SJon Paul Maloy if (dsz && (dsz == rc)) 102860120526SJon Paul Maloy tsk->sent_unacked = 1; 10294ccfe5e0SJon Paul Maloy return rc; 10304ccfe5e0SJon Paul Maloy } 10314ccfe5e0SJon Paul Maloy if (dsz > (uint)INT_MAX) 10324ccfe5e0SJon Paul Maloy return -EMSGSIZE; 10334ccfe5e0SJon Paul Maloy 1034b97bf3fdSPer Liden if (unlikely(sock->state != SS_CONNECTED)) { 10354ccfe5e0SJon Paul Maloy if (sock->state == SS_DISCONNECTING) 103639a0295fSYing Xue return -EPIPE; 1037b0555976Swangweidong else 103839a0295fSYing Xue return -ENOTCONN; 10390c3141e9SAllan Stephens } 1040b97bf3fdSPer Liden 10414ccfe5e0SJon Paul Maloy timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); 1042301bae56SJon Paul Maloy dnode = tsk_peer_node(tsk); 1043f214fc40SParthasarathy Bhuvaragan skb_queue_head_init(&pktchain); 10444ccfe5e0SJon Paul Maloy 10454ccfe5e0SJon Paul Maloy next: 1046f25dcc76SAl Viro save = m->msg_iter; 1047301bae56SJon Paul Maloy mtu = tsk->max_pkt; 10484ccfe5e0SJon Paul Maloy send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE); 1049f214fc40SParthasarathy Bhuvaragan rc = tipc_msg_build(mhdr, m, sent, send, mtu, &pktchain); 10504ccfe5e0SJon Paul Maloy if (unlikely(rc < 0)) 105139a0295fSYing Xue return rc; 1052f214fc40SParthasarathy Bhuvaragan 10534ccfe5e0SJon Paul Maloy do { 1054301bae56SJon Paul Maloy if (likely(!tsk_conn_cong(tsk))) { 1055f214fc40SParthasarathy Bhuvaragan rc = tipc_node_xmit(net, &pktchain, dnode, portid); 10564ccfe5e0SJon Paul Maloy if (likely(!rc)) { 105760120526SJon Paul Maloy tsk->sent_unacked++; 10584ccfe5e0SJon Paul Maloy sent += send; 10594ccfe5e0SJon Paul Maloy if (sent == dsz) 106022d85c79SJon Paul Maloy return dsz; 10614ccfe5e0SJon Paul Maloy goto next; 10620c3141e9SAllan Stephens } 10634ccfe5e0SJon Paul Maloy if (rc == -EMSGSIZE) { 1064f214fc40SParthasarathy Bhuvaragan __skb_queue_purge(&pktchain); 1065f2f9800dSYing Xue tsk->max_pkt = tipc_node_get_mtu(net, dnode, 1066f2f9800dSYing Xue portid); 1067f25dcc76SAl Viro m->msg_iter = save; 10684ccfe5e0SJon Paul Maloy goto next; 1069c29c3f70SAllan Stephens } 10704ccfe5e0SJon Paul Maloy if (rc != -ELINKCONG) 10714ccfe5e0SJon Paul Maloy break; 107222d85c79SJon Paul Maloy 107350100a5eSJon Paul Maloy tsk->link_cong = 1; 10741303e8f1SAllan Stephens } 10754ccfe5e0SJon Paul Maloy rc = tipc_wait_for_sndpkt(sock, &timeo); 10764ccfe5e0SJon Paul Maloy } while (!rc); 107739a0295fSYing Xue 1078f214fc40SParthasarathy Bhuvaragan __skb_queue_purge(&pktchain); 10794ccfe5e0SJon Paul Maloy return sent ? sent : rc; 10804ccfe5e0SJon Paul Maloy } 10814ccfe5e0SJon Paul Maloy 10824ccfe5e0SJon Paul Maloy /** 10834ccfe5e0SJon Paul Maloy * tipc_send_packet - send a connection-oriented message 10844ccfe5e0SJon Paul Maloy * @sock: socket structure 10854ccfe5e0SJon Paul Maloy * @m: message to send 10864ccfe5e0SJon Paul Maloy * @dsz: length of data to be transmitted 10874ccfe5e0SJon Paul Maloy * 10884ccfe5e0SJon Paul Maloy * Used for SOCK_SEQPACKET messages. 10894ccfe5e0SJon Paul Maloy * 10904ccfe5e0SJon Paul Maloy * Returns the number of bytes sent on success, or errno otherwise 10914ccfe5e0SJon Paul Maloy */ 10921b784140SYing Xue static int tipc_send_packet(struct socket *sock, struct msghdr *m, size_t dsz) 10934ccfe5e0SJon Paul Maloy { 10944ccfe5e0SJon Paul Maloy if (dsz > TIPC_MAX_USER_MSG_SIZE) 10954ccfe5e0SJon Paul Maloy return -EMSGSIZE; 10964ccfe5e0SJon Paul Maloy 10971b784140SYing Xue return tipc_send_stream(sock, m, dsz); 1098b97bf3fdSPer Liden } 1099b97bf3fdSPer Liden 1100dadebc00SJon Paul Maloy /* tipc_sk_finish_conn - complete the setup of a connection 1101b97bf3fdSPer Liden */ 1102301bae56SJon Paul Maloy static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port, 1103dadebc00SJon Paul Maloy u32 peer_node) 1104b97bf3fdSPer Liden { 11053721e9c7SYing Xue struct sock *sk = &tsk->sk; 11063721e9c7SYing Xue struct net *net = sock_net(sk); 1107301bae56SJon Paul Maloy struct tipc_msg *msg = &tsk->phdr; 1108b97bf3fdSPer Liden 1109dadebc00SJon Paul Maloy msg_set_destnode(msg, peer_node); 1110dadebc00SJon Paul Maloy msg_set_destport(msg, peer_port); 1111dadebc00SJon Paul Maloy msg_set_type(msg, TIPC_CONN_MSG); 1112dadebc00SJon Paul Maloy msg_set_lookup_scope(msg, 0); 1113dadebc00SJon Paul Maloy msg_set_hdr_sz(msg, SHORT_H_SIZE); 1114f9fef18cSJon Paul Maloy 11152f55c437SYing Xue tsk->probing_intv = CONN_PROBING_INTERVAL; 1116301bae56SJon Paul Maloy tsk->probing_state = TIPC_CONN_OK; 1117301bae56SJon Paul Maloy tsk->connected = 1; 11183721e9c7SYing Xue sk_reset_timer(sk, &sk->sk_timer, jiffies + tsk->probing_intv); 1119f2f9800dSYing Xue tipc_node_add_conn(net, peer_node, tsk->portid, peer_port); 1120f2f9800dSYing Xue tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid); 1121b97bf3fdSPer Liden } 1122b97bf3fdSPer Liden 1123b97bf3fdSPer Liden /** 1124b97bf3fdSPer Liden * set_orig_addr - capture sender's address for received message 1125b97bf3fdSPer Liden * @m: descriptor for message info 1126b97bf3fdSPer Liden * @msg: received message header 1127b97bf3fdSPer Liden * 1128b97bf3fdSPer Liden * Note: Address is not captured if not requested by receiver. 1129b97bf3fdSPer Liden */ 113005790c64SSam Ravnborg static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) 1131b97bf3fdSPer Liden { 1132342dfc30SSteffen Hurrle DECLARE_SOCKADDR(struct sockaddr_tipc *, addr, m->msg_name); 1133b97bf3fdSPer Liden 1134b97bf3fdSPer Liden if (addr) { 1135b97bf3fdSPer Liden addr->family = AF_TIPC; 1136b97bf3fdSPer Liden addr->addrtype = TIPC_ADDR_ID; 113760085c3dSMathias Krause memset(&addr->addr, 0, sizeof(addr->addr)); 1138b97bf3fdSPer Liden addr->addr.id.ref = msg_origport(msg); 1139b97bf3fdSPer Liden addr->addr.id.node = msg_orignode(msg); 1140b97bf3fdSPer Liden addr->addr.name.domain = 0; /* could leave uninitialized */ 1141b97bf3fdSPer Liden addr->scope = 0; /* could leave uninitialized */ 1142b97bf3fdSPer Liden m->msg_namelen = sizeof(struct sockaddr_tipc); 1143b97bf3fdSPer Liden } 1144b97bf3fdSPer Liden } 1145b97bf3fdSPer Liden 1146b97bf3fdSPer Liden /** 1147301bae56SJon Paul Maloy * tipc_sk_anc_data_recv - optionally capture ancillary data for received message 1148b97bf3fdSPer Liden * @m: descriptor for message info 1149b97bf3fdSPer Liden * @msg: received message header 1150301bae56SJon Paul Maloy * @tsk: TIPC port associated with message 1151b97bf3fdSPer Liden * 1152b97bf3fdSPer Liden * Note: Ancillary data is not captured if not requested by receiver. 1153b97bf3fdSPer Liden * 1154b97bf3fdSPer Liden * Returns 0 if successful, otherwise errno 1155b97bf3fdSPer Liden */ 1156301bae56SJon Paul Maloy static int tipc_sk_anc_data_recv(struct msghdr *m, struct tipc_msg *msg, 1157301bae56SJon Paul Maloy struct tipc_sock *tsk) 1158b97bf3fdSPer Liden { 1159b97bf3fdSPer Liden u32 anc_data[3]; 1160b97bf3fdSPer Liden u32 err; 1161b97bf3fdSPer Liden u32 dest_type; 11623546c750SAllan Stephens int has_name; 1163b97bf3fdSPer Liden int res; 1164b97bf3fdSPer Liden 1165b97bf3fdSPer Liden if (likely(m->msg_controllen == 0)) 1166b97bf3fdSPer Liden return 0; 1167b97bf3fdSPer Liden 1168b97bf3fdSPer Liden /* Optionally capture errored message object(s) */ 1169b97bf3fdSPer Liden err = msg ? msg_errcode(msg) : 0; 1170b97bf3fdSPer Liden if (unlikely(err)) { 1171b97bf3fdSPer Liden anc_data[0] = err; 1172b97bf3fdSPer Liden anc_data[1] = msg_data_sz(msg); 11732db9983aSAllan Stephens res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data); 11742db9983aSAllan Stephens if (res) 1175b97bf3fdSPer Liden return res; 11762db9983aSAllan Stephens if (anc_data[1]) { 11772db9983aSAllan Stephens res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1], 11782db9983aSAllan Stephens msg_data(msg)); 11792db9983aSAllan Stephens if (res) 1180b97bf3fdSPer Liden return res; 1181b97bf3fdSPer Liden } 11822db9983aSAllan Stephens } 1183b97bf3fdSPer Liden 1184b97bf3fdSPer Liden /* Optionally capture message destination object */ 1185b97bf3fdSPer Liden dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG; 1186b97bf3fdSPer Liden switch (dest_type) { 1187b97bf3fdSPer Liden case TIPC_NAMED_MSG: 11883546c750SAllan Stephens has_name = 1; 1189b97bf3fdSPer Liden anc_data[0] = msg_nametype(msg); 1190b97bf3fdSPer Liden anc_data[1] = msg_namelower(msg); 1191b97bf3fdSPer Liden anc_data[2] = msg_namelower(msg); 1192b97bf3fdSPer Liden break; 1193b97bf3fdSPer Liden case TIPC_MCAST_MSG: 11943546c750SAllan Stephens has_name = 1; 1195b97bf3fdSPer Liden anc_data[0] = msg_nametype(msg); 1196b97bf3fdSPer Liden anc_data[1] = msg_namelower(msg); 1197b97bf3fdSPer Liden anc_data[2] = msg_nameupper(msg); 1198b97bf3fdSPer Liden break; 1199b97bf3fdSPer Liden case TIPC_CONN_MSG: 1200301bae56SJon Paul Maloy has_name = (tsk->conn_type != 0); 1201301bae56SJon Paul Maloy anc_data[0] = tsk->conn_type; 1202301bae56SJon Paul Maloy anc_data[1] = tsk->conn_instance; 1203301bae56SJon Paul Maloy anc_data[2] = tsk->conn_instance; 1204b97bf3fdSPer Liden break; 1205b97bf3fdSPer Liden default: 12063546c750SAllan Stephens has_name = 0; 1207b97bf3fdSPer Liden } 12082db9983aSAllan Stephens if (has_name) { 12092db9983aSAllan Stephens res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data); 12102db9983aSAllan Stephens if (res) 1211b97bf3fdSPer Liden return res; 12122db9983aSAllan Stephens } 1213b97bf3fdSPer Liden 1214b97bf3fdSPer Liden return 0; 1215b97bf3fdSPer Liden } 1216b97bf3fdSPer Liden 1217301bae56SJon Paul Maloy static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack) 1218739f5e4eSJon Paul Maloy { 1219f2f9800dSYing Xue struct net *net = sock_net(&tsk->sk); 1220a6ca1094SYing Xue struct sk_buff *skb = NULL; 1221739f5e4eSJon Paul Maloy struct tipc_msg *msg; 1222301bae56SJon Paul Maloy u32 peer_port = tsk_peer_port(tsk); 1223301bae56SJon Paul Maloy u32 dnode = tsk_peer_node(tsk); 1224739f5e4eSJon Paul Maloy 1225301bae56SJon Paul Maloy if (!tsk->connected) 1226739f5e4eSJon Paul Maloy return; 1227c5898636SJon Paul Maloy skb = tipc_msg_create(CONN_MANAGER, CONN_ACK, INT_H_SIZE, 0, 1228c5898636SJon Paul Maloy dnode, tsk_own_node(tsk), peer_port, 1229c5898636SJon Paul Maloy tsk->portid, TIPC_OK); 1230a6ca1094SYing Xue if (!skb) 1231739f5e4eSJon Paul Maloy return; 1232a6ca1094SYing Xue msg = buf_msg(skb); 1233739f5e4eSJon Paul Maloy msg_set_msgcnt(msg, ack); 1234af9b028eSJon Paul Maloy tipc_node_xmit_skb(net, skb, dnode, msg_link_selector(msg)); 1235739f5e4eSJon Paul Maloy } 1236739f5e4eSJon Paul Maloy 123785d3fc94SArnaldo Carvalho de Melo static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) 12389bbb4eccSYing Xue { 12399bbb4eccSYing Xue struct sock *sk = sock->sk; 12409bbb4eccSYing Xue DEFINE_WAIT(wait); 124185d3fc94SArnaldo Carvalho de Melo long timeo = *timeop; 12429bbb4eccSYing Xue int err; 12439bbb4eccSYing Xue 12449bbb4eccSYing Xue for (;;) { 12459bbb4eccSYing Xue prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 1246fe8e4649SYing Xue if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { 12479bbb4eccSYing Xue if (sock->state == SS_DISCONNECTING) { 12489bbb4eccSYing Xue err = -ENOTCONN; 12499bbb4eccSYing Xue break; 12509bbb4eccSYing Xue } 12519bbb4eccSYing Xue release_sock(sk); 12529bbb4eccSYing Xue timeo = schedule_timeout(timeo); 12539bbb4eccSYing Xue lock_sock(sk); 12549bbb4eccSYing Xue } 12559bbb4eccSYing Xue err = 0; 12569bbb4eccSYing Xue if (!skb_queue_empty(&sk->sk_receive_queue)) 12579bbb4eccSYing Xue break; 12589bbb4eccSYing Xue err = -EAGAIN; 12599bbb4eccSYing Xue if (!timeo) 12609bbb4eccSYing Xue break; 1261143fe22fSErik Hugne err = sock_intr_errno(timeo); 1262143fe22fSErik Hugne if (signal_pending(current)) 1263143fe22fSErik Hugne break; 12649bbb4eccSYing Xue } 12659bbb4eccSYing Xue finish_wait(sk_sleep(sk), &wait); 126685d3fc94SArnaldo Carvalho de Melo *timeop = timeo; 12679bbb4eccSYing Xue return err; 12689bbb4eccSYing Xue } 12699bbb4eccSYing Xue 1270b97bf3fdSPer Liden /** 1271247f0f3cSYing Xue * tipc_recvmsg - receive packet-oriented message 1272b97bf3fdSPer Liden * @m: descriptor for message info 1273b97bf3fdSPer Liden * @buf_len: total size of user buffer area 1274b97bf3fdSPer Liden * @flags: receive flags 1275b97bf3fdSPer Liden * 1276b97bf3fdSPer Liden * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages. 1277b97bf3fdSPer Liden * If the complete message doesn't fit in user area, truncate it. 1278b97bf3fdSPer Liden * 1279b97bf3fdSPer Liden * Returns size of returned message data, errno otherwise 1280b97bf3fdSPer Liden */ 12811b784140SYing Xue static int tipc_recvmsg(struct socket *sock, struct msghdr *m, size_t buf_len, 12821b784140SYing Xue int flags) 1283b97bf3fdSPer Liden { 12840c3141e9SAllan Stephens struct sock *sk = sock->sk; 128558ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 1286b97bf3fdSPer Liden struct sk_buff *buf; 1287b97bf3fdSPer Liden struct tipc_msg *msg; 12889bbb4eccSYing Xue long timeo; 1289b97bf3fdSPer Liden unsigned int sz; 1290b97bf3fdSPer Liden u32 err; 1291b97bf3fdSPer Liden int res; 1292b97bf3fdSPer Liden 12930c3141e9SAllan Stephens /* Catch invalid receive requests */ 1294b97bf3fdSPer Liden if (unlikely(!buf_len)) 1295b97bf3fdSPer Liden return -EINVAL; 1296b97bf3fdSPer Liden 12970c3141e9SAllan Stephens lock_sock(sk); 1298b97bf3fdSPer Liden 12990c3141e9SAllan Stephens if (unlikely(sock->state == SS_UNCONNECTED)) { 1300b97bf3fdSPer Liden res = -ENOTCONN; 1301b97bf3fdSPer Liden goto exit; 1302b97bf3fdSPer Liden } 1303b97bf3fdSPer Liden 13049bbb4eccSYing Xue timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 13050c3141e9SAllan Stephens restart: 1306b97bf3fdSPer Liden 13070c3141e9SAllan Stephens /* Look for a message in receive queue; wait if necessary */ 130885d3fc94SArnaldo Carvalho de Melo res = tipc_wait_for_rcvmsg(sock, &timeo); 13099bbb4eccSYing Xue if (res) 13100c3141e9SAllan Stephens goto exit; 13110c3141e9SAllan Stephens 13120c3141e9SAllan Stephens /* Look at first message in receive queue */ 13130c3141e9SAllan Stephens buf = skb_peek(&sk->sk_receive_queue); 1314b97bf3fdSPer Liden msg = buf_msg(buf); 1315b97bf3fdSPer Liden sz = msg_data_sz(msg); 1316b97bf3fdSPer Liden err = msg_errcode(msg); 1317b97bf3fdSPer Liden 1318b97bf3fdSPer Liden /* Discard an empty non-errored message & try again */ 1319b97bf3fdSPer Liden if ((!sz) && (!err)) { 13202e84c60bSJon Paul Maloy tsk_advance_rx_queue(sk); 1321b97bf3fdSPer Liden goto restart; 1322b97bf3fdSPer Liden } 1323b97bf3fdSPer Liden 1324b97bf3fdSPer Liden /* Capture sender's address (optional) */ 1325b97bf3fdSPer Liden set_orig_addr(m, msg); 1326b97bf3fdSPer Liden 1327b97bf3fdSPer Liden /* Capture ancillary data (optional) */ 1328301bae56SJon Paul Maloy res = tipc_sk_anc_data_recv(m, msg, tsk); 13290c3141e9SAllan Stephens if (res) 1330b97bf3fdSPer Liden goto exit; 1331b97bf3fdSPer Liden 1332b97bf3fdSPer Liden /* Capture message data (if valid) & compute return value (always) */ 1333b97bf3fdSPer Liden if (!err) { 1334b97bf3fdSPer Liden if (unlikely(buf_len < sz)) { 1335b97bf3fdSPer Liden sz = buf_len; 1336b97bf3fdSPer Liden m->msg_flags |= MSG_TRUNC; 1337b97bf3fdSPer Liden } 133851f3d02bSDavid S. Miller res = skb_copy_datagram_msg(buf, msg_hdr_sz(msg), m, sz); 13390232fd0aSAllan Stephens if (res) 1340b97bf3fdSPer Liden goto exit; 1341b97bf3fdSPer Liden res = sz; 1342b97bf3fdSPer Liden } else { 1343b97bf3fdSPer Liden if ((sock->state == SS_READY) || 1344b97bf3fdSPer Liden ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)) 1345b97bf3fdSPer Liden res = 0; 1346b97bf3fdSPer Liden else 1347b97bf3fdSPer Liden res = -ECONNRESET; 1348b97bf3fdSPer Liden } 1349b97bf3fdSPer Liden 1350b97bf3fdSPer Liden /* Consume received message (optional) */ 1351b97bf3fdSPer Liden if (likely(!(flags & MSG_PEEK))) { 135299009806SAllan Stephens if ((sock->state != SS_READY) && 135360120526SJon Paul Maloy (++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) { 1354301bae56SJon Paul Maloy tipc_sk_send_ack(tsk, tsk->rcv_unacked); 135560120526SJon Paul Maloy tsk->rcv_unacked = 0; 135660120526SJon Paul Maloy } 13572e84c60bSJon Paul Maloy tsk_advance_rx_queue(sk); 1358b97bf3fdSPer Liden } 1359b97bf3fdSPer Liden exit: 13600c3141e9SAllan Stephens release_sock(sk); 1361b97bf3fdSPer Liden return res; 1362b97bf3fdSPer Liden } 1363b97bf3fdSPer Liden 1364b97bf3fdSPer Liden /** 1365247f0f3cSYing Xue * tipc_recv_stream - receive stream-oriented data 1366b97bf3fdSPer Liden * @m: descriptor for message info 1367b97bf3fdSPer Liden * @buf_len: total size of user buffer area 1368b97bf3fdSPer Liden * @flags: receive flags 1369b97bf3fdSPer Liden * 1370b97bf3fdSPer Liden * Used for SOCK_STREAM messages only. If not enough data is available 1371b97bf3fdSPer Liden * will optionally wait for more; never truncates data. 1372b97bf3fdSPer Liden * 1373b97bf3fdSPer Liden * Returns size of returned message data, errno otherwise 1374b97bf3fdSPer Liden */ 13751b784140SYing Xue static int tipc_recv_stream(struct socket *sock, struct msghdr *m, 13761b784140SYing Xue size_t buf_len, int flags) 1377b97bf3fdSPer Liden { 13780c3141e9SAllan Stephens struct sock *sk = sock->sk; 137958ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 1380b97bf3fdSPer Liden struct sk_buff *buf; 1381b97bf3fdSPer Liden struct tipc_msg *msg; 13829bbb4eccSYing Xue long timeo; 1383b97bf3fdSPer Liden unsigned int sz; 13843720d40bSFlorian Westphal int sz_to_copy, target, needed; 1385b97bf3fdSPer Liden int sz_copied = 0; 1386b97bf3fdSPer Liden u32 err; 13870c3141e9SAllan Stephens int res = 0; 1388b97bf3fdSPer Liden 1389b97bf3fdSPer Liden /* Catch invalid receive attempts */ 1390b97bf3fdSPer Liden if (unlikely(!buf_len)) 1391b97bf3fdSPer Liden return -EINVAL; 1392b97bf3fdSPer Liden 13930c3141e9SAllan Stephens lock_sock(sk); 1394b97bf3fdSPer Liden 13959bbb4eccSYing Xue if (unlikely(sock->state == SS_UNCONNECTED)) { 1396b97bf3fdSPer Liden res = -ENOTCONN; 1397b97bf3fdSPer Liden goto exit; 1398b97bf3fdSPer Liden } 1399b97bf3fdSPer Liden 14003720d40bSFlorian Westphal target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); 14019bbb4eccSYing Xue timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 1402617d3c7aSPaul Gortmaker 14030c3141e9SAllan Stephens restart: 14040c3141e9SAllan Stephens /* Look for a message in receive queue; wait if necessary */ 140585d3fc94SArnaldo Carvalho de Melo res = tipc_wait_for_rcvmsg(sock, &timeo); 14069bbb4eccSYing Xue if (res) 14070c3141e9SAllan Stephens goto exit; 14080c3141e9SAllan Stephens 14090c3141e9SAllan Stephens /* Look at first message in receive queue */ 14100c3141e9SAllan Stephens buf = skb_peek(&sk->sk_receive_queue); 1411b97bf3fdSPer Liden msg = buf_msg(buf); 1412b97bf3fdSPer Liden sz = msg_data_sz(msg); 1413b97bf3fdSPer Liden err = msg_errcode(msg); 1414b97bf3fdSPer Liden 1415b97bf3fdSPer Liden /* Discard an empty non-errored message & try again */ 1416b97bf3fdSPer Liden if ((!sz) && (!err)) { 14172e84c60bSJon Paul Maloy tsk_advance_rx_queue(sk); 1418b97bf3fdSPer Liden goto restart; 1419b97bf3fdSPer Liden } 1420b97bf3fdSPer Liden 1421b97bf3fdSPer Liden /* Optionally capture sender's address & ancillary data of first msg */ 1422b97bf3fdSPer Liden if (sz_copied == 0) { 1423b97bf3fdSPer Liden set_orig_addr(m, msg); 1424301bae56SJon Paul Maloy res = tipc_sk_anc_data_recv(m, msg, tsk); 14250c3141e9SAllan Stephens if (res) 1426b97bf3fdSPer Liden goto exit; 1427b97bf3fdSPer Liden } 1428b97bf3fdSPer Liden 1429b97bf3fdSPer Liden /* Capture message data (if valid) & compute return value (always) */ 1430b97bf3fdSPer Liden if (!err) { 14310232fd0aSAllan Stephens u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle); 1432b97bf3fdSPer Liden 14330232fd0aSAllan Stephens sz -= offset; 1434b97bf3fdSPer Liden needed = (buf_len - sz_copied); 1435b97bf3fdSPer Liden sz_to_copy = (sz <= needed) ? sz : needed; 14360232fd0aSAllan Stephens 143751f3d02bSDavid S. Miller res = skb_copy_datagram_msg(buf, msg_hdr_sz(msg) + offset, 143851f3d02bSDavid S. Miller m, sz_to_copy); 14390232fd0aSAllan Stephens if (res) 1440b97bf3fdSPer Liden goto exit; 14410232fd0aSAllan Stephens 1442b97bf3fdSPer Liden sz_copied += sz_to_copy; 1443b97bf3fdSPer Liden 1444b97bf3fdSPer Liden if (sz_to_copy < sz) { 1445b97bf3fdSPer Liden if (!(flags & MSG_PEEK)) 14460232fd0aSAllan Stephens TIPC_SKB_CB(buf)->handle = 14470232fd0aSAllan Stephens (void *)(unsigned long)(offset + sz_to_copy); 1448b97bf3fdSPer Liden goto exit; 1449b97bf3fdSPer Liden } 1450b97bf3fdSPer Liden } else { 1451b97bf3fdSPer Liden if (sz_copied != 0) 1452b97bf3fdSPer Liden goto exit; /* can't add error msg to valid data */ 1453b97bf3fdSPer Liden 1454b97bf3fdSPer Liden if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) 1455b97bf3fdSPer Liden res = 0; 1456b97bf3fdSPer Liden else 1457b97bf3fdSPer Liden res = -ECONNRESET; 1458b97bf3fdSPer Liden } 1459b97bf3fdSPer Liden 1460b97bf3fdSPer Liden /* Consume received message (optional) */ 1461b97bf3fdSPer Liden if (likely(!(flags & MSG_PEEK))) { 146260120526SJon Paul Maloy if (unlikely(++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) { 1463301bae56SJon Paul Maloy tipc_sk_send_ack(tsk, tsk->rcv_unacked); 146460120526SJon Paul Maloy tsk->rcv_unacked = 0; 146560120526SJon Paul Maloy } 14662e84c60bSJon Paul Maloy tsk_advance_rx_queue(sk); 1467b97bf3fdSPer Liden } 1468b97bf3fdSPer Liden 1469b97bf3fdSPer Liden /* Loop around if more data is required */ 1470f64f9e71SJoe Perches if ((sz_copied < buf_len) && /* didn't get all requested data */ 1471f64f9e71SJoe Perches (!skb_queue_empty(&sk->sk_receive_queue) || 14723720d40bSFlorian Westphal (sz_copied < target)) && /* and more is ready or required */ 1473f64f9e71SJoe Perches (!(flags & MSG_PEEK)) && /* and aren't just peeking at data */ 1474f64f9e71SJoe Perches (!err)) /* and haven't reached a FIN */ 1475b97bf3fdSPer Liden goto restart; 1476b97bf3fdSPer Liden 1477b97bf3fdSPer Liden exit: 14780c3141e9SAllan Stephens release_sock(sk); 1479a3b0a5a9SAllan Stephens return sz_copied ? sz_copied : res; 1480b97bf3fdSPer Liden } 1481b97bf3fdSPer Liden 1482b97bf3fdSPer Liden /** 1483f288bef4SYing Xue * tipc_write_space - wake up thread if port congestion is released 1484f288bef4SYing Xue * @sk: socket 1485f288bef4SYing Xue */ 1486f288bef4SYing Xue static void tipc_write_space(struct sock *sk) 1487f288bef4SYing Xue { 1488f288bef4SYing Xue struct socket_wq *wq; 1489f288bef4SYing Xue 1490f288bef4SYing Xue rcu_read_lock(); 1491f288bef4SYing Xue wq = rcu_dereference(sk->sk_wq); 14921ce0bf50SHerbert Xu if (skwq_has_sleeper(wq)) 1493f288bef4SYing Xue wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | 1494f288bef4SYing Xue POLLWRNORM | POLLWRBAND); 1495f288bef4SYing Xue rcu_read_unlock(); 1496f288bef4SYing Xue } 1497f288bef4SYing Xue 1498f288bef4SYing Xue /** 1499f288bef4SYing Xue * tipc_data_ready - wake up threads to indicate messages have been received 1500f288bef4SYing Xue * @sk: socket 1501f288bef4SYing Xue * @len: the length of messages 1502f288bef4SYing Xue */ 1503676d2369SDavid S. Miller static void tipc_data_ready(struct sock *sk) 1504f288bef4SYing Xue { 1505f288bef4SYing Xue struct socket_wq *wq; 1506f288bef4SYing Xue 1507f288bef4SYing Xue rcu_read_lock(); 1508f288bef4SYing Xue wq = rcu_dereference(sk->sk_wq); 15091ce0bf50SHerbert Xu if (skwq_has_sleeper(wq)) 1510f288bef4SYing Xue wake_up_interruptible_sync_poll(&wq->wait, POLLIN | 1511f288bef4SYing Xue POLLRDNORM | POLLRDBAND); 1512f288bef4SYing Xue rcu_read_unlock(); 1513f288bef4SYing Xue } 1514f288bef4SYing Xue 1515f4195d1eSYing Xue static void tipc_sock_destruct(struct sock *sk) 1516f4195d1eSYing Xue { 1517f4195d1eSYing Xue __skb_queue_purge(&sk->sk_receive_queue); 1518f4195d1eSYing Xue } 1519f4195d1eSYing Xue 1520f288bef4SYing Xue /** 15217e6c131eSYing Xue * filter_connect - Handle all incoming messages for a connection-based socket 152258ed9442SJon Paul Maloy * @tsk: TIPC socket 15231186adf7SJon Paul Maloy * @skb: pointer to message buffer. Set to NULL if buffer is consumed 15247e6c131eSYing Xue * 1525cda3696dSJon Paul Maloy * Returns true if everything ok, false otherwise 15267e6c131eSYing Xue */ 1527cda3696dSJon Paul Maloy static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) 15287e6c131eSYing Xue { 152958ed9442SJon Paul Maloy struct sock *sk = &tsk->sk; 1530f2f9800dSYing Xue struct net *net = sock_net(sk); 15318826cde6SJon Paul Maloy struct socket *sock = sk->sk_socket; 1532cda3696dSJon Paul Maloy struct tipc_msg *hdr = buf_msg(skb); 15337e6c131eSYing Xue 1534cda3696dSJon Paul Maloy if (unlikely(msg_mcast(hdr))) 1535cda3696dSJon Paul Maloy return false; 15367e6c131eSYing Xue 15377e6c131eSYing Xue switch ((int)sock->state) { 15387e6c131eSYing Xue case SS_CONNECTED: 1539cda3696dSJon Paul Maloy 15407e6c131eSYing Xue /* Accept only connection-based messages sent by peer */ 1541cda3696dSJon Paul Maloy if (unlikely(!tsk_peer_msg(tsk, hdr))) 1542cda3696dSJon Paul Maloy return false; 1543cda3696dSJon Paul Maloy 1544cda3696dSJon Paul Maloy if (unlikely(msg_errcode(hdr))) { 15457e6c131eSYing Xue sock->state = SS_DISCONNECTING; 1546301bae56SJon Paul Maloy tsk->connected = 0; 1547cda3696dSJon Paul Maloy /* Let timer expire on it's own */ 1548f2f9800dSYing Xue tipc_node_remove_conn(net, tsk_peer_node(tsk), 154907f6c4bcSYing Xue tsk->portid); 15507e6c131eSYing Xue } 1551cda3696dSJon Paul Maloy return true; 1552cda3696dSJon Paul Maloy 15537e6c131eSYing Xue case SS_CONNECTING: 1554cda3696dSJon Paul Maloy 15557e6c131eSYing Xue /* Accept only ACK or NACK message */ 1556cda3696dSJon Paul Maloy if (unlikely(!msg_connected(hdr))) 1557cda3696dSJon Paul Maloy return false; 1558dadebc00SJon Paul Maloy 1559cda3696dSJon Paul Maloy if (unlikely(msg_errcode(hdr))) { 1560584d24b3SYing Xue sock->state = SS_DISCONNECTING; 15612c8d8518SErik Hugne sk->sk_err = ECONNREFUSED; 1562cda3696dSJon Paul Maloy return true; 1563584d24b3SYing Xue } 1564584d24b3SYing Xue 1565cda3696dSJon Paul Maloy if (unlikely(!msg_isdata(hdr))) { 1566584d24b3SYing Xue sock->state = SS_DISCONNECTING; 1567dadebc00SJon Paul Maloy sk->sk_err = EINVAL; 1568cda3696dSJon Paul Maloy return true; 1569584d24b3SYing Xue } 1570584d24b3SYing Xue 1571cda3696dSJon Paul Maloy tipc_sk_finish_conn(tsk, msg_origport(hdr), msg_orignode(hdr)); 1572cda3696dSJon Paul Maloy msg_set_importance(&tsk->phdr, msg_importance(hdr)); 1573dadebc00SJon Paul Maloy sock->state = SS_CONNECTED; 1574dadebc00SJon Paul Maloy 1575cda3696dSJon Paul Maloy /* If 'ACK+' message, add to socket receive queue */ 1576cda3696dSJon Paul Maloy if (msg_data_sz(hdr)) 1577cda3696dSJon Paul Maloy return true; 1578cda3696dSJon Paul Maloy 1579cda3696dSJon Paul Maloy /* If empty 'ACK-' message, wake up sleeping connect() */ 1580584d24b3SYing Xue if (waitqueue_active(sk_sleep(sk))) 1581584d24b3SYing Xue wake_up_interruptible(sk_sleep(sk)); 1582cda3696dSJon Paul Maloy 1583cda3696dSJon Paul Maloy /* 'ACK-' message is neither accepted nor rejected: */ 1584cda3696dSJon Paul Maloy msg_set_dest_droppable(hdr, 1); 1585cda3696dSJon Paul Maloy return false; 1586cda3696dSJon Paul Maloy 15877e6c131eSYing Xue case SS_LISTENING: 15887e6c131eSYing Xue case SS_UNCONNECTED: 1589cda3696dSJon Paul Maloy 15907e6c131eSYing Xue /* Accept only SYN message */ 1591cda3696dSJon Paul Maloy if (!msg_connected(hdr) && !(msg_errcode(hdr))) 1592cda3696dSJon Paul Maloy return true; 15937e6c131eSYing Xue break; 15947e6c131eSYing Xue case SS_DISCONNECTING: 15957e6c131eSYing Xue break; 15967e6c131eSYing Xue default: 15977e6c131eSYing Xue pr_err("Unknown socket state %u\n", sock->state); 15987e6c131eSYing Xue } 1599cda3696dSJon Paul Maloy return false; 16007e6c131eSYing Xue } 16017e6c131eSYing Xue 16027e6c131eSYing Xue /** 1603aba79f33SYing Xue * rcvbuf_limit - get proper overload limit of socket receive queue 1604aba79f33SYing Xue * @sk: socket 1605aba79f33SYing Xue * @buf: message 1606aba79f33SYing Xue * 1607aba79f33SYing Xue * For all connection oriented messages, irrespective of importance, 1608aba79f33SYing Xue * the default overload value (i.e. 67MB) is set as limit. 1609aba79f33SYing Xue * 1610aba79f33SYing Xue * For all connectionless messages, by default new queue limits are 1611aba79f33SYing Xue * as belows: 1612aba79f33SYing Xue * 1613cc79dd1bSYing Xue * TIPC_LOW_IMPORTANCE (4 MB) 1614cc79dd1bSYing Xue * TIPC_MEDIUM_IMPORTANCE (8 MB) 1615cc79dd1bSYing Xue * TIPC_HIGH_IMPORTANCE (16 MB) 1616cc79dd1bSYing Xue * TIPC_CRITICAL_IMPORTANCE (32 MB) 1617aba79f33SYing Xue * 1618aba79f33SYing Xue * Returns overload limit according to corresponding message importance 1619aba79f33SYing Xue */ 1620aba79f33SYing Xue static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) 1621aba79f33SYing Xue { 1622aba79f33SYing Xue struct tipc_msg *msg = buf_msg(buf); 1623aba79f33SYing Xue 1624aba79f33SYing Xue if (msg_connected(msg)) 16250cee6bbeSwangweidong return sysctl_tipc_rmem[2]; 16260cee6bbeSwangweidong 16270cee6bbeSwangweidong return sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << 1628cc79dd1bSYing Xue msg_importance(msg); 1629aba79f33SYing Xue } 1630aba79f33SYing Xue 1631aba79f33SYing Xue /** 16320c3141e9SAllan Stephens * filter_rcv - validate incoming message 16330c3141e9SAllan Stephens * @sk: socket 1634cda3696dSJon Paul Maloy * @skb: pointer to message. 1635b97bf3fdSPer Liden * 16360c3141e9SAllan Stephens * Enqueues message on receive queue if acceptable; optionally handles 16370c3141e9SAllan Stephens * disconnect indication for a connected socket. 16380c3141e9SAllan Stephens * 16391186adf7SJon Paul Maloy * Called with socket lock already taken 1640b97bf3fdSPer Liden * 1641cda3696dSJon Paul Maloy * Returns true if message was added to socket receive queue, otherwise false 1642b97bf3fdSPer Liden */ 1643cda3696dSJon Paul Maloy static bool filter_rcv(struct sock *sk, struct sk_buff *skb) 1644b97bf3fdSPer Liden { 16450c3141e9SAllan Stephens struct socket *sock = sk->sk_socket; 164658ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 1647cda3696dSJon Paul Maloy struct tipc_msg *hdr = buf_msg(skb); 1648cda3696dSJon Paul Maloy unsigned int limit = rcvbuf_limit(sk, skb); 1649cda3696dSJon Paul Maloy int err = TIPC_OK; 1650cda3696dSJon Paul Maloy int usr = msg_user(hdr); 1651b97bf3fdSPer Liden 1652cda3696dSJon Paul Maloy if (unlikely(msg_user(hdr) == CONN_MANAGER)) { 1653cda3696dSJon Paul Maloy tipc_sk_proto_rcv(tsk, skb); 1654cda3696dSJon Paul Maloy return false; 16551186adf7SJon Paul Maloy } 1656ec8a2e56SJon Paul Maloy 1657cda3696dSJon Paul Maloy if (unlikely(usr == SOCK_WAKEUP)) { 1658cda3696dSJon Paul Maloy kfree_skb(skb); 165950100a5eSJon Paul Maloy tsk->link_cong = 0; 166050100a5eSJon Paul Maloy sk->sk_write_space(sk); 1661cda3696dSJon Paul Maloy return false; 166250100a5eSJon Paul Maloy } 166350100a5eSJon Paul Maloy 1664cda3696dSJon Paul Maloy /* Drop if illegal message type */ 1665cda3696dSJon Paul Maloy if (unlikely(msg_type(hdr) > TIPC_DIRECT_MSG)) { 1666cda3696dSJon Paul Maloy kfree_skb(skb); 1667cda3696dSJon Paul Maloy return false; 1668cda3696dSJon Paul Maloy } 16690c3141e9SAllan Stephens 1670cda3696dSJon Paul Maloy /* Reject if wrong message type for current socket state */ 1671cda3696dSJon Paul Maloy if (unlikely(sock->state == SS_READY)) { 1672cda3696dSJon Paul Maloy if (msg_connected(hdr)) { 1673cda3696dSJon Paul Maloy err = TIPC_ERR_NO_PORT; 1674cda3696dSJon Paul Maloy goto reject; 1675cda3696dSJon Paul Maloy } 1676cda3696dSJon Paul Maloy } else if (unlikely(!filter_connect(tsk, skb))) { 1677cda3696dSJon Paul Maloy err = TIPC_ERR_NO_PORT; 1678cda3696dSJon Paul Maloy goto reject; 1679b97bf3fdSPer Liden } 1680b97bf3fdSPer Liden 1681b97bf3fdSPer Liden /* Reject message if there isn't room to queue it */ 1682cda3696dSJon Paul Maloy if (unlikely(sk_rmem_alloc_get(sk) + skb->truesize >= limit)) { 1683cda3696dSJon Paul Maloy err = TIPC_ERR_OVERLOAD; 1684cda3696dSJon Paul Maloy goto reject; 1685cda3696dSJon Paul Maloy } 1686b97bf3fdSPer Liden 1687aba79f33SYing Xue /* Enqueue message */ 1688cda3696dSJon Paul Maloy TIPC_SKB_CB(skb)->handle = NULL; 1689cda3696dSJon Paul Maloy __skb_queue_tail(&sk->sk_receive_queue, skb); 1690cda3696dSJon Paul Maloy skb_set_owner_r(skb, sk); 1691b97bf3fdSPer Liden 1692676d2369SDavid S. Miller sk->sk_data_ready(sk); 1693cda3696dSJon Paul Maloy return true; 1694cda3696dSJon Paul Maloy 1695cda3696dSJon Paul Maloy reject: 1696cda3696dSJon Paul Maloy tipc_sk_respond(sk, skb, err); 1697cda3696dSJon Paul Maloy return false; 1698b97bf3fdSPer Liden } 1699b97bf3fdSPer Liden 1700b97bf3fdSPer Liden /** 17014f4482dcSJon Paul Maloy * tipc_backlog_rcv - handle incoming message from backlog queue 17020c3141e9SAllan Stephens * @sk: socket 1703a6ca1094SYing Xue * @skb: message 17040c3141e9SAllan Stephens * 1705e3a77561SJon Paul Maloy * Caller must hold socket lock 17060c3141e9SAllan Stephens * 17070c3141e9SAllan Stephens * Returns 0 17080c3141e9SAllan Stephens */ 1709a6ca1094SYing Xue static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) 17100c3141e9SAllan Stephens { 1711cda3696dSJon Paul Maloy unsigned int truesize = skb->truesize; 17120c3141e9SAllan Stephens 1713cda3696dSJon Paul Maloy if (likely(filter_rcv(sk, skb))) 1714cda3696dSJon Paul Maloy atomic_add(truesize, &tipc_sk(sk)->dupl_rcvcnt); 17150c3141e9SAllan Stephens return 0; 17160c3141e9SAllan Stephens } 17170c3141e9SAllan Stephens 17180c3141e9SAllan Stephens /** 1719c637c103SJon Paul Maloy * tipc_sk_enqueue - extract all buffers with destination 'dport' from 1720c637c103SJon Paul Maloy * inputq and try adding them to socket or backlog queue 1721c637c103SJon Paul Maloy * @inputq: list of incoming buffers with potentially different destinations 1722c637c103SJon Paul Maloy * @sk: socket where the buffers should be enqueued 1723c637c103SJon Paul Maloy * @dport: port number for the socket 1724d570d864SJon Paul Maloy * 1725d570d864SJon Paul Maloy * Caller must hold socket lock 1726d570d864SJon Paul Maloy */ 1727cda3696dSJon Paul Maloy static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, 1728cda3696dSJon Paul Maloy u32 dport) 1729d570d864SJon Paul Maloy { 1730d570d864SJon Paul Maloy unsigned int lim; 1731d570d864SJon Paul Maloy atomic_t *dcnt; 1732c637c103SJon Paul Maloy struct sk_buff *skb; 1733c637c103SJon Paul Maloy unsigned long time_limit = jiffies + 2; 1734d570d864SJon Paul Maloy 1735c637c103SJon Paul Maloy while (skb_queue_len(inputq)) { 173651a00dafSJon Paul Maloy if (unlikely(time_after_eq(jiffies, time_limit))) 1737cda3696dSJon Paul Maloy return; 1738cda3696dSJon Paul Maloy 1739c637c103SJon Paul Maloy skb = tipc_skb_dequeue(inputq, dport); 1740c637c103SJon Paul Maloy if (unlikely(!skb)) 1741cda3696dSJon Paul Maloy return; 1742cda3696dSJon Paul Maloy 1743cda3696dSJon Paul Maloy /* Add message directly to receive queue if possible */ 1744c637c103SJon Paul Maloy if (!sock_owned_by_user(sk)) { 1745cda3696dSJon Paul Maloy filter_rcv(sk, skb); 1746c637c103SJon Paul Maloy continue; 1747c637c103SJon Paul Maloy } 1748cda3696dSJon Paul Maloy 1749cda3696dSJon Paul Maloy /* Try backlog, compensating for double-counted bytes */ 1750d570d864SJon Paul Maloy dcnt = &tipc_sk(sk)->dupl_rcvcnt; 1751d570d864SJon Paul Maloy if (sk->sk_backlog.len) 1752d570d864SJon Paul Maloy atomic_set(dcnt, 0); 1753c637c103SJon Paul Maloy lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt); 1754c637c103SJon Paul Maloy if (likely(!sk_add_backlog(sk, skb, lim))) 1755c637c103SJon Paul Maloy continue; 1756cda3696dSJon Paul Maloy 1757cda3696dSJon Paul Maloy /* Overload => reject message back to sender */ 1758cda3696dSJon Paul Maloy tipc_sk_respond(sk, skb, TIPC_ERR_OVERLOAD); 1759cda3696dSJon Paul Maloy break; 1760c637c103SJon Paul Maloy } 1761d570d864SJon Paul Maloy } 1762d570d864SJon Paul Maloy 1763d570d864SJon Paul Maloy /** 1764c637c103SJon Paul Maloy * tipc_sk_rcv - handle a chain of incoming buffers 1765c637c103SJon Paul Maloy * @inputq: buffer list containing the buffers 1766c637c103SJon Paul Maloy * Consumes all buffers in list until inputq is empty 1767c637c103SJon Paul Maloy * Note: may be called in multiple threads referring to the same queue 17680c3141e9SAllan Stephens */ 1769cda3696dSJon Paul Maloy void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) 17700c3141e9SAllan Stephens { 1771c637c103SJon Paul Maloy u32 dnode, dport = 0; 17729871b27fSErik Hugne int err; 17739816f061SJon Paul Maloy struct tipc_sock *tsk; 17749816f061SJon Paul Maloy struct sock *sk; 1775cda3696dSJon Paul Maloy struct sk_buff *skb; 17769816f061SJon Paul Maloy 1777c637c103SJon Paul Maloy while (skb_queue_len(inputq)) { 1778c637c103SJon Paul Maloy dport = tipc_skb_peek_port(inputq, dport); 1779e05b31f4SYing Xue tsk = tipc_sk_lookup(net, dport); 1780cda3696dSJon Paul Maloy 1781e3a77561SJon Paul Maloy if (likely(tsk)) { 17829816f061SJon Paul Maloy sk = &tsk->sk; 1783c637c103SJon Paul Maloy if (likely(spin_trylock_bh(&sk->sk_lock.slock))) { 1784cda3696dSJon Paul Maloy tipc_sk_enqueue(inputq, sk, dport); 17851a194c2dSYing Xue spin_unlock_bh(&sk->sk_lock.slock); 1786c637c103SJon Paul Maloy } 178707f6c4bcSYing Xue sock_put(sk); 1788c637c103SJon Paul Maloy continue; 1789e3a77561SJon Paul Maloy } 1790cda3696dSJon Paul Maloy 1791cda3696dSJon Paul Maloy /* No destination socket => dequeue skb if still there */ 1792cda3696dSJon Paul Maloy skb = tipc_skb_dequeue(inputq, dport); 1793cda3696dSJon Paul Maloy if (!skb) 1794cda3696dSJon Paul Maloy return; 1795cda3696dSJon Paul Maloy 1796cda3696dSJon Paul Maloy /* Try secondary lookup if unresolved named message */ 1797cda3696dSJon Paul Maloy err = TIPC_ERR_NO_PORT; 1798cda3696dSJon Paul Maloy if (tipc_msg_lookup_dest(net, skb, &err)) 1799cda3696dSJon Paul Maloy goto xmit; 1800cda3696dSJon Paul Maloy 1801cda3696dSJon Paul Maloy /* Prepare for message rejection */ 1802cda3696dSJon Paul Maloy if (!tipc_msg_reverse(tipc_own_addr(net), &skb, err)) 1803c637c103SJon Paul Maloy continue; 1804e3a77561SJon Paul Maloy xmit: 1805cda3696dSJon Paul Maloy dnode = msg_destnode(buf_msg(skb)); 1806af9b028eSJon Paul Maloy tipc_node_xmit_skb(net, skb, dnode, dport); 1807c637c103SJon Paul Maloy } 18080c3141e9SAllan Stephens } 18090c3141e9SAllan Stephens 181078eb3a53SYing Xue static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) 181178eb3a53SYing Xue { 181278eb3a53SYing Xue struct sock *sk = sock->sk; 181378eb3a53SYing Xue DEFINE_WAIT(wait); 181478eb3a53SYing Xue int done; 181578eb3a53SYing Xue 181678eb3a53SYing Xue do { 181778eb3a53SYing Xue int err = sock_error(sk); 181878eb3a53SYing Xue if (err) 181978eb3a53SYing Xue return err; 182078eb3a53SYing Xue if (!*timeo_p) 182178eb3a53SYing Xue return -ETIMEDOUT; 182278eb3a53SYing Xue if (signal_pending(current)) 182378eb3a53SYing Xue return sock_intr_errno(*timeo_p); 182478eb3a53SYing Xue 182578eb3a53SYing Xue prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 182678eb3a53SYing Xue done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING); 182778eb3a53SYing Xue finish_wait(sk_sleep(sk), &wait); 182878eb3a53SYing Xue } while (!done); 182978eb3a53SYing Xue return 0; 183078eb3a53SYing Xue } 183178eb3a53SYing Xue 1832b97bf3fdSPer Liden /** 1833247f0f3cSYing Xue * tipc_connect - establish a connection to another TIPC port 1834b97bf3fdSPer Liden * @sock: socket structure 1835b97bf3fdSPer Liden * @dest: socket address for destination port 1836b97bf3fdSPer Liden * @destlen: size of socket address data structure 18370c3141e9SAllan Stephens * @flags: file-related flags associated with socket 1838b97bf3fdSPer Liden * 1839b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 1840b97bf3fdSPer Liden */ 1841247f0f3cSYing Xue static int tipc_connect(struct socket *sock, struct sockaddr *dest, 1842247f0f3cSYing Xue int destlen, int flags) 1843b97bf3fdSPer Liden { 18440c3141e9SAllan Stephens struct sock *sk = sock->sk; 1845f2f8036eSErik Hugne struct tipc_sock *tsk = tipc_sk(sk); 1846b97bf3fdSPer Liden struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; 18471fc54d8fSSam Ravnborg struct msghdr m = {NULL,}; 1848f2f8036eSErik Hugne long timeout = (flags & O_NONBLOCK) ? 0 : tsk->conn_timeout; 184978eb3a53SYing Xue socket_state previous; 1850f2f8036eSErik Hugne int res = 0; 1851b97bf3fdSPer Liden 18520c3141e9SAllan Stephens lock_sock(sk); 18530c3141e9SAllan Stephens 1854f2f8036eSErik Hugne /* DGRAM/RDM connect(), just save the destaddr */ 18550c3141e9SAllan Stephens if (sock->state == SS_READY) { 1856f2f8036eSErik Hugne if (dst->family == AF_UNSPEC) { 1857f2f8036eSErik Hugne memset(&tsk->remote, 0, sizeof(struct sockaddr_tipc)); 1858f2f8036eSErik Hugne tsk->connected = 0; 1859610600c8SSasha Levin } else if (destlen != sizeof(struct sockaddr_tipc)) { 1860610600c8SSasha Levin res = -EINVAL; 1861f2f8036eSErik Hugne } else { 1862f2f8036eSErik Hugne memcpy(&tsk->remote, dest, destlen); 1863f2f8036eSErik Hugne tsk->connected = 1; 1864f2f8036eSErik Hugne } 18650c3141e9SAllan Stephens goto exit; 18660c3141e9SAllan Stephens } 1867b97bf3fdSPer Liden 186851f9cc1fSAllan Stephens /* 186951f9cc1fSAllan Stephens * Reject connection attempt using multicast address 187051f9cc1fSAllan Stephens * 187151f9cc1fSAllan Stephens * Note: send_msg() validates the rest of the address fields, 187251f9cc1fSAllan Stephens * so there's no need to do it here 187351f9cc1fSAllan Stephens */ 18740c3141e9SAllan Stephens if (dst->addrtype == TIPC_ADDR_MCAST) { 18750c3141e9SAllan Stephens res = -EINVAL; 18760c3141e9SAllan Stephens goto exit; 18770c3141e9SAllan Stephens } 18780c3141e9SAllan Stephens 187978eb3a53SYing Xue previous = sock->state; 1880584d24b3SYing Xue switch (sock->state) { 1881584d24b3SYing Xue case SS_UNCONNECTED: 1882b97bf3fdSPer Liden /* Send a 'SYN-' to destination */ 1883b97bf3fdSPer Liden m.msg_name = dest; 188451f9cc1fSAllan Stephens m.msg_namelen = destlen; 1885584d24b3SYing Xue 1886584d24b3SYing Xue /* If connect is in non-blocking case, set MSG_DONTWAIT to 1887584d24b3SYing Xue * indicate send_msg() is never blocked. 1888584d24b3SYing Xue */ 1889584d24b3SYing Xue if (!timeout) 1890584d24b3SYing Xue m.msg_flags = MSG_DONTWAIT; 1891584d24b3SYing Xue 189239a0295fSYing Xue res = __tipc_sendmsg(sock, &m, 0); 1893584d24b3SYing Xue if ((res < 0) && (res != -EWOULDBLOCK)) 1894584d24b3SYing Xue goto exit; 1895584d24b3SYing Xue 1896584d24b3SYing Xue /* Just entered SS_CONNECTING state; the only 1897584d24b3SYing Xue * difference is that return value in non-blocking 1898584d24b3SYing Xue * case is EINPROGRESS, rather than EALREADY. 1899584d24b3SYing Xue */ 1900584d24b3SYing Xue res = -EINPROGRESS; 1901584d24b3SYing Xue case SS_CONNECTING: 190278eb3a53SYing Xue if (previous == SS_CONNECTING) 1903584d24b3SYing Xue res = -EALREADY; 190478eb3a53SYing Xue if (!timeout) 190578eb3a53SYing Xue goto exit; 190678eb3a53SYing Xue timeout = msecs_to_jiffies(timeout); 190778eb3a53SYing Xue /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ 190878eb3a53SYing Xue res = tipc_wait_for_connect(sock, &timeout); 1909584d24b3SYing Xue break; 1910584d24b3SYing Xue case SS_CONNECTED: 1911584d24b3SYing Xue res = -EISCONN; 1912584d24b3SYing Xue break; 1913584d24b3SYing Xue default: 1914584d24b3SYing Xue res = -EINVAL; 191578eb3a53SYing Xue break; 1916584d24b3SYing Xue } 19170c3141e9SAllan Stephens exit: 19180c3141e9SAllan Stephens release_sock(sk); 1919b97bf3fdSPer Liden return res; 1920b97bf3fdSPer Liden } 1921b97bf3fdSPer Liden 1922b97bf3fdSPer Liden /** 1923247f0f3cSYing Xue * tipc_listen - allow socket to listen for incoming connections 1924b97bf3fdSPer Liden * @sock: socket structure 1925b97bf3fdSPer Liden * @len: (unused) 1926b97bf3fdSPer Liden * 1927b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 1928b97bf3fdSPer Liden */ 1929247f0f3cSYing Xue static int tipc_listen(struct socket *sock, int len) 1930b97bf3fdSPer Liden { 19310c3141e9SAllan Stephens struct sock *sk = sock->sk; 19320c3141e9SAllan Stephens int res; 19330c3141e9SAllan Stephens 19340c3141e9SAllan Stephens lock_sock(sk); 1935b97bf3fdSPer Liden 1936245f3d34SYing Xue if (sock->state != SS_UNCONNECTED) 19370c3141e9SAllan Stephens res = -EINVAL; 19380c3141e9SAllan Stephens else { 1939b97bf3fdSPer Liden sock->state = SS_LISTENING; 19400c3141e9SAllan Stephens res = 0; 19410c3141e9SAllan Stephens } 19420c3141e9SAllan Stephens 19430c3141e9SAllan Stephens release_sock(sk); 19440c3141e9SAllan Stephens return res; 1945b97bf3fdSPer Liden } 1946b97bf3fdSPer Liden 19476398e23cSYing Xue static int tipc_wait_for_accept(struct socket *sock, long timeo) 19486398e23cSYing Xue { 19496398e23cSYing Xue struct sock *sk = sock->sk; 19506398e23cSYing Xue DEFINE_WAIT(wait); 19516398e23cSYing Xue int err; 19526398e23cSYing Xue 19536398e23cSYing Xue /* True wake-one mechanism for incoming connections: only 19546398e23cSYing Xue * one process gets woken up, not the 'whole herd'. 19556398e23cSYing Xue * Since we do not 'race & poll' for established sockets 19566398e23cSYing Xue * anymore, the common case will execute the loop only once. 19576398e23cSYing Xue */ 19586398e23cSYing Xue for (;;) { 19596398e23cSYing Xue prepare_to_wait_exclusive(sk_sleep(sk), &wait, 19606398e23cSYing Xue TASK_INTERRUPTIBLE); 1961fe8e4649SYing Xue if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { 19626398e23cSYing Xue release_sock(sk); 19636398e23cSYing Xue timeo = schedule_timeout(timeo); 19646398e23cSYing Xue lock_sock(sk); 19656398e23cSYing Xue } 19666398e23cSYing Xue err = 0; 19676398e23cSYing Xue if (!skb_queue_empty(&sk->sk_receive_queue)) 19686398e23cSYing Xue break; 19696398e23cSYing Xue err = -EINVAL; 19706398e23cSYing Xue if (sock->state != SS_LISTENING) 19716398e23cSYing Xue break; 19726398e23cSYing Xue err = -EAGAIN; 19736398e23cSYing Xue if (!timeo) 19746398e23cSYing Xue break; 1975143fe22fSErik Hugne err = sock_intr_errno(timeo); 1976143fe22fSErik Hugne if (signal_pending(current)) 1977143fe22fSErik Hugne break; 19786398e23cSYing Xue } 19796398e23cSYing Xue finish_wait(sk_sleep(sk), &wait); 19806398e23cSYing Xue return err; 19816398e23cSYing Xue } 19826398e23cSYing Xue 1983b97bf3fdSPer Liden /** 1984247f0f3cSYing Xue * tipc_accept - wait for connection request 1985b97bf3fdSPer Liden * @sock: listening socket 1986b97bf3fdSPer Liden * @newsock: new socket that is to be connected 1987b97bf3fdSPer Liden * @flags: file-related flags associated with socket 1988b97bf3fdSPer Liden * 1989b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 1990b97bf3fdSPer Liden */ 1991247f0f3cSYing Xue static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) 1992b97bf3fdSPer Liden { 19930fef8f20SPaul Gortmaker struct sock *new_sk, *sk = sock->sk; 1994b97bf3fdSPer Liden struct sk_buff *buf; 1995301bae56SJon Paul Maloy struct tipc_sock *new_tsock; 19960fef8f20SPaul Gortmaker struct tipc_msg *msg; 19976398e23cSYing Xue long timeo; 19980c3141e9SAllan Stephens int res; 1999b97bf3fdSPer Liden 20000c3141e9SAllan Stephens lock_sock(sk); 2001b97bf3fdSPer Liden 20020c3141e9SAllan Stephens if (sock->state != SS_LISTENING) { 20030c3141e9SAllan Stephens res = -EINVAL; 20040c3141e9SAllan Stephens goto exit; 20050c3141e9SAllan Stephens } 20066398e23cSYing Xue timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 20076398e23cSYing Xue res = tipc_wait_for_accept(sock, timeo); 20080c3141e9SAllan Stephens if (res) 20090c3141e9SAllan Stephens goto exit; 20100c3141e9SAllan Stephens 20110c3141e9SAllan Stephens buf = skb_peek(&sk->sk_receive_queue); 20120c3141e9SAllan Stephens 2013c5fa7b3cSYing Xue res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 1); 20140fef8f20SPaul Gortmaker if (res) 20150fef8f20SPaul Gortmaker goto exit; 2016fdd75ea8SStephen Smalley security_sk_clone(sock->sk, new_sock->sk); 20170fef8f20SPaul Gortmaker 20180fef8f20SPaul Gortmaker new_sk = new_sock->sk; 2019301bae56SJon Paul Maloy new_tsock = tipc_sk(new_sk); 20200fef8f20SPaul Gortmaker msg = buf_msg(buf); 20210c3141e9SAllan Stephens 2022258f8667SYing Xue /* we lock on new_sk; but lockdep sees the lock on sk */ 2023258f8667SYing Xue lock_sock_nested(new_sk, SINGLE_DEPTH_NESTING); 20240c3141e9SAllan Stephens 20250c3141e9SAllan Stephens /* 20260c3141e9SAllan Stephens * Reject any stray messages received by new socket 20270c3141e9SAllan Stephens * before the socket lock was taken (very, very unlikely) 20280c3141e9SAllan Stephens */ 20292e84c60bSJon Paul Maloy tsk_rej_rx_queue(new_sk); 20300c3141e9SAllan Stephens 20310c3141e9SAllan Stephens /* Connect new socket to it's peer */ 2032301bae56SJon Paul Maloy tipc_sk_finish_conn(new_tsock, msg_origport(msg), msg_orignode(msg)); 20330c3141e9SAllan Stephens new_sock->state = SS_CONNECTED; 2034b97bf3fdSPer Liden 2035301bae56SJon Paul Maloy tsk_set_importance(new_tsock, msg_importance(msg)); 2036b97bf3fdSPer Liden if (msg_named(msg)) { 2037301bae56SJon Paul Maloy new_tsock->conn_type = msg_nametype(msg); 2038301bae56SJon Paul Maloy new_tsock->conn_instance = msg_nameinst(msg); 2039b97bf3fdSPer Liden } 2040b97bf3fdSPer Liden 2041b97bf3fdSPer Liden /* 2042b97bf3fdSPer Liden * Respond to 'SYN-' by discarding it & returning 'ACK'-. 2043b97bf3fdSPer Liden * Respond to 'SYN+' by queuing it on new socket. 2044b97bf3fdSPer Liden */ 2045b97bf3fdSPer Liden if (!msg_data_sz(msg)) { 20461fc54d8fSSam Ravnborg struct msghdr m = {NULL,}; 2047b97bf3fdSPer Liden 20482e84c60bSJon Paul Maloy tsk_advance_rx_queue(sk); 204939a0295fSYing Xue __tipc_send_stream(new_sock, &m, 0); 2050b97bf3fdSPer Liden } else { 20510c3141e9SAllan Stephens __skb_dequeue(&sk->sk_receive_queue); 20520c3141e9SAllan Stephens __skb_queue_head(&new_sk->sk_receive_queue, buf); 2053aba79f33SYing Xue skb_set_owner_r(buf, new_sk); 2054b97bf3fdSPer Liden } 20550c3141e9SAllan Stephens release_sock(new_sk); 2056b97bf3fdSPer Liden exit: 20570c3141e9SAllan Stephens release_sock(sk); 2058b97bf3fdSPer Liden return res; 2059b97bf3fdSPer Liden } 2060b97bf3fdSPer Liden 2061b97bf3fdSPer Liden /** 2062247f0f3cSYing Xue * tipc_shutdown - shutdown socket connection 2063b97bf3fdSPer Liden * @sock: socket structure 2064e247a8f5SAllan Stephens * @how: direction to close (must be SHUT_RDWR) 2065b97bf3fdSPer Liden * 2066b97bf3fdSPer Liden * Terminates connection (if necessary), then purges socket's receive queue. 2067b97bf3fdSPer Liden * 2068b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 2069b97bf3fdSPer Liden */ 2070247f0f3cSYing Xue static int tipc_shutdown(struct socket *sock, int how) 2071b97bf3fdSPer Liden { 20720c3141e9SAllan Stephens struct sock *sk = sock->sk; 2073f2f9800dSYing Xue struct net *net = sock_net(sk); 207458ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 2075a6ca1094SYing Xue struct sk_buff *skb; 2076cda3696dSJon Paul Maloy u32 dnode = tsk_peer_node(tsk); 2077cda3696dSJon Paul Maloy u32 dport = tsk_peer_port(tsk); 2078cda3696dSJon Paul Maloy u32 onode = tipc_own_addr(net); 2079cda3696dSJon Paul Maloy u32 oport = tsk->portid; 2080b97bf3fdSPer Liden int res; 2081b97bf3fdSPer Liden 2082e247a8f5SAllan Stephens if (how != SHUT_RDWR) 2083e247a8f5SAllan Stephens return -EINVAL; 2084b97bf3fdSPer Liden 20850c3141e9SAllan Stephens lock_sock(sk); 2086b97bf3fdSPer Liden 2087b97bf3fdSPer Liden switch (sock->state) { 20880c3141e9SAllan Stephens case SS_CONNECTING: 2089b97bf3fdSPer Liden case SS_CONNECTED: 2090b97bf3fdSPer Liden 2091b97bf3fdSPer Liden restart: 2092bcd3ffd4SJon Paul Maloy dnode = tsk_peer_node(tsk); 2093bcd3ffd4SJon Paul Maloy 2094617d3c7aSPaul Gortmaker /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ 2095a6ca1094SYing Xue skb = __skb_dequeue(&sk->sk_receive_queue); 2096a6ca1094SYing Xue if (skb) { 2097a6ca1094SYing Xue if (TIPC_SKB_CB(skb)->handle != NULL) { 2098a6ca1094SYing Xue kfree_skb(skb); 2099b97bf3fdSPer Liden goto restart; 2100b97bf3fdSPer Liden } 2101bcd3ffd4SJon Paul Maloy tipc_sk_respond(sk, skb, TIPC_CONN_SHUTDOWN); 21020c3141e9SAllan Stephens } else { 2103c5898636SJon Paul Maloy skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, 210480e44c22SJon Paul Maloy TIPC_CONN_MSG, SHORT_H_SIZE, 2105cda3696dSJon Paul Maloy 0, dnode, onode, dport, oport, 2106cda3696dSJon Paul Maloy TIPC_CONN_SHUTDOWN); 2107af9b028eSJon Paul Maloy tipc_node_xmit_skb(net, skb, dnode, tsk->portid); 2108b97bf3fdSPer Liden } 2109301bae56SJon Paul Maloy tsk->connected = 0; 21100c3141e9SAllan Stephens sock->state = SS_DISCONNECTING; 2111f2f9800dSYing Xue tipc_node_remove_conn(net, dnode, tsk->portid); 2112b97bf3fdSPer Liden /* fall through */ 2113b97bf3fdSPer Liden 2114b97bf3fdSPer Liden case SS_DISCONNECTING: 2115b97bf3fdSPer Liden 211675031151SYing Xue /* Discard any unreceived messages */ 211757467e56SYing Xue __skb_queue_purge(&sk->sk_receive_queue); 211875031151SYing Xue 211975031151SYing Xue /* Wake up anyone sleeping in poll */ 212075031151SYing Xue sk->sk_state_change(sk); 2121b97bf3fdSPer Liden res = 0; 2122b97bf3fdSPer Liden break; 2123b97bf3fdSPer Liden 2124b97bf3fdSPer Liden default: 2125b97bf3fdSPer Liden res = -ENOTCONN; 2126b97bf3fdSPer Liden } 2127b97bf3fdSPer Liden 21280c3141e9SAllan Stephens release_sock(sk); 2129b97bf3fdSPer Liden return res; 2130b97bf3fdSPer Liden } 2131b97bf3fdSPer Liden 2132f2f2a96aSYing Xue static void tipc_sk_timeout(unsigned long data) 213357289015SJon Paul Maloy { 2134f2f2a96aSYing Xue struct tipc_sock *tsk = (struct tipc_sock *)data; 2135f2f2a96aSYing Xue struct sock *sk = &tsk->sk; 2136a6ca1094SYing Xue struct sk_buff *skb = NULL; 213757289015SJon Paul Maloy u32 peer_port, peer_node; 2138c5898636SJon Paul Maloy u32 own_node = tsk_own_node(tsk); 213957289015SJon Paul Maloy 214057289015SJon Paul Maloy bh_lock_sock(sk); 2141301bae56SJon Paul Maloy if (!tsk->connected) { 21426c9808ceSJon Paul Maloy bh_unlock_sock(sk); 21436c9808ceSJon Paul Maloy goto exit; 21446c9808ceSJon Paul Maloy } 2145301bae56SJon Paul Maloy peer_port = tsk_peer_port(tsk); 2146301bae56SJon Paul Maloy peer_node = tsk_peer_node(tsk); 214757289015SJon Paul Maloy 2148301bae56SJon Paul Maloy if (tsk->probing_state == TIPC_CONN_PROBING) { 2149b3be5e3eSErik Hugne if (!sock_owned_by_user(sk)) { 2150b3be5e3eSErik Hugne sk->sk_socket->state = SS_DISCONNECTING; 2151b3be5e3eSErik Hugne tsk->connected = 0; 2152b3be5e3eSErik Hugne tipc_node_remove_conn(sock_net(sk), tsk_peer_node(tsk), 2153b3be5e3eSErik Hugne tsk_peer_port(tsk)); 2154b3be5e3eSErik Hugne sk->sk_state_change(sk); 2155b3be5e3eSErik Hugne } else { 2156b3be5e3eSErik Hugne /* Try again later */ 2157b3be5e3eSErik Hugne sk_reset_timer(sk, &sk->sk_timer, (HZ / 20)); 2158b3be5e3eSErik Hugne } 2159b3be5e3eSErik Hugne 216057289015SJon Paul Maloy } else { 2161c5898636SJon Paul Maloy skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, 2162c5898636SJon Paul Maloy INT_H_SIZE, 0, peer_node, own_node, 2163f2f2a96aSYing Xue peer_port, tsk->portid, TIPC_OK); 2164301bae56SJon Paul Maloy tsk->probing_state = TIPC_CONN_PROBING; 21653721e9c7SYing Xue sk_reset_timer(sk, &sk->sk_timer, jiffies + tsk->probing_intv); 216657289015SJon Paul Maloy } 216757289015SJon Paul Maloy bh_unlock_sock(sk); 2168a6ca1094SYing Xue if (skb) 2169af9b028eSJon Paul Maloy tipc_node_xmit_skb(sock_net(sk), skb, peer_node, tsk->portid); 21706c9808ceSJon Paul Maloy exit: 217107f6c4bcSYing Xue sock_put(sk); 217257289015SJon Paul Maloy } 217357289015SJon Paul Maloy 2174301bae56SJon Paul Maloy static int tipc_sk_publish(struct tipc_sock *tsk, uint scope, 21750fc87aaeSJon Paul Maloy struct tipc_name_seq const *seq) 21760fc87aaeSJon Paul Maloy { 2177f2f9800dSYing Xue struct net *net = sock_net(&tsk->sk); 21780fc87aaeSJon Paul Maloy struct publication *publ; 21790fc87aaeSJon Paul Maloy u32 key; 21800fc87aaeSJon Paul Maloy 2181301bae56SJon Paul Maloy if (tsk->connected) 21820fc87aaeSJon Paul Maloy return -EINVAL; 218307f6c4bcSYing Xue key = tsk->portid + tsk->pub_count + 1; 218407f6c4bcSYing Xue if (key == tsk->portid) 21850fc87aaeSJon Paul Maloy return -EADDRINUSE; 21860fc87aaeSJon Paul Maloy 2187f2f9800dSYing Xue publ = tipc_nametbl_publish(net, seq->type, seq->lower, seq->upper, 218807f6c4bcSYing Xue scope, tsk->portid, key); 21890fc87aaeSJon Paul Maloy if (unlikely(!publ)) 21900fc87aaeSJon Paul Maloy return -EINVAL; 21910fc87aaeSJon Paul Maloy 2192301bae56SJon Paul Maloy list_add(&publ->pport_list, &tsk->publications); 2193301bae56SJon Paul Maloy tsk->pub_count++; 2194301bae56SJon Paul Maloy tsk->published = 1; 21950fc87aaeSJon Paul Maloy return 0; 21960fc87aaeSJon Paul Maloy } 21970fc87aaeSJon Paul Maloy 2198301bae56SJon Paul Maloy static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope, 21990fc87aaeSJon Paul Maloy struct tipc_name_seq const *seq) 22000fc87aaeSJon Paul Maloy { 2201f2f9800dSYing Xue struct net *net = sock_net(&tsk->sk); 22020fc87aaeSJon Paul Maloy struct publication *publ; 22030fc87aaeSJon Paul Maloy struct publication *safe; 22040fc87aaeSJon Paul Maloy int rc = -EINVAL; 22050fc87aaeSJon Paul Maloy 2206301bae56SJon Paul Maloy list_for_each_entry_safe(publ, safe, &tsk->publications, pport_list) { 22070fc87aaeSJon Paul Maloy if (seq) { 22080fc87aaeSJon Paul Maloy if (publ->scope != scope) 22090fc87aaeSJon Paul Maloy continue; 22100fc87aaeSJon Paul Maloy if (publ->type != seq->type) 22110fc87aaeSJon Paul Maloy continue; 22120fc87aaeSJon Paul Maloy if (publ->lower != seq->lower) 22130fc87aaeSJon Paul Maloy continue; 22140fc87aaeSJon Paul Maloy if (publ->upper != seq->upper) 22150fc87aaeSJon Paul Maloy break; 2216f2f9800dSYing Xue tipc_nametbl_withdraw(net, publ->type, publ->lower, 22170fc87aaeSJon Paul Maloy publ->ref, publ->key); 22180fc87aaeSJon Paul Maloy rc = 0; 22190fc87aaeSJon Paul Maloy break; 22200fc87aaeSJon Paul Maloy } 2221f2f9800dSYing Xue tipc_nametbl_withdraw(net, publ->type, publ->lower, 22220fc87aaeSJon Paul Maloy publ->ref, publ->key); 22230fc87aaeSJon Paul Maloy rc = 0; 22240fc87aaeSJon Paul Maloy } 2225301bae56SJon Paul Maloy if (list_empty(&tsk->publications)) 2226301bae56SJon Paul Maloy tsk->published = 0; 22270fc87aaeSJon Paul Maloy return rc; 22280fc87aaeSJon Paul Maloy } 22290fc87aaeSJon Paul Maloy 22305a9ee0beSJon Paul Maloy /* tipc_sk_reinit: set non-zero address in all existing sockets 22315a9ee0beSJon Paul Maloy * when we go from standalone to network mode. 22325a9ee0beSJon Paul Maloy */ 2233e05b31f4SYing Xue void tipc_sk_reinit(struct net *net) 22345a9ee0beSJon Paul Maloy { 2235e05b31f4SYing Xue struct tipc_net *tn = net_generic(net, tipc_net_id); 223607f6c4bcSYing Xue const struct bucket_table *tbl; 223707f6c4bcSYing Xue struct rhash_head *pos; 223807f6c4bcSYing Xue struct tipc_sock *tsk; 22395a9ee0beSJon Paul Maloy struct tipc_msg *msg; 224007f6c4bcSYing Xue int i; 22415a9ee0beSJon Paul Maloy 224207f6c4bcSYing Xue rcu_read_lock(); 2243e05b31f4SYing Xue tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht); 224407f6c4bcSYing Xue for (i = 0; i < tbl->size; i++) { 224507f6c4bcSYing Xue rht_for_each_entry_rcu(tsk, pos, tbl, i, node) { 224607f6c4bcSYing Xue spin_lock_bh(&tsk->sk.sk_lock.slock); 2247301bae56SJon Paul Maloy msg = &tsk->phdr; 224834747539SYing Xue msg_set_prevnode(msg, tn->own_addr); 224934747539SYing Xue msg_set_orignode(msg, tn->own_addr); 225007f6c4bcSYing Xue spin_unlock_bh(&tsk->sk.sk_lock.slock); 22515a9ee0beSJon Paul Maloy } 22525a9ee0beSJon Paul Maloy } 225307f6c4bcSYing Xue rcu_read_unlock(); 225407f6c4bcSYing Xue } 22555a9ee0beSJon Paul Maloy 2256e05b31f4SYing Xue static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid) 2257808d90f9SJon Paul Maloy { 2258e05b31f4SYing Xue struct tipc_net *tn = net_generic(net, tipc_net_id); 2259808d90f9SJon Paul Maloy struct tipc_sock *tsk; 2260808d90f9SJon Paul Maloy 226107f6c4bcSYing Xue rcu_read_lock(); 22626cca7289SHerbert Xu tsk = rhashtable_lookup_fast(&tn->sk_rht, &portid, tsk_rht_params); 226307f6c4bcSYing Xue if (tsk) 2264808d90f9SJon Paul Maloy sock_hold(&tsk->sk); 226507f6c4bcSYing Xue rcu_read_unlock(); 226607f6c4bcSYing Xue 2267808d90f9SJon Paul Maloy return tsk; 2268808d90f9SJon Paul Maloy } 2269808d90f9SJon Paul Maloy 227007f6c4bcSYing Xue static int tipc_sk_insert(struct tipc_sock *tsk) 2271808d90f9SJon Paul Maloy { 2272e05b31f4SYing Xue struct sock *sk = &tsk->sk; 2273e05b31f4SYing Xue struct net *net = sock_net(sk); 2274e05b31f4SYing Xue struct tipc_net *tn = net_generic(net, tipc_net_id); 227507f6c4bcSYing Xue u32 remaining = (TIPC_MAX_PORT - TIPC_MIN_PORT) + 1; 227607f6c4bcSYing Xue u32 portid = prandom_u32() % remaining + TIPC_MIN_PORT; 2277808d90f9SJon Paul Maloy 227807f6c4bcSYing Xue while (remaining--) { 227907f6c4bcSYing Xue portid++; 228007f6c4bcSYing Xue if ((portid < TIPC_MIN_PORT) || (portid > TIPC_MAX_PORT)) 228107f6c4bcSYing Xue portid = TIPC_MIN_PORT; 228207f6c4bcSYing Xue tsk->portid = portid; 2283808d90f9SJon Paul Maloy sock_hold(&tsk->sk); 22846cca7289SHerbert Xu if (!rhashtable_lookup_insert_fast(&tn->sk_rht, &tsk->node, 22856cca7289SHerbert Xu tsk_rht_params)) 228607f6c4bcSYing Xue return 0; 2287808d90f9SJon Paul Maloy sock_put(&tsk->sk); 2288808d90f9SJon Paul Maloy } 2289808d90f9SJon Paul Maloy 229007f6c4bcSYing Xue return -1; 229107f6c4bcSYing Xue } 229207f6c4bcSYing Xue 229307f6c4bcSYing Xue static void tipc_sk_remove(struct tipc_sock *tsk) 229407f6c4bcSYing Xue { 229507f6c4bcSYing Xue struct sock *sk = &tsk->sk; 2296e05b31f4SYing Xue struct tipc_net *tn = net_generic(sock_net(sk), tipc_net_id); 229707f6c4bcSYing Xue 22986cca7289SHerbert Xu if (!rhashtable_remove_fast(&tn->sk_rht, &tsk->node, tsk_rht_params)) { 229907f6c4bcSYing Xue WARN_ON(atomic_read(&sk->sk_refcnt) == 1); 230007f6c4bcSYing Xue __sock_put(sk); 230107f6c4bcSYing Xue } 230207f6c4bcSYing Xue } 230307f6c4bcSYing Xue 23046cca7289SHerbert Xu static const struct rhashtable_params tsk_rht_params = { 230507f6c4bcSYing Xue .nelem_hint = 192, 230607f6c4bcSYing Xue .head_offset = offsetof(struct tipc_sock, node), 230707f6c4bcSYing Xue .key_offset = offsetof(struct tipc_sock, portid), 230807f6c4bcSYing Xue .key_len = sizeof(u32), /* portid */ 2309446c89acSHerbert Xu .max_size = 1048576, 2310446c89acSHerbert Xu .min_size = 256, 2311b5e2c150SThomas Graf .automatic_shrinking = true, 231207f6c4bcSYing Xue }; 231307f6c4bcSYing Xue 23146cca7289SHerbert Xu int tipc_sk_rht_init(struct net *net) 23156cca7289SHerbert Xu { 23166cca7289SHerbert Xu struct tipc_net *tn = net_generic(net, tipc_net_id); 23176cca7289SHerbert Xu 23186cca7289SHerbert Xu return rhashtable_init(&tn->sk_rht, &tsk_rht_params); 231907f6c4bcSYing Xue } 232007f6c4bcSYing Xue 2321e05b31f4SYing Xue void tipc_sk_rht_destroy(struct net *net) 232207f6c4bcSYing Xue { 2323e05b31f4SYing Xue struct tipc_net *tn = net_generic(net, tipc_net_id); 2324e05b31f4SYing Xue 232507f6c4bcSYing Xue /* Wait for socket readers to complete */ 232607f6c4bcSYing Xue synchronize_net(); 232707f6c4bcSYing Xue 2328e05b31f4SYing Xue rhashtable_destroy(&tn->sk_rht); 232907f6c4bcSYing Xue } 233007f6c4bcSYing Xue 2331808d90f9SJon Paul Maloy /** 2332247f0f3cSYing Xue * tipc_setsockopt - set socket option 2333b97bf3fdSPer Liden * @sock: socket structure 2334b97bf3fdSPer Liden * @lvl: option level 2335b97bf3fdSPer Liden * @opt: option identifier 2336b97bf3fdSPer Liden * @ov: pointer to new option value 2337b97bf3fdSPer Liden * @ol: length of option value 2338b97bf3fdSPer Liden * 2339b97bf3fdSPer Liden * For stream sockets only, accepts and ignores all IPPROTO_TCP options 2340b97bf3fdSPer Liden * (to ease compatibility). 2341b97bf3fdSPer Liden * 2342b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 2343b97bf3fdSPer Liden */ 2344247f0f3cSYing Xue static int tipc_setsockopt(struct socket *sock, int lvl, int opt, 2345247f0f3cSYing Xue char __user *ov, unsigned int ol) 2346b97bf3fdSPer Liden { 23470c3141e9SAllan Stephens struct sock *sk = sock->sk; 234858ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 2349b97bf3fdSPer Liden u32 value; 2350b97bf3fdSPer Liden int res; 2351b97bf3fdSPer Liden 2352b97bf3fdSPer Liden if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM)) 2353b97bf3fdSPer Liden return 0; 2354b97bf3fdSPer Liden if (lvl != SOL_TIPC) 2355b97bf3fdSPer Liden return -ENOPROTOOPT; 2356b97bf3fdSPer Liden if (ol < sizeof(value)) 2357b97bf3fdSPer Liden return -EINVAL; 23582db9983aSAllan Stephens res = get_user(value, (u32 __user *)ov); 23592db9983aSAllan Stephens if (res) 2360b97bf3fdSPer Liden return res; 2361b97bf3fdSPer Liden 23620c3141e9SAllan Stephens lock_sock(sk); 2363b97bf3fdSPer Liden 2364b97bf3fdSPer Liden switch (opt) { 2365b97bf3fdSPer Liden case TIPC_IMPORTANCE: 2366301bae56SJon Paul Maloy res = tsk_set_importance(tsk, value); 2367b97bf3fdSPer Liden break; 2368b97bf3fdSPer Liden case TIPC_SRC_DROPPABLE: 2369b97bf3fdSPer Liden if (sock->type != SOCK_STREAM) 2370301bae56SJon Paul Maloy tsk_set_unreliable(tsk, value); 2371b97bf3fdSPer Liden else 2372b97bf3fdSPer Liden res = -ENOPROTOOPT; 2373b97bf3fdSPer Liden break; 2374b97bf3fdSPer Liden case TIPC_DEST_DROPPABLE: 2375301bae56SJon Paul Maloy tsk_set_unreturnable(tsk, value); 2376b97bf3fdSPer Liden break; 2377b97bf3fdSPer Liden case TIPC_CONN_TIMEOUT: 2378a0f40f02SAllan Stephens tipc_sk(sk)->conn_timeout = value; 23790c3141e9SAllan Stephens /* no need to set "res", since already 0 at this point */ 2380b97bf3fdSPer Liden break; 2381b97bf3fdSPer Liden default: 2382b97bf3fdSPer Liden res = -EINVAL; 2383b97bf3fdSPer Liden } 2384b97bf3fdSPer Liden 23850c3141e9SAllan Stephens release_sock(sk); 23860c3141e9SAllan Stephens 2387b97bf3fdSPer Liden return res; 2388b97bf3fdSPer Liden } 2389b97bf3fdSPer Liden 2390b97bf3fdSPer Liden /** 2391247f0f3cSYing Xue * tipc_getsockopt - get socket option 2392b97bf3fdSPer Liden * @sock: socket structure 2393b97bf3fdSPer Liden * @lvl: option level 2394b97bf3fdSPer Liden * @opt: option identifier 2395b97bf3fdSPer Liden * @ov: receptacle for option value 2396b97bf3fdSPer Liden * @ol: receptacle for length of option value 2397b97bf3fdSPer Liden * 2398b97bf3fdSPer Liden * For stream sockets only, returns 0 length result for all IPPROTO_TCP options 2399b97bf3fdSPer Liden * (to ease compatibility). 2400b97bf3fdSPer Liden * 2401b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 2402b97bf3fdSPer Liden */ 2403247f0f3cSYing Xue static int tipc_getsockopt(struct socket *sock, int lvl, int opt, 2404247f0f3cSYing Xue char __user *ov, int __user *ol) 2405b97bf3fdSPer Liden { 24060c3141e9SAllan Stephens struct sock *sk = sock->sk; 240758ed9442SJon Paul Maloy struct tipc_sock *tsk = tipc_sk(sk); 2408b97bf3fdSPer Liden int len; 2409b97bf3fdSPer Liden u32 value; 2410b97bf3fdSPer Liden int res; 2411b97bf3fdSPer Liden 2412b97bf3fdSPer Liden if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM)) 2413b97bf3fdSPer Liden return put_user(0, ol); 2414b97bf3fdSPer Liden if (lvl != SOL_TIPC) 2415b97bf3fdSPer Liden return -ENOPROTOOPT; 24162db9983aSAllan Stephens res = get_user(len, ol); 24172db9983aSAllan Stephens if (res) 2418b97bf3fdSPer Liden return res; 2419b97bf3fdSPer Liden 24200c3141e9SAllan Stephens lock_sock(sk); 2421b97bf3fdSPer Liden 2422b97bf3fdSPer Liden switch (opt) { 2423b97bf3fdSPer Liden case TIPC_IMPORTANCE: 2424301bae56SJon Paul Maloy value = tsk_importance(tsk); 2425b97bf3fdSPer Liden break; 2426b97bf3fdSPer Liden case TIPC_SRC_DROPPABLE: 2427301bae56SJon Paul Maloy value = tsk_unreliable(tsk); 2428b97bf3fdSPer Liden break; 2429b97bf3fdSPer Liden case TIPC_DEST_DROPPABLE: 2430301bae56SJon Paul Maloy value = tsk_unreturnable(tsk); 2431b97bf3fdSPer Liden break; 2432b97bf3fdSPer Liden case TIPC_CONN_TIMEOUT: 2433301bae56SJon Paul Maloy value = tsk->conn_timeout; 24340c3141e9SAllan Stephens /* no need to set "res", since already 0 at this point */ 2435b97bf3fdSPer Liden break; 24366650613dS[email protected] case TIPC_NODE_RECVQ_DEPTH: 24379da3d475SYing Xue value = 0; /* was tipc_queue_size, now obsolete */ 24386650613dS[email protected] break; 24396650613dS[email protected] case TIPC_SOCK_RECVQ_DEPTH: 24406650613dS[email protected] value = skb_queue_len(&sk->sk_receive_queue); 24416650613dS[email protected] break; 2442b97bf3fdSPer Liden default: 2443b97bf3fdSPer Liden res = -EINVAL; 2444b97bf3fdSPer Liden } 2445b97bf3fdSPer Liden 24460c3141e9SAllan Stephens release_sock(sk); 24470c3141e9SAllan Stephens 244825860c3bSPaul Gortmaker if (res) 244925860c3bSPaul Gortmaker return res; /* "get" failed */ 2450b97bf3fdSPer Liden 245125860c3bSPaul Gortmaker if (len < sizeof(value)) 245225860c3bSPaul Gortmaker return -EINVAL; 245325860c3bSPaul Gortmaker 245425860c3bSPaul Gortmaker if (copy_to_user(ov, &value, sizeof(value))) 245525860c3bSPaul Gortmaker return -EFAULT; 245625860c3bSPaul Gortmaker 245725860c3bSPaul Gortmaker return put_user(sizeof(value), ol); 2458b97bf3fdSPer Liden } 2459b97bf3fdSPer Liden 2460f2f9800dSYing Xue static int tipc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 246178acb1f9SErik Hugne { 2462f2f9800dSYing Xue struct sock *sk = sock->sk; 246378acb1f9SErik Hugne struct tipc_sioc_ln_req lnr; 246478acb1f9SErik Hugne void __user *argp = (void __user *)arg; 246578acb1f9SErik Hugne 246678acb1f9SErik Hugne switch (cmd) { 246778acb1f9SErik Hugne case SIOCGETLINKNAME: 246878acb1f9SErik Hugne if (copy_from_user(&lnr, argp, sizeof(lnr))) 246978acb1f9SErik Hugne return -EFAULT; 2470f2f9800dSYing Xue if (!tipc_node_get_linkname(sock_net(sk), 2471f2f9800dSYing Xue lnr.bearer_id & 0xffff, lnr.peer, 247278acb1f9SErik Hugne lnr.linkname, TIPC_MAX_LINK_NAME)) { 247378acb1f9SErik Hugne if (copy_to_user(argp, &lnr, sizeof(lnr))) 247478acb1f9SErik Hugne return -EFAULT; 247578acb1f9SErik Hugne return 0; 247678acb1f9SErik Hugne } 247778acb1f9SErik Hugne return -EADDRNOTAVAIL; 247878acb1f9SErik Hugne default: 247978acb1f9SErik Hugne return -ENOIOCTLCMD; 248078acb1f9SErik Hugne } 248178acb1f9SErik Hugne } 248278acb1f9SErik Hugne 2483ae86b9e3SBen Hutchings /* Protocol switches for the various types of TIPC sockets */ 2484ae86b9e3SBen Hutchings 2485bca65eaeSFlorian Westphal static const struct proto_ops msg_ops = { 2486b97bf3fdSPer Liden .owner = THIS_MODULE, 2487b97bf3fdSPer Liden .family = AF_TIPC, 2488247f0f3cSYing Xue .release = tipc_release, 2489247f0f3cSYing Xue .bind = tipc_bind, 2490247f0f3cSYing Xue .connect = tipc_connect, 24915eee6a6dSAllan Stephens .socketpair = sock_no_socketpair, 2492245f3d34SYing Xue .accept = sock_no_accept, 2493247f0f3cSYing Xue .getname = tipc_getname, 2494247f0f3cSYing Xue .poll = tipc_poll, 249578acb1f9SErik Hugne .ioctl = tipc_ioctl, 2496245f3d34SYing Xue .listen = sock_no_listen, 2497247f0f3cSYing Xue .shutdown = tipc_shutdown, 2498247f0f3cSYing Xue .setsockopt = tipc_setsockopt, 2499247f0f3cSYing Xue .getsockopt = tipc_getsockopt, 2500247f0f3cSYing Xue .sendmsg = tipc_sendmsg, 2501247f0f3cSYing Xue .recvmsg = tipc_recvmsg, 25025eee6a6dSAllan Stephens .mmap = sock_no_mmap, 25035eee6a6dSAllan Stephens .sendpage = sock_no_sendpage 2504b97bf3fdSPer Liden }; 2505b97bf3fdSPer Liden 2506bca65eaeSFlorian Westphal static const struct proto_ops packet_ops = { 2507b97bf3fdSPer Liden .owner = THIS_MODULE, 2508b97bf3fdSPer Liden .family = AF_TIPC, 2509247f0f3cSYing Xue .release = tipc_release, 2510247f0f3cSYing Xue .bind = tipc_bind, 2511247f0f3cSYing Xue .connect = tipc_connect, 25125eee6a6dSAllan Stephens .socketpair = sock_no_socketpair, 2513247f0f3cSYing Xue .accept = tipc_accept, 2514247f0f3cSYing Xue .getname = tipc_getname, 2515247f0f3cSYing Xue .poll = tipc_poll, 251678acb1f9SErik Hugne .ioctl = tipc_ioctl, 2517247f0f3cSYing Xue .listen = tipc_listen, 2518247f0f3cSYing Xue .shutdown = tipc_shutdown, 2519247f0f3cSYing Xue .setsockopt = tipc_setsockopt, 2520247f0f3cSYing Xue .getsockopt = tipc_getsockopt, 2521247f0f3cSYing Xue .sendmsg = tipc_send_packet, 2522247f0f3cSYing Xue .recvmsg = tipc_recvmsg, 25235eee6a6dSAllan Stephens .mmap = sock_no_mmap, 25245eee6a6dSAllan Stephens .sendpage = sock_no_sendpage 2525b97bf3fdSPer Liden }; 2526b97bf3fdSPer Liden 2527bca65eaeSFlorian Westphal static const struct proto_ops stream_ops = { 2528b97bf3fdSPer Liden .owner = THIS_MODULE, 2529b97bf3fdSPer Liden .family = AF_TIPC, 2530247f0f3cSYing Xue .release = tipc_release, 2531247f0f3cSYing Xue .bind = tipc_bind, 2532247f0f3cSYing Xue .connect = tipc_connect, 25335eee6a6dSAllan Stephens .socketpair = sock_no_socketpair, 2534247f0f3cSYing Xue .accept = tipc_accept, 2535247f0f3cSYing Xue .getname = tipc_getname, 2536247f0f3cSYing Xue .poll = tipc_poll, 253778acb1f9SErik Hugne .ioctl = tipc_ioctl, 2538247f0f3cSYing Xue .listen = tipc_listen, 2539247f0f3cSYing Xue .shutdown = tipc_shutdown, 2540247f0f3cSYing Xue .setsockopt = tipc_setsockopt, 2541247f0f3cSYing Xue .getsockopt = tipc_getsockopt, 2542247f0f3cSYing Xue .sendmsg = tipc_send_stream, 2543247f0f3cSYing Xue .recvmsg = tipc_recv_stream, 25445eee6a6dSAllan Stephens .mmap = sock_no_mmap, 25455eee6a6dSAllan Stephens .sendpage = sock_no_sendpage 2546b97bf3fdSPer Liden }; 2547b97bf3fdSPer Liden 2548bca65eaeSFlorian Westphal static const struct net_proto_family tipc_family_ops = { 2549b97bf3fdSPer Liden .owner = THIS_MODULE, 2550b97bf3fdSPer Liden .family = AF_TIPC, 2551c5fa7b3cSYing Xue .create = tipc_sk_create 2552b97bf3fdSPer Liden }; 2553b97bf3fdSPer Liden 2554b97bf3fdSPer Liden static struct proto tipc_proto = { 2555b97bf3fdSPer Liden .name = "TIPC", 2556b97bf3fdSPer Liden .owner = THIS_MODULE, 2557cc79dd1bSYing Xue .obj_size = sizeof(struct tipc_sock), 2558cc79dd1bSYing Xue .sysctl_rmem = sysctl_tipc_rmem 2559b97bf3fdSPer Liden }; 2560b97bf3fdSPer Liden 2561b97bf3fdSPer Liden /** 25624323add6SPer Liden * tipc_socket_init - initialize TIPC socket interface 2563b97bf3fdSPer Liden * 2564b97bf3fdSPer Liden * Returns 0 on success, errno otherwise 2565b97bf3fdSPer Liden */ 25664323add6SPer Liden int tipc_socket_init(void) 2567b97bf3fdSPer Liden { 2568b97bf3fdSPer Liden int res; 2569b97bf3fdSPer Liden 2570b97bf3fdSPer Liden res = proto_register(&tipc_proto, 1); 2571b97bf3fdSPer Liden if (res) { 25722cf8aa19SErik Hugne pr_err("Failed to register TIPC protocol type\n"); 2573b97bf3fdSPer Liden goto out; 2574b97bf3fdSPer Liden } 2575b97bf3fdSPer Liden 2576b97bf3fdSPer Liden res = sock_register(&tipc_family_ops); 2577b97bf3fdSPer Liden if (res) { 25782cf8aa19SErik Hugne pr_err("Failed to register TIPC socket type\n"); 2579b97bf3fdSPer Liden proto_unregister(&tipc_proto); 2580b97bf3fdSPer Liden goto out; 2581b97bf3fdSPer Liden } 2582b97bf3fdSPer Liden out: 2583b97bf3fdSPer Liden return res; 2584b97bf3fdSPer Liden } 2585b97bf3fdSPer Liden 2586b97bf3fdSPer Liden /** 25874323add6SPer Liden * tipc_socket_stop - stop TIPC socket interface 2588b97bf3fdSPer Liden */ 25894323add6SPer Liden void tipc_socket_stop(void) 2590b97bf3fdSPer Liden { 2591b97bf3fdSPer Liden sock_unregister(tipc_family_ops.family); 2592b97bf3fdSPer Liden proto_unregister(&tipc_proto); 2593b97bf3fdSPer Liden } 259434b78a12SRichard Alpe 259534b78a12SRichard Alpe /* Caller should hold socket lock for the passed tipc socket. */ 2596d8182804SRichard Alpe static int __tipc_nl_add_sk_con(struct sk_buff *skb, struct tipc_sock *tsk) 259734b78a12SRichard Alpe { 259834b78a12SRichard Alpe u32 peer_node; 259934b78a12SRichard Alpe u32 peer_port; 260034b78a12SRichard Alpe struct nlattr *nest; 260134b78a12SRichard Alpe 260234b78a12SRichard Alpe peer_node = tsk_peer_node(tsk); 260334b78a12SRichard Alpe peer_port = tsk_peer_port(tsk); 260434b78a12SRichard Alpe 260534b78a12SRichard Alpe nest = nla_nest_start(skb, TIPC_NLA_SOCK_CON); 260634b78a12SRichard Alpe 260734b78a12SRichard Alpe if (nla_put_u32(skb, TIPC_NLA_CON_NODE, peer_node)) 260834b78a12SRichard Alpe goto msg_full; 260934b78a12SRichard Alpe if (nla_put_u32(skb, TIPC_NLA_CON_SOCK, peer_port)) 261034b78a12SRichard Alpe goto msg_full; 261134b78a12SRichard Alpe 261234b78a12SRichard Alpe if (tsk->conn_type != 0) { 261334b78a12SRichard Alpe if (nla_put_flag(skb, TIPC_NLA_CON_FLAG)) 261434b78a12SRichard Alpe goto msg_full; 261534b78a12SRichard Alpe if (nla_put_u32(skb, TIPC_NLA_CON_TYPE, tsk->conn_type)) 261634b78a12SRichard Alpe goto msg_full; 261734b78a12SRichard Alpe if (nla_put_u32(skb, TIPC_NLA_CON_INST, tsk->conn_instance)) 261834b78a12SRichard Alpe goto msg_full; 261934b78a12SRichard Alpe } 262034b78a12SRichard Alpe nla_nest_end(skb, nest); 262134b78a12SRichard Alpe 262234b78a12SRichard Alpe return 0; 262334b78a12SRichard Alpe 262434b78a12SRichard Alpe msg_full: 262534b78a12SRichard Alpe nla_nest_cancel(skb, nest); 262634b78a12SRichard Alpe 262734b78a12SRichard Alpe return -EMSGSIZE; 262834b78a12SRichard Alpe } 262934b78a12SRichard Alpe 263034b78a12SRichard Alpe /* Caller should hold socket lock for the passed tipc socket. */ 2631d8182804SRichard Alpe static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb, 263234b78a12SRichard Alpe struct tipc_sock *tsk) 263334b78a12SRichard Alpe { 263434b78a12SRichard Alpe int err; 263534b78a12SRichard Alpe void *hdr; 263634b78a12SRichard Alpe struct nlattr *attrs; 263734747539SYing Xue struct net *net = sock_net(skb->sk); 263834747539SYing Xue struct tipc_net *tn = net_generic(net, tipc_net_id); 263934b78a12SRichard Alpe 264034b78a12SRichard Alpe hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 2641bfb3e5ddSRichard Alpe &tipc_genl_family, NLM_F_MULTI, TIPC_NL_SOCK_GET); 264234b78a12SRichard Alpe if (!hdr) 264334b78a12SRichard Alpe goto msg_cancel; 264434b78a12SRichard Alpe 264534b78a12SRichard Alpe attrs = nla_nest_start(skb, TIPC_NLA_SOCK); 264634b78a12SRichard Alpe if (!attrs) 264734b78a12SRichard Alpe goto genlmsg_cancel; 264807f6c4bcSYing Xue if (nla_put_u32(skb, TIPC_NLA_SOCK_REF, tsk->portid)) 264934b78a12SRichard Alpe goto attr_msg_cancel; 265034747539SYing Xue if (nla_put_u32(skb, TIPC_NLA_SOCK_ADDR, tn->own_addr)) 265134b78a12SRichard Alpe goto attr_msg_cancel; 265234b78a12SRichard Alpe 265334b78a12SRichard Alpe if (tsk->connected) { 265434b78a12SRichard Alpe err = __tipc_nl_add_sk_con(skb, tsk); 265534b78a12SRichard Alpe if (err) 265634b78a12SRichard Alpe goto attr_msg_cancel; 265734b78a12SRichard Alpe } else if (!list_empty(&tsk->publications)) { 265834b78a12SRichard Alpe if (nla_put_flag(skb, TIPC_NLA_SOCK_HAS_PUBL)) 265934b78a12SRichard Alpe goto attr_msg_cancel; 266034b78a12SRichard Alpe } 266134b78a12SRichard Alpe nla_nest_end(skb, attrs); 266234b78a12SRichard Alpe genlmsg_end(skb, hdr); 266334b78a12SRichard Alpe 266434b78a12SRichard Alpe return 0; 266534b78a12SRichard Alpe 266634b78a12SRichard Alpe attr_msg_cancel: 266734b78a12SRichard Alpe nla_nest_cancel(skb, attrs); 266834b78a12SRichard Alpe genlmsg_cancel: 266934b78a12SRichard Alpe genlmsg_cancel(skb, hdr); 267034b78a12SRichard Alpe msg_cancel: 267134b78a12SRichard Alpe return -EMSGSIZE; 267234b78a12SRichard Alpe } 267334b78a12SRichard Alpe 267434b78a12SRichard Alpe int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb) 267534b78a12SRichard Alpe { 267634b78a12SRichard Alpe int err; 267734b78a12SRichard Alpe struct tipc_sock *tsk; 267807f6c4bcSYing Xue const struct bucket_table *tbl; 267907f6c4bcSYing Xue struct rhash_head *pos; 2680e05b31f4SYing Xue struct net *net = sock_net(skb->sk); 2681e05b31f4SYing Xue struct tipc_net *tn = net_generic(net, tipc_net_id); 2682d6e164e3SRichard Alpe u32 tbl_id = cb->args[0]; 2683d6e164e3SRichard Alpe u32 prev_portid = cb->args[1]; 268434b78a12SRichard Alpe 268507f6c4bcSYing Xue rcu_read_lock(); 2686e05b31f4SYing Xue tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht); 2687d6e164e3SRichard Alpe for (; tbl_id < tbl->size; tbl_id++) { 2688d6e164e3SRichard Alpe rht_for_each_entry_rcu(tsk, pos, tbl, tbl_id, node) { 268907f6c4bcSYing Xue spin_lock_bh(&tsk->sk.sk_lock.slock); 2690d6e164e3SRichard Alpe if (prev_portid && prev_portid != tsk->portid) { 269107f6c4bcSYing Xue spin_unlock_bh(&tsk->sk.sk_lock.slock); 2692d6e164e3SRichard Alpe continue; 2693d6e164e3SRichard Alpe } 269434b78a12SRichard Alpe 2695d6e164e3SRichard Alpe err = __tipc_nl_add_sk(skb, cb, tsk); 2696d6e164e3SRichard Alpe if (err) { 2697d6e164e3SRichard Alpe prev_portid = tsk->portid; 2698d6e164e3SRichard Alpe spin_unlock_bh(&tsk->sk.sk_lock.slock); 2699d6e164e3SRichard Alpe goto out; 2700d6e164e3SRichard Alpe } 2701d6e164e3SRichard Alpe prev_portid = 0; 2702d6e164e3SRichard Alpe spin_unlock_bh(&tsk->sk.sk_lock.slock); 270334b78a12SRichard Alpe } 270407f6c4bcSYing Xue } 2705d6e164e3SRichard Alpe out: 270607f6c4bcSYing Xue rcu_read_unlock(); 2707d6e164e3SRichard Alpe cb->args[0] = tbl_id; 2708d6e164e3SRichard Alpe cb->args[1] = prev_portid; 270934b78a12SRichard Alpe 271034b78a12SRichard Alpe return skb->len; 271134b78a12SRichard Alpe } 27121a1a143dSRichard Alpe 27131a1a143dSRichard Alpe /* Caller should hold socket lock for the passed tipc socket. */ 2714d8182804SRichard Alpe static int __tipc_nl_add_sk_publ(struct sk_buff *skb, 2715d8182804SRichard Alpe struct netlink_callback *cb, 27161a1a143dSRichard Alpe struct publication *publ) 27171a1a143dSRichard Alpe { 27181a1a143dSRichard Alpe void *hdr; 27191a1a143dSRichard Alpe struct nlattr *attrs; 27201a1a143dSRichard Alpe 27211a1a143dSRichard Alpe hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 2722bfb3e5ddSRichard Alpe &tipc_genl_family, NLM_F_MULTI, TIPC_NL_PUBL_GET); 27231a1a143dSRichard Alpe if (!hdr) 27241a1a143dSRichard Alpe goto msg_cancel; 27251a1a143dSRichard Alpe 27261a1a143dSRichard Alpe attrs = nla_nest_start(skb, TIPC_NLA_PUBL); 27271a1a143dSRichard Alpe if (!attrs) 27281a1a143dSRichard Alpe goto genlmsg_cancel; 27291a1a143dSRichard Alpe 27301a1a143dSRichard Alpe if (nla_put_u32(skb, TIPC_NLA_PUBL_KEY, publ->key)) 27311a1a143dSRichard Alpe goto attr_msg_cancel; 27321a1a143dSRichard Alpe if (nla_put_u32(skb, TIPC_NLA_PUBL_TYPE, publ->type)) 27331a1a143dSRichard Alpe goto attr_msg_cancel; 27341a1a143dSRichard Alpe if (nla_put_u32(skb, TIPC_NLA_PUBL_LOWER, publ->lower)) 27351a1a143dSRichard Alpe goto attr_msg_cancel; 27361a1a143dSRichard Alpe if (nla_put_u32(skb, TIPC_NLA_PUBL_UPPER, publ->upper)) 27371a1a143dSRichard Alpe goto attr_msg_cancel; 27381a1a143dSRichard Alpe 27391a1a143dSRichard Alpe nla_nest_end(skb, attrs); 27401a1a143dSRichard Alpe genlmsg_end(skb, hdr); 27411a1a143dSRichard Alpe 27421a1a143dSRichard Alpe return 0; 27431a1a143dSRichard Alpe 27441a1a143dSRichard Alpe attr_msg_cancel: 27451a1a143dSRichard Alpe nla_nest_cancel(skb, attrs); 27461a1a143dSRichard Alpe genlmsg_cancel: 27471a1a143dSRichard Alpe genlmsg_cancel(skb, hdr); 27481a1a143dSRichard Alpe msg_cancel: 27491a1a143dSRichard Alpe return -EMSGSIZE; 27501a1a143dSRichard Alpe } 27511a1a143dSRichard Alpe 27521a1a143dSRichard Alpe /* Caller should hold socket lock for the passed tipc socket. */ 2753d8182804SRichard Alpe static int __tipc_nl_list_sk_publ(struct sk_buff *skb, 2754d8182804SRichard Alpe struct netlink_callback *cb, 27551a1a143dSRichard Alpe struct tipc_sock *tsk, u32 *last_publ) 27561a1a143dSRichard Alpe { 27571a1a143dSRichard Alpe int err; 27581a1a143dSRichard Alpe struct publication *p; 27591a1a143dSRichard Alpe 27601a1a143dSRichard Alpe if (*last_publ) { 27611a1a143dSRichard Alpe list_for_each_entry(p, &tsk->publications, pport_list) { 27621a1a143dSRichard Alpe if (p->key == *last_publ) 27631a1a143dSRichard Alpe break; 27641a1a143dSRichard Alpe } 27651a1a143dSRichard Alpe if (p->key != *last_publ) { 27661a1a143dSRichard Alpe /* We never set seq or call nl_dump_check_consistent() 27671a1a143dSRichard Alpe * this means that setting prev_seq here will cause the 27681a1a143dSRichard Alpe * consistence check to fail in the netlink callback 27691a1a143dSRichard Alpe * handler. Resulting in the last NLMSG_DONE message 27701a1a143dSRichard Alpe * having the NLM_F_DUMP_INTR flag set. 27711a1a143dSRichard Alpe */ 27721a1a143dSRichard Alpe cb->prev_seq = 1; 27731a1a143dSRichard Alpe *last_publ = 0; 27741a1a143dSRichard Alpe return -EPIPE; 27751a1a143dSRichard Alpe } 27761a1a143dSRichard Alpe } else { 27771a1a143dSRichard Alpe p = list_first_entry(&tsk->publications, struct publication, 27781a1a143dSRichard Alpe pport_list); 27791a1a143dSRichard Alpe } 27801a1a143dSRichard Alpe 27811a1a143dSRichard Alpe list_for_each_entry_from(p, &tsk->publications, pport_list) { 27821a1a143dSRichard Alpe err = __tipc_nl_add_sk_publ(skb, cb, p); 27831a1a143dSRichard Alpe if (err) { 27841a1a143dSRichard Alpe *last_publ = p->key; 27851a1a143dSRichard Alpe return err; 27861a1a143dSRichard Alpe } 27871a1a143dSRichard Alpe } 27881a1a143dSRichard Alpe *last_publ = 0; 27891a1a143dSRichard Alpe 27901a1a143dSRichard Alpe return 0; 27911a1a143dSRichard Alpe } 27921a1a143dSRichard Alpe 27931a1a143dSRichard Alpe int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb) 27941a1a143dSRichard Alpe { 27951a1a143dSRichard Alpe int err; 279607f6c4bcSYing Xue u32 tsk_portid = cb->args[0]; 27971a1a143dSRichard Alpe u32 last_publ = cb->args[1]; 27981a1a143dSRichard Alpe u32 done = cb->args[2]; 2799e05b31f4SYing Xue struct net *net = sock_net(skb->sk); 28001a1a143dSRichard Alpe struct tipc_sock *tsk; 28011a1a143dSRichard Alpe 280207f6c4bcSYing Xue if (!tsk_portid) { 28031a1a143dSRichard Alpe struct nlattr **attrs; 28041a1a143dSRichard Alpe struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1]; 28051a1a143dSRichard Alpe 28061a1a143dSRichard Alpe err = tipc_nlmsg_parse(cb->nlh, &attrs); 28071a1a143dSRichard Alpe if (err) 28081a1a143dSRichard Alpe return err; 28091a1a143dSRichard Alpe 28101a1a143dSRichard Alpe err = nla_parse_nested(sock, TIPC_NLA_SOCK_MAX, 28111a1a143dSRichard Alpe attrs[TIPC_NLA_SOCK], 28121a1a143dSRichard Alpe tipc_nl_sock_policy); 28131a1a143dSRichard Alpe if (err) 28141a1a143dSRichard Alpe return err; 28151a1a143dSRichard Alpe 28161a1a143dSRichard Alpe if (!sock[TIPC_NLA_SOCK_REF]) 28171a1a143dSRichard Alpe return -EINVAL; 28181a1a143dSRichard Alpe 281907f6c4bcSYing Xue tsk_portid = nla_get_u32(sock[TIPC_NLA_SOCK_REF]); 28201a1a143dSRichard Alpe } 28211a1a143dSRichard Alpe 28221a1a143dSRichard Alpe if (done) 28231a1a143dSRichard Alpe return 0; 28241a1a143dSRichard Alpe 2825e05b31f4SYing Xue tsk = tipc_sk_lookup(net, tsk_portid); 28261a1a143dSRichard Alpe if (!tsk) 28271a1a143dSRichard Alpe return -EINVAL; 28281a1a143dSRichard Alpe 28291a1a143dSRichard Alpe lock_sock(&tsk->sk); 28301a1a143dSRichard Alpe err = __tipc_nl_list_sk_publ(skb, cb, tsk, &last_publ); 28311a1a143dSRichard Alpe if (!err) 28321a1a143dSRichard Alpe done = 1; 28331a1a143dSRichard Alpe release_sock(&tsk->sk); 283407f6c4bcSYing Xue sock_put(&tsk->sk); 28351a1a143dSRichard Alpe 283607f6c4bcSYing Xue cb->args[0] = tsk_portid; 28371a1a143dSRichard Alpe cb->args[1] = last_publ; 28381a1a143dSRichard Alpe cb->args[2] = done; 28391a1a143dSRichard Alpe 28401a1a143dSRichard Alpe return skb->len; 28411a1a143dSRichard Alpe } 2842