18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * net/tipc/link.c: TIPC link code 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 1996-2007, 2012-2016, Ericsson AB 58c2ecf20Sopenharmony_ci * Copyright (c) 2004-2007, 2010-2013, Wind River Systems 68c2ecf20Sopenharmony_ci * All rights reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 128c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 148c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 158c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 168c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its 178c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived from 188c2ecf20Sopenharmony_ci * this software without specific prior written permission. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 228c2ecf20Sopenharmony_ci * Software Foundation. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 268c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 278c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 288c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 318c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 328c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 338c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 348c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "core.h" 388c2ecf20Sopenharmony_ci#include "subscr.h" 398c2ecf20Sopenharmony_ci#include "link.h" 408c2ecf20Sopenharmony_ci#include "bcast.h" 418c2ecf20Sopenharmony_ci#include "socket.h" 428c2ecf20Sopenharmony_ci#include "name_distr.h" 438c2ecf20Sopenharmony_ci#include "discover.h" 448c2ecf20Sopenharmony_ci#include "netlink.h" 458c2ecf20Sopenharmony_ci#include "monitor.h" 468c2ecf20Sopenharmony_ci#include "trace.h" 478c2ecf20Sopenharmony_ci#include "crypto.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <linux/pkt_sched.h> 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct tipc_stats { 528c2ecf20Sopenharmony_ci u32 sent_pkts; 538c2ecf20Sopenharmony_ci u32 recv_pkts; 548c2ecf20Sopenharmony_ci u32 sent_states; 558c2ecf20Sopenharmony_ci u32 recv_states; 568c2ecf20Sopenharmony_ci u32 sent_probes; 578c2ecf20Sopenharmony_ci u32 recv_probes; 588c2ecf20Sopenharmony_ci u32 sent_nacks; 598c2ecf20Sopenharmony_ci u32 recv_nacks; 608c2ecf20Sopenharmony_ci u32 sent_acks; 618c2ecf20Sopenharmony_ci u32 sent_bundled; 628c2ecf20Sopenharmony_ci u32 sent_bundles; 638c2ecf20Sopenharmony_ci u32 recv_bundled; 648c2ecf20Sopenharmony_ci u32 recv_bundles; 658c2ecf20Sopenharmony_ci u32 retransmitted; 668c2ecf20Sopenharmony_ci u32 sent_fragmented; 678c2ecf20Sopenharmony_ci u32 sent_fragments; 688c2ecf20Sopenharmony_ci u32 recv_fragmented; 698c2ecf20Sopenharmony_ci u32 recv_fragments; 708c2ecf20Sopenharmony_ci u32 link_congs; /* # port sends blocked by congestion */ 718c2ecf20Sopenharmony_ci u32 deferred_recv; 728c2ecf20Sopenharmony_ci u32 duplicates; 738c2ecf20Sopenharmony_ci u32 max_queue_sz; /* send queue size high water mark */ 748c2ecf20Sopenharmony_ci u32 accu_queue_sz; /* used for send queue size profiling */ 758c2ecf20Sopenharmony_ci u32 queue_sz_counts; /* used for send queue size profiling */ 768c2ecf20Sopenharmony_ci u32 msg_length_counts; /* used for message length profiling */ 778c2ecf20Sopenharmony_ci u32 msg_lengths_total; /* used for message length profiling */ 788c2ecf20Sopenharmony_ci u32 msg_length_profile[7]; /* used for msg. length profiling */ 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/** 828c2ecf20Sopenharmony_ci * struct tipc_link - TIPC link data structure 838c2ecf20Sopenharmony_ci * @addr: network address of link's peer node 848c2ecf20Sopenharmony_ci * @name: link name character string 858c2ecf20Sopenharmony_ci * @media_addr: media address to use when sending messages over link 868c2ecf20Sopenharmony_ci * @timer: link timer 878c2ecf20Sopenharmony_ci * @net: pointer to namespace struct 888c2ecf20Sopenharmony_ci * @refcnt: reference counter for permanent references (owner node & timer) 898c2ecf20Sopenharmony_ci * @peer_session: link session # being used by peer end of link 908c2ecf20Sopenharmony_ci * @peer_bearer_id: bearer id used by link's peer endpoint 918c2ecf20Sopenharmony_ci * @bearer_id: local bearer id used by link 928c2ecf20Sopenharmony_ci * @tolerance: minimum link continuity loss needed to reset link [in ms] 938c2ecf20Sopenharmony_ci * @abort_limit: # of unacknowledged continuity probes needed to reset link 948c2ecf20Sopenharmony_ci * @state: current state of link FSM 958c2ecf20Sopenharmony_ci * @peer_caps: bitmap describing capabilities of peer node 968c2ecf20Sopenharmony_ci * @silent_intv_cnt: # of timer intervals without any reception from peer 978c2ecf20Sopenharmony_ci * @proto_msg: template for control messages generated by link 988c2ecf20Sopenharmony_ci * @pmsg: convenience pointer to "proto_msg" field 998c2ecf20Sopenharmony_ci * @priority: current link priority 1008c2ecf20Sopenharmony_ci * @net_plane: current link network plane ('A' through 'H') 1018c2ecf20Sopenharmony_ci * @mon_state: cookie with information needed by link monitor 1028c2ecf20Sopenharmony_ci * @backlog_limit: backlog queue congestion thresholds (indexed by importance) 1038c2ecf20Sopenharmony_ci * @exp_msg_count: # of tunnelled messages expected during link changeover 1048c2ecf20Sopenharmony_ci * @reset_rcv_checkpt: seq # of last acknowledged message at time of link reset 1058c2ecf20Sopenharmony_ci * @mtu: current maximum packet size for this link 1068c2ecf20Sopenharmony_ci * @advertised_mtu: advertised own mtu when link is being established 1078c2ecf20Sopenharmony_ci * @transmitq: queue for sent, non-acked messages 1088c2ecf20Sopenharmony_ci * @backlogq: queue for messages waiting to be sent 1098c2ecf20Sopenharmony_ci * @snt_nxt: next sequence number to use for outbound messages 1108c2ecf20Sopenharmony_ci * @ackers: # of peers that needs to ack each packet before it can be released 1118c2ecf20Sopenharmony_ci * @acked: # last packet acked by a certain peer. Used for broadcast. 1128c2ecf20Sopenharmony_ci * @rcv_nxt: next sequence number to expect for inbound messages 1138c2ecf20Sopenharmony_ci * @deferred_queue: deferred queue saved OOS b'cast message received from node 1148c2ecf20Sopenharmony_ci * @unacked_window: # of inbound messages rx'd without ack'ing back to peer 1158c2ecf20Sopenharmony_ci * @inputq: buffer queue for messages to be delivered upwards 1168c2ecf20Sopenharmony_ci * @namedq: buffer queue for name table messages to be delivered upwards 1178c2ecf20Sopenharmony_ci * @next_out: ptr to first unsent outbound message in queue 1188c2ecf20Sopenharmony_ci * @wakeupq: linked list of wakeup msgs waiting for link congestion to abate 1198c2ecf20Sopenharmony_ci * @long_msg_seq_no: next identifier to use for outbound fragmented messages 1208c2ecf20Sopenharmony_ci * @reasm_buf: head of partially reassembled inbound message fragments 1218c2ecf20Sopenharmony_ci * @bc_rcvr: marks that this is a broadcast receiver link 1228c2ecf20Sopenharmony_ci * @stats: collects statistics regarding link activity 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cistruct tipc_link { 1258c2ecf20Sopenharmony_ci u32 addr; 1268c2ecf20Sopenharmony_ci char name[TIPC_MAX_LINK_NAME]; 1278c2ecf20Sopenharmony_ci struct net *net; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Management and link supervision data */ 1308c2ecf20Sopenharmony_ci u16 peer_session; 1318c2ecf20Sopenharmony_ci u16 session; 1328c2ecf20Sopenharmony_ci u16 snd_nxt_state; 1338c2ecf20Sopenharmony_ci u16 rcv_nxt_state; 1348c2ecf20Sopenharmony_ci u32 peer_bearer_id; 1358c2ecf20Sopenharmony_ci u32 bearer_id; 1368c2ecf20Sopenharmony_ci u32 tolerance; 1378c2ecf20Sopenharmony_ci u32 abort_limit; 1388c2ecf20Sopenharmony_ci u32 state; 1398c2ecf20Sopenharmony_ci u16 peer_caps; 1408c2ecf20Sopenharmony_ci bool in_session; 1418c2ecf20Sopenharmony_ci bool active; 1428c2ecf20Sopenharmony_ci u32 silent_intv_cnt; 1438c2ecf20Sopenharmony_ci char if_name[TIPC_MAX_IF_NAME]; 1448c2ecf20Sopenharmony_ci u32 priority; 1458c2ecf20Sopenharmony_ci char net_plane; 1468c2ecf20Sopenharmony_ci struct tipc_mon_state mon_state; 1478c2ecf20Sopenharmony_ci u16 rst_cnt; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Failover/synch */ 1508c2ecf20Sopenharmony_ci u16 drop_point; 1518c2ecf20Sopenharmony_ci struct sk_buff *failover_reasm_skb; 1528c2ecf20Sopenharmony_ci struct sk_buff_head failover_deferdq; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Max packet negotiation */ 1558c2ecf20Sopenharmony_ci u16 mtu; 1568c2ecf20Sopenharmony_ci u16 advertised_mtu; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* Sending */ 1598c2ecf20Sopenharmony_ci struct sk_buff_head transmq; 1608c2ecf20Sopenharmony_ci struct sk_buff_head backlogq; 1618c2ecf20Sopenharmony_ci struct { 1628c2ecf20Sopenharmony_ci u16 len; 1638c2ecf20Sopenharmony_ci u16 limit; 1648c2ecf20Sopenharmony_ci struct sk_buff *target_bskb; 1658c2ecf20Sopenharmony_ci } backlog[5]; 1668c2ecf20Sopenharmony_ci u16 snd_nxt; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Reception */ 1698c2ecf20Sopenharmony_ci u16 rcv_nxt; 1708c2ecf20Sopenharmony_ci u32 rcv_unacked; 1718c2ecf20Sopenharmony_ci struct sk_buff_head deferdq; 1728c2ecf20Sopenharmony_ci struct sk_buff_head *inputq; 1738c2ecf20Sopenharmony_ci struct sk_buff_head *namedq; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Congestion handling */ 1768c2ecf20Sopenharmony_ci struct sk_buff_head wakeupq; 1778c2ecf20Sopenharmony_ci u16 window; 1788c2ecf20Sopenharmony_ci u16 min_win; 1798c2ecf20Sopenharmony_ci u16 ssthresh; 1808c2ecf20Sopenharmony_ci u16 max_win; 1818c2ecf20Sopenharmony_ci u16 cong_acks; 1828c2ecf20Sopenharmony_ci u16 checkpoint; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Fragmentation/reassembly */ 1858c2ecf20Sopenharmony_ci struct sk_buff *reasm_buf; 1868c2ecf20Sopenharmony_ci struct sk_buff *reasm_tnlmsg; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Broadcast */ 1898c2ecf20Sopenharmony_ci u16 ackers; 1908c2ecf20Sopenharmony_ci u16 acked; 1918c2ecf20Sopenharmony_ci u16 last_gap; 1928c2ecf20Sopenharmony_ci struct tipc_gap_ack_blks *last_ga; 1938c2ecf20Sopenharmony_ci struct tipc_link *bc_rcvlink; 1948c2ecf20Sopenharmony_ci struct tipc_link *bc_sndlink; 1958c2ecf20Sopenharmony_ci u8 nack_state; 1968c2ecf20Sopenharmony_ci bool bc_peer_is_up; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* Statistics */ 1998c2ecf20Sopenharmony_ci struct tipc_stats stats; 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* 2038c2ecf20Sopenharmony_ci * Error message prefixes 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic const char *link_co_err = "Link tunneling error, "; 2068c2ecf20Sopenharmony_cistatic const char *link_rst_msg = "Resetting link "; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* Send states for broadcast NACKs 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_cienum { 2118c2ecf20Sopenharmony_ci BC_NACK_SND_CONDITIONAL, 2128c2ecf20Sopenharmony_ci BC_NACK_SND_UNCONDITIONAL, 2138c2ecf20Sopenharmony_ci BC_NACK_SND_SUPPRESS, 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#define TIPC_BC_RETR_LIM (jiffies + msecs_to_jiffies(10)) 2178c2ecf20Sopenharmony_ci#define TIPC_UC_RETR_TIME (jiffies + msecs_to_jiffies(1)) 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* Link FSM states: 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_cienum { 2228c2ecf20Sopenharmony_ci LINK_ESTABLISHED = 0xe, 2238c2ecf20Sopenharmony_ci LINK_ESTABLISHING = 0xe << 4, 2248c2ecf20Sopenharmony_ci LINK_RESET = 0x1 << 8, 2258c2ecf20Sopenharmony_ci LINK_RESETTING = 0x2 << 12, 2268c2ecf20Sopenharmony_ci LINK_PEER_RESET = 0xd << 16, 2278c2ecf20Sopenharmony_ci LINK_FAILINGOVER = 0xf << 20, 2288c2ecf20Sopenharmony_ci LINK_SYNCHING = 0xc << 24 2298c2ecf20Sopenharmony_ci}; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* Link FSM state checking routines 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_cistatic int link_is_up(struct tipc_link *l) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci return l->state & (LINK_ESTABLISHED | LINK_SYNCHING); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, 2398c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq); 2408c2ecf20Sopenharmony_cistatic void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, 2418c2ecf20Sopenharmony_ci bool probe_reply, u16 rcvgap, 2428c2ecf20Sopenharmony_ci int tolerance, int priority, 2438c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq); 2448c2ecf20Sopenharmony_cistatic void link_print(struct tipc_link *l, const char *str); 2458c2ecf20Sopenharmony_cistatic int tipc_link_build_nack_msg(struct tipc_link *l, 2468c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq); 2478c2ecf20Sopenharmony_cistatic void tipc_link_build_bc_init_msg(struct tipc_link *l, 2488c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq); 2498c2ecf20Sopenharmony_cistatic u8 __tipc_build_gap_ack_blks(struct tipc_gap_ack_blks *ga, 2508c2ecf20Sopenharmony_ci struct tipc_link *l, u8 start_index); 2518c2ecf20Sopenharmony_cistatic u16 tipc_build_gap_ack_blks(struct tipc_link *l, struct tipc_msg *hdr); 2528c2ecf20Sopenharmony_cistatic int tipc_link_advance_transmq(struct tipc_link *l, struct tipc_link *r, 2538c2ecf20Sopenharmony_ci u16 acked, u16 gap, 2548c2ecf20Sopenharmony_ci struct tipc_gap_ack_blks *ga, 2558c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq, 2568c2ecf20Sopenharmony_ci bool *retransmitted, int *rc); 2578c2ecf20Sopenharmony_cistatic void tipc_link_update_cwin(struct tipc_link *l, int released, 2588c2ecf20Sopenharmony_ci bool retransmitted); 2598c2ecf20Sopenharmony_ci/* 2608c2ecf20Sopenharmony_ci * Simple non-static link routines (i.e. referenced outside this file) 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_cibool tipc_link_is_up(struct tipc_link *l) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci return link_is_up(l); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cibool tipc_link_peer_is_down(struct tipc_link *l) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci return l->state == LINK_PEER_RESET; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cibool tipc_link_is_reset(struct tipc_link *l) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci return l->state & (LINK_RESET | LINK_FAILINGOVER | LINK_ESTABLISHING); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cibool tipc_link_is_establishing(struct tipc_link *l) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci return l->state == LINK_ESTABLISHING; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cibool tipc_link_is_synching(struct tipc_link *l) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci return l->state == LINK_SYNCHING; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cibool tipc_link_is_failingover(struct tipc_link *l) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci return l->state == LINK_FAILINGOVER; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cibool tipc_link_is_blocked(struct tipc_link *l) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci return l->state & (LINK_RESETTING | LINK_PEER_RESET | LINK_FAILINGOVER); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic bool link_is_bc_sndlink(struct tipc_link *l) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci return !l->bc_sndlink; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic bool link_is_bc_rcvlink(struct tipc_link *l) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci return ((l->bc_rcvlink == l) && !link_is_bc_sndlink(l)); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_civoid tipc_link_set_active(struct tipc_link *l, bool active) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci l->active = active; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ciu32 tipc_link_id(struct tipc_link *l) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci return l->peer_bearer_id << 16 | l->bearer_id; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciint tipc_link_min_win(struct tipc_link *l) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci return l->min_win; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciint tipc_link_max_win(struct tipc_link *l) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci return l->max_win; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ciint tipc_link_prio(struct tipc_link *l) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci return l->priority; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ciunsigned long tipc_link_tolerance(struct tipc_link *l) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci return l->tolerance; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistruct sk_buff_head *tipc_link_inputq(struct tipc_link *l) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci return l->inputq; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cichar tipc_link_plane(struct tipc_link *l) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci return l->net_plane; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistruct net *tipc_link_net(struct tipc_link *l) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci return l->net; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_civoid tipc_link_update_caps(struct tipc_link *l, u16 capabilities) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci l->peer_caps = capabilities; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_civoid tipc_link_add_bc_peer(struct tipc_link *snd_l, 3588c2ecf20Sopenharmony_ci struct tipc_link *uc_l, 3598c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct tipc_link *rcv_l = uc_l->bc_rcvlink; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci snd_l->ackers++; 3648c2ecf20Sopenharmony_ci rcv_l->acked = snd_l->snd_nxt - 1; 3658c2ecf20Sopenharmony_ci snd_l->state = LINK_ESTABLISHED; 3668c2ecf20Sopenharmony_ci tipc_link_build_bc_init_msg(uc_l, xmitq); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_civoid tipc_link_remove_bc_peer(struct tipc_link *snd_l, 3708c2ecf20Sopenharmony_ci struct tipc_link *rcv_l, 3718c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci u16 ack = snd_l->snd_nxt - 1; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci snd_l->ackers--; 3768c2ecf20Sopenharmony_ci rcv_l->bc_peer_is_up = true; 3778c2ecf20Sopenharmony_ci rcv_l->state = LINK_ESTABLISHED; 3788c2ecf20Sopenharmony_ci tipc_link_bc_ack_rcv(rcv_l, ack, 0, NULL, xmitq, NULL); 3798c2ecf20Sopenharmony_ci trace_tipc_link_reset(rcv_l, TIPC_DUMP_ALL, "bclink removed!"); 3808c2ecf20Sopenharmony_ci tipc_link_reset(rcv_l); 3818c2ecf20Sopenharmony_ci rcv_l->state = LINK_RESET; 3828c2ecf20Sopenharmony_ci if (!snd_l->ackers) { 3838c2ecf20Sopenharmony_ci trace_tipc_link_reset(snd_l, TIPC_DUMP_ALL, "zero ackers!"); 3848c2ecf20Sopenharmony_ci tipc_link_reset(snd_l); 3858c2ecf20Sopenharmony_ci snd_l->state = LINK_RESET; 3868c2ecf20Sopenharmony_ci __skb_queue_purge(xmitq); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciint tipc_link_bc_peers(struct tipc_link *l) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci return l->ackers; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic u16 link_bc_rcv_gap(struct tipc_link *l) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct sk_buff *skb = skb_peek(&l->deferdq); 3988c2ecf20Sopenharmony_ci u16 gap = 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (more(l->snd_nxt, l->rcv_nxt)) 4018c2ecf20Sopenharmony_ci gap = l->snd_nxt - l->rcv_nxt; 4028c2ecf20Sopenharmony_ci if (skb) 4038c2ecf20Sopenharmony_ci gap = buf_seqno(skb) - l->rcv_nxt; 4048c2ecf20Sopenharmony_ci return gap; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_civoid tipc_link_set_mtu(struct tipc_link *l, int mtu) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci l->mtu = mtu; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ciint tipc_link_mtu(struct tipc_link *l) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci return l->mtu; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciint tipc_link_mss(struct tipc_link *l) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 4208c2ecf20Sopenharmony_ci return l->mtu - INT_H_SIZE - EMSG_OVERHEAD; 4218c2ecf20Sopenharmony_ci#else 4228c2ecf20Sopenharmony_ci return l->mtu - INT_H_SIZE; 4238c2ecf20Sopenharmony_ci#endif 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ciu16 tipc_link_rcv_nxt(struct tipc_link *l) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci return l->rcv_nxt; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ciu16 tipc_link_acked(struct tipc_link *l) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci return l->acked; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cichar *tipc_link_name(struct tipc_link *l) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci return l->name; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciu32 tipc_link_state(struct tipc_link *l) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci return l->state; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/** 4478c2ecf20Sopenharmony_ci * tipc_link_create - create a new link 4488c2ecf20Sopenharmony_ci * @net: pointer to associated network namespace 4498c2ecf20Sopenharmony_ci * @if_name: associated interface name 4508c2ecf20Sopenharmony_ci * @bearer_id: id (index) of associated bearer 4518c2ecf20Sopenharmony_ci * @tolerance: link tolerance to be used by link 4528c2ecf20Sopenharmony_ci * @net_plane: network plane (A,B,c..) this link belongs to 4538c2ecf20Sopenharmony_ci * @mtu: mtu to be advertised by link 4548c2ecf20Sopenharmony_ci * @priority: priority to be used by link 4558c2ecf20Sopenharmony_ci * @min_win: minimal send window to be used by link 4568c2ecf20Sopenharmony_ci * @max_win: maximal send window to be used by link 4578c2ecf20Sopenharmony_ci * @session: session to be used by link 4588c2ecf20Sopenharmony_ci * @ownnode: identity of own node 4598c2ecf20Sopenharmony_ci * @peer: node id of peer node 4608c2ecf20Sopenharmony_ci * @peer_caps: bitmap describing peer node capabilities 4618c2ecf20Sopenharmony_ci * @bc_sndlink: the namespace global link used for broadcast sending 4628c2ecf20Sopenharmony_ci * @bc_rcvlink: the peer specific link used for broadcast reception 4638c2ecf20Sopenharmony_ci * @inputq: queue to put messages ready for delivery 4648c2ecf20Sopenharmony_ci * @namedq: queue to put binding table update messages ready for delivery 4658c2ecf20Sopenharmony_ci * @link: return value, pointer to put the created link 4668c2ecf20Sopenharmony_ci * 4678c2ecf20Sopenharmony_ci * Returns true if link was created, otherwise false 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_cibool tipc_link_create(struct net *net, char *if_name, int bearer_id, 4708c2ecf20Sopenharmony_ci int tolerance, char net_plane, u32 mtu, int priority, 4718c2ecf20Sopenharmony_ci u32 min_win, u32 max_win, u32 session, u32 self, 4728c2ecf20Sopenharmony_ci u32 peer, u8 *peer_id, u16 peer_caps, 4738c2ecf20Sopenharmony_ci struct tipc_link *bc_sndlink, 4748c2ecf20Sopenharmony_ci struct tipc_link *bc_rcvlink, 4758c2ecf20Sopenharmony_ci struct sk_buff_head *inputq, 4768c2ecf20Sopenharmony_ci struct sk_buff_head *namedq, 4778c2ecf20Sopenharmony_ci struct tipc_link **link) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci char peer_str[NODE_ID_STR_LEN] = {0,}; 4808c2ecf20Sopenharmony_ci char self_str[NODE_ID_STR_LEN] = {0,}; 4818c2ecf20Sopenharmony_ci struct tipc_link *l; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci l = kzalloc(sizeof(*l), GFP_ATOMIC); 4848c2ecf20Sopenharmony_ci if (!l) 4858c2ecf20Sopenharmony_ci return false; 4868c2ecf20Sopenharmony_ci *link = l; 4878c2ecf20Sopenharmony_ci l->session = session; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* Set link name for unicast links only */ 4908c2ecf20Sopenharmony_ci if (peer_id) { 4918c2ecf20Sopenharmony_ci tipc_nodeid2string(self_str, tipc_own_id(net)); 4928c2ecf20Sopenharmony_ci if (strlen(self_str) > 16) 4938c2ecf20Sopenharmony_ci sprintf(self_str, "%x", self); 4948c2ecf20Sopenharmony_ci tipc_nodeid2string(peer_str, peer_id); 4958c2ecf20Sopenharmony_ci if (strlen(peer_str) > 16) 4968c2ecf20Sopenharmony_ci sprintf(peer_str, "%x", peer); 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci /* Peer i/f name will be completed by reset/activate message */ 4998c2ecf20Sopenharmony_ci snprintf(l->name, sizeof(l->name), "%s:%s-%s:unknown", 5008c2ecf20Sopenharmony_ci self_str, if_name, peer_str); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci strcpy(l->if_name, if_name); 5038c2ecf20Sopenharmony_ci l->addr = peer; 5048c2ecf20Sopenharmony_ci l->peer_caps = peer_caps; 5058c2ecf20Sopenharmony_ci l->net = net; 5068c2ecf20Sopenharmony_ci l->in_session = false; 5078c2ecf20Sopenharmony_ci l->bearer_id = bearer_id; 5088c2ecf20Sopenharmony_ci l->tolerance = tolerance; 5098c2ecf20Sopenharmony_ci if (bc_rcvlink) 5108c2ecf20Sopenharmony_ci bc_rcvlink->tolerance = tolerance; 5118c2ecf20Sopenharmony_ci l->net_plane = net_plane; 5128c2ecf20Sopenharmony_ci l->advertised_mtu = mtu; 5138c2ecf20Sopenharmony_ci l->mtu = mtu; 5148c2ecf20Sopenharmony_ci l->priority = priority; 5158c2ecf20Sopenharmony_ci tipc_link_set_queue_limits(l, min_win, max_win); 5168c2ecf20Sopenharmony_ci l->ackers = 1; 5178c2ecf20Sopenharmony_ci l->bc_sndlink = bc_sndlink; 5188c2ecf20Sopenharmony_ci l->bc_rcvlink = bc_rcvlink; 5198c2ecf20Sopenharmony_ci l->inputq = inputq; 5208c2ecf20Sopenharmony_ci l->namedq = namedq; 5218c2ecf20Sopenharmony_ci l->state = LINK_RESETTING; 5228c2ecf20Sopenharmony_ci __skb_queue_head_init(&l->transmq); 5238c2ecf20Sopenharmony_ci __skb_queue_head_init(&l->backlogq); 5248c2ecf20Sopenharmony_ci __skb_queue_head_init(&l->deferdq); 5258c2ecf20Sopenharmony_ci __skb_queue_head_init(&l->failover_deferdq); 5268c2ecf20Sopenharmony_ci skb_queue_head_init(&l->wakeupq); 5278c2ecf20Sopenharmony_ci skb_queue_head_init(l->inputq); 5288c2ecf20Sopenharmony_ci return true; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/** 5328c2ecf20Sopenharmony_ci * tipc_link_bc_create - create new link to be used for broadcast 5338c2ecf20Sopenharmony_ci * @net: pointer to associated network namespace 5348c2ecf20Sopenharmony_ci * @mtu: mtu to be used initially if no peers 5358c2ecf20Sopenharmony_ci * @min_win: minimal send window to be used by link 5368c2ecf20Sopenharmony_ci * @max_win: maximal send window to be used by link 5378c2ecf20Sopenharmony_ci * @inputq: queue to put messages ready for delivery 5388c2ecf20Sopenharmony_ci * @namedq: queue to put binding table update messages ready for delivery 5398c2ecf20Sopenharmony_ci * @link: return value, pointer to put the created link 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * Returns true if link was created, otherwise false 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_cibool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer, u8 *peer_id, 5448c2ecf20Sopenharmony_ci int mtu, u32 min_win, u32 max_win, u16 peer_caps, 5458c2ecf20Sopenharmony_ci struct sk_buff_head *inputq, 5468c2ecf20Sopenharmony_ci struct sk_buff_head *namedq, 5478c2ecf20Sopenharmony_ci struct tipc_link *bc_sndlink, 5488c2ecf20Sopenharmony_ci struct tipc_link **link) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct tipc_link *l; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (!tipc_link_create(net, "", MAX_BEARERS, 0, 'Z', mtu, 0, min_win, 5538c2ecf20Sopenharmony_ci max_win, 0, ownnode, peer, NULL, peer_caps, 5548c2ecf20Sopenharmony_ci bc_sndlink, NULL, inputq, namedq, link)) 5558c2ecf20Sopenharmony_ci return false; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci l = *link; 5588c2ecf20Sopenharmony_ci if (peer_id) { 5598c2ecf20Sopenharmony_ci char peer_str[NODE_ID_STR_LEN] = {0,}; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci tipc_nodeid2string(peer_str, peer_id); 5628c2ecf20Sopenharmony_ci if (strlen(peer_str) > 16) 5638c2ecf20Sopenharmony_ci sprintf(peer_str, "%x", peer); 5648c2ecf20Sopenharmony_ci /* Broadcast receiver link name: "broadcast-link:<peer>" */ 5658c2ecf20Sopenharmony_ci snprintf(l->name, sizeof(l->name), "%s:%s", tipc_bclink_name, 5668c2ecf20Sopenharmony_ci peer_str); 5678c2ecf20Sopenharmony_ci } else { 5688c2ecf20Sopenharmony_ci strcpy(l->name, tipc_bclink_name); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci trace_tipc_link_reset(l, TIPC_DUMP_ALL, "bclink created!"); 5718c2ecf20Sopenharmony_ci tipc_link_reset(l); 5728c2ecf20Sopenharmony_ci l->state = LINK_RESET; 5738c2ecf20Sopenharmony_ci l->ackers = 0; 5748c2ecf20Sopenharmony_ci l->bc_rcvlink = l; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* Broadcast send link is always up */ 5778c2ecf20Sopenharmony_ci if (link_is_bc_sndlink(l)) 5788c2ecf20Sopenharmony_ci l->state = LINK_ESTABLISHED; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* Disable replicast if even a single peer doesn't support it */ 5818c2ecf20Sopenharmony_ci if (link_is_bc_rcvlink(l) && !(peer_caps & TIPC_BCAST_RCAST)) 5828c2ecf20Sopenharmony_ci tipc_bcast_toggle_rcast(net, false); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return true; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/** 5888c2ecf20Sopenharmony_ci * tipc_link_fsm_evt - link finite state machine 5898c2ecf20Sopenharmony_ci * @l: pointer to link 5908c2ecf20Sopenharmony_ci * @evt: state machine event to be processed 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ciint tipc_link_fsm_evt(struct tipc_link *l, int evt) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci int rc = 0; 5958c2ecf20Sopenharmony_ci int old_state = l->state; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci switch (l->state) { 5988c2ecf20Sopenharmony_ci case LINK_RESETTING: 5998c2ecf20Sopenharmony_ci switch (evt) { 6008c2ecf20Sopenharmony_ci case LINK_PEER_RESET_EVT: 6018c2ecf20Sopenharmony_ci l->state = LINK_PEER_RESET; 6028c2ecf20Sopenharmony_ci break; 6038c2ecf20Sopenharmony_ci case LINK_RESET_EVT: 6048c2ecf20Sopenharmony_ci l->state = LINK_RESET; 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci case LINK_FAILURE_EVT: 6078c2ecf20Sopenharmony_ci case LINK_FAILOVER_BEGIN_EVT: 6088c2ecf20Sopenharmony_ci case LINK_ESTABLISH_EVT: 6098c2ecf20Sopenharmony_ci case LINK_FAILOVER_END_EVT: 6108c2ecf20Sopenharmony_ci case LINK_SYNCH_BEGIN_EVT: 6118c2ecf20Sopenharmony_ci case LINK_SYNCH_END_EVT: 6128c2ecf20Sopenharmony_ci default: 6138c2ecf20Sopenharmony_ci goto illegal_evt; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci case LINK_RESET: 6178c2ecf20Sopenharmony_ci switch (evt) { 6188c2ecf20Sopenharmony_ci case LINK_PEER_RESET_EVT: 6198c2ecf20Sopenharmony_ci l->state = LINK_ESTABLISHING; 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci case LINK_FAILOVER_BEGIN_EVT: 6228c2ecf20Sopenharmony_ci l->state = LINK_FAILINGOVER; 6238c2ecf20Sopenharmony_ci case LINK_FAILURE_EVT: 6248c2ecf20Sopenharmony_ci case LINK_RESET_EVT: 6258c2ecf20Sopenharmony_ci case LINK_ESTABLISH_EVT: 6268c2ecf20Sopenharmony_ci case LINK_FAILOVER_END_EVT: 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci case LINK_SYNCH_BEGIN_EVT: 6298c2ecf20Sopenharmony_ci case LINK_SYNCH_END_EVT: 6308c2ecf20Sopenharmony_ci default: 6318c2ecf20Sopenharmony_ci goto illegal_evt; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci case LINK_PEER_RESET: 6358c2ecf20Sopenharmony_ci switch (evt) { 6368c2ecf20Sopenharmony_ci case LINK_RESET_EVT: 6378c2ecf20Sopenharmony_ci l->state = LINK_ESTABLISHING; 6388c2ecf20Sopenharmony_ci break; 6398c2ecf20Sopenharmony_ci case LINK_PEER_RESET_EVT: 6408c2ecf20Sopenharmony_ci case LINK_ESTABLISH_EVT: 6418c2ecf20Sopenharmony_ci case LINK_FAILURE_EVT: 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci case LINK_SYNCH_BEGIN_EVT: 6448c2ecf20Sopenharmony_ci case LINK_SYNCH_END_EVT: 6458c2ecf20Sopenharmony_ci case LINK_FAILOVER_BEGIN_EVT: 6468c2ecf20Sopenharmony_ci case LINK_FAILOVER_END_EVT: 6478c2ecf20Sopenharmony_ci default: 6488c2ecf20Sopenharmony_ci goto illegal_evt; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci case LINK_FAILINGOVER: 6528c2ecf20Sopenharmony_ci switch (evt) { 6538c2ecf20Sopenharmony_ci case LINK_FAILOVER_END_EVT: 6548c2ecf20Sopenharmony_ci l->state = LINK_RESET; 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci case LINK_PEER_RESET_EVT: 6578c2ecf20Sopenharmony_ci case LINK_RESET_EVT: 6588c2ecf20Sopenharmony_ci case LINK_ESTABLISH_EVT: 6598c2ecf20Sopenharmony_ci case LINK_FAILURE_EVT: 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case LINK_FAILOVER_BEGIN_EVT: 6628c2ecf20Sopenharmony_ci case LINK_SYNCH_BEGIN_EVT: 6638c2ecf20Sopenharmony_ci case LINK_SYNCH_END_EVT: 6648c2ecf20Sopenharmony_ci default: 6658c2ecf20Sopenharmony_ci goto illegal_evt; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci case LINK_ESTABLISHING: 6698c2ecf20Sopenharmony_ci switch (evt) { 6708c2ecf20Sopenharmony_ci case LINK_ESTABLISH_EVT: 6718c2ecf20Sopenharmony_ci l->state = LINK_ESTABLISHED; 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci case LINK_FAILOVER_BEGIN_EVT: 6748c2ecf20Sopenharmony_ci l->state = LINK_FAILINGOVER; 6758c2ecf20Sopenharmony_ci break; 6768c2ecf20Sopenharmony_ci case LINK_RESET_EVT: 6778c2ecf20Sopenharmony_ci l->state = LINK_RESET; 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci case LINK_FAILURE_EVT: 6808c2ecf20Sopenharmony_ci case LINK_PEER_RESET_EVT: 6818c2ecf20Sopenharmony_ci case LINK_SYNCH_BEGIN_EVT: 6828c2ecf20Sopenharmony_ci case LINK_FAILOVER_END_EVT: 6838c2ecf20Sopenharmony_ci break; 6848c2ecf20Sopenharmony_ci case LINK_SYNCH_END_EVT: 6858c2ecf20Sopenharmony_ci default: 6868c2ecf20Sopenharmony_ci goto illegal_evt; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci case LINK_ESTABLISHED: 6908c2ecf20Sopenharmony_ci switch (evt) { 6918c2ecf20Sopenharmony_ci case LINK_PEER_RESET_EVT: 6928c2ecf20Sopenharmony_ci l->state = LINK_PEER_RESET; 6938c2ecf20Sopenharmony_ci rc |= TIPC_LINK_DOWN_EVT; 6948c2ecf20Sopenharmony_ci break; 6958c2ecf20Sopenharmony_ci case LINK_FAILURE_EVT: 6968c2ecf20Sopenharmony_ci l->state = LINK_RESETTING; 6978c2ecf20Sopenharmony_ci rc |= TIPC_LINK_DOWN_EVT; 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci case LINK_RESET_EVT: 7008c2ecf20Sopenharmony_ci l->state = LINK_RESET; 7018c2ecf20Sopenharmony_ci break; 7028c2ecf20Sopenharmony_ci case LINK_ESTABLISH_EVT: 7038c2ecf20Sopenharmony_ci case LINK_SYNCH_END_EVT: 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci case LINK_SYNCH_BEGIN_EVT: 7068c2ecf20Sopenharmony_ci l->state = LINK_SYNCHING; 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci case LINK_FAILOVER_BEGIN_EVT: 7098c2ecf20Sopenharmony_ci case LINK_FAILOVER_END_EVT: 7108c2ecf20Sopenharmony_ci default: 7118c2ecf20Sopenharmony_ci goto illegal_evt; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci case LINK_SYNCHING: 7158c2ecf20Sopenharmony_ci switch (evt) { 7168c2ecf20Sopenharmony_ci case LINK_PEER_RESET_EVT: 7178c2ecf20Sopenharmony_ci l->state = LINK_PEER_RESET; 7188c2ecf20Sopenharmony_ci rc |= TIPC_LINK_DOWN_EVT; 7198c2ecf20Sopenharmony_ci break; 7208c2ecf20Sopenharmony_ci case LINK_FAILURE_EVT: 7218c2ecf20Sopenharmony_ci l->state = LINK_RESETTING; 7228c2ecf20Sopenharmony_ci rc |= TIPC_LINK_DOWN_EVT; 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci case LINK_RESET_EVT: 7258c2ecf20Sopenharmony_ci l->state = LINK_RESET; 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci case LINK_ESTABLISH_EVT: 7288c2ecf20Sopenharmony_ci case LINK_SYNCH_BEGIN_EVT: 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci case LINK_SYNCH_END_EVT: 7318c2ecf20Sopenharmony_ci l->state = LINK_ESTABLISHED; 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci case LINK_FAILOVER_BEGIN_EVT: 7348c2ecf20Sopenharmony_ci case LINK_FAILOVER_END_EVT: 7358c2ecf20Sopenharmony_ci default: 7368c2ecf20Sopenharmony_ci goto illegal_evt; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci break; 7398c2ecf20Sopenharmony_ci default: 7408c2ecf20Sopenharmony_ci pr_err("Unknown FSM state %x in %s\n", l->state, l->name); 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci trace_tipc_link_fsm(l->name, old_state, l->state, evt); 7438c2ecf20Sopenharmony_ci return rc; 7448c2ecf20Sopenharmony_ciillegal_evt: 7458c2ecf20Sopenharmony_ci pr_err("Illegal FSM event %x in state %x on link %s\n", 7468c2ecf20Sopenharmony_ci evt, l->state, l->name); 7478c2ecf20Sopenharmony_ci trace_tipc_link_fsm(l->name, old_state, l->state, evt); 7488c2ecf20Sopenharmony_ci return rc; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci/* link_profile_stats - update statistical profiling of traffic 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_cistatic void link_profile_stats(struct tipc_link *l) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct sk_buff *skb; 7568c2ecf20Sopenharmony_ci struct tipc_msg *msg; 7578c2ecf20Sopenharmony_ci int length; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* Update counters used in statistical profiling of send traffic */ 7608c2ecf20Sopenharmony_ci l->stats.accu_queue_sz += skb_queue_len(&l->transmq); 7618c2ecf20Sopenharmony_ci l->stats.queue_sz_counts++; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci skb = skb_peek(&l->transmq); 7648c2ecf20Sopenharmony_ci if (!skb) 7658c2ecf20Sopenharmony_ci return; 7668c2ecf20Sopenharmony_ci msg = buf_msg(skb); 7678c2ecf20Sopenharmony_ci length = msg_size(msg); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (msg_user(msg) == MSG_FRAGMENTER) { 7708c2ecf20Sopenharmony_ci if (msg_type(msg) != FIRST_FRAGMENT) 7718c2ecf20Sopenharmony_ci return; 7728c2ecf20Sopenharmony_ci length = msg_size(msg_inner_hdr(msg)); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci l->stats.msg_lengths_total += length; 7758c2ecf20Sopenharmony_ci l->stats.msg_length_counts++; 7768c2ecf20Sopenharmony_ci if (length <= 64) 7778c2ecf20Sopenharmony_ci l->stats.msg_length_profile[0]++; 7788c2ecf20Sopenharmony_ci else if (length <= 256) 7798c2ecf20Sopenharmony_ci l->stats.msg_length_profile[1]++; 7808c2ecf20Sopenharmony_ci else if (length <= 1024) 7818c2ecf20Sopenharmony_ci l->stats.msg_length_profile[2]++; 7828c2ecf20Sopenharmony_ci else if (length <= 4096) 7838c2ecf20Sopenharmony_ci l->stats.msg_length_profile[3]++; 7848c2ecf20Sopenharmony_ci else if (length <= 16384) 7858c2ecf20Sopenharmony_ci l->stats.msg_length_profile[4]++; 7868c2ecf20Sopenharmony_ci else if (length <= 32768) 7878c2ecf20Sopenharmony_ci l->stats.msg_length_profile[5]++; 7888c2ecf20Sopenharmony_ci else 7898c2ecf20Sopenharmony_ci l->stats.msg_length_profile[6]++; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci/** 7938c2ecf20Sopenharmony_ci * tipc_link_too_silent - check if link is "too silent" 7948c2ecf20Sopenharmony_ci * @l: tipc link to be checked 7958c2ecf20Sopenharmony_ci * 7968c2ecf20Sopenharmony_ci * Returns true if the link 'silent_intv_cnt' is about to reach the 7978c2ecf20Sopenharmony_ci * 'abort_limit' value, otherwise false 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_cibool tipc_link_too_silent(struct tipc_link *l) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci return (l->silent_intv_cnt + 2 > l->abort_limit); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci/* tipc_link_timeout - perform periodic task as instructed from node timeout 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_ciint tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci int mtyp = 0; 8098c2ecf20Sopenharmony_ci int rc = 0; 8108c2ecf20Sopenharmony_ci bool state = false; 8118c2ecf20Sopenharmony_ci bool probe = false; 8128c2ecf20Sopenharmony_ci bool setup = false; 8138c2ecf20Sopenharmony_ci u16 bc_snt = l->bc_sndlink->snd_nxt - 1; 8148c2ecf20Sopenharmony_ci u16 bc_acked = l->bc_rcvlink->acked; 8158c2ecf20Sopenharmony_ci struct tipc_mon_state *mstate = &l->mon_state; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci trace_tipc_link_timeout(l, TIPC_DUMP_NONE, " "); 8188c2ecf20Sopenharmony_ci trace_tipc_link_too_silent(l, TIPC_DUMP_ALL, " "); 8198c2ecf20Sopenharmony_ci switch (l->state) { 8208c2ecf20Sopenharmony_ci case LINK_ESTABLISHED: 8218c2ecf20Sopenharmony_ci case LINK_SYNCHING: 8228c2ecf20Sopenharmony_ci mtyp = STATE_MSG; 8238c2ecf20Sopenharmony_ci link_profile_stats(l); 8248c2ecf20Sopenharmony_ci tipc_mon_get_state(l->net, l->addr, mstate, l->bearer_id); 8258c2ecf20Sopenharmony_ci if (mstate->reset || (l->silent_intv_cnt > l->abort_limit)) 8268c2ecf20Sopenharmony_ci return tipc_link_fsm_evt(l, LINK_FAILURE_EVT); 8278c2ecf20Sopenharmony_ci state = bc_acked != bc_snt; 8288c2ecf20Sopenharmony_ci state |= l->bc_rcvlink->rcv_unacked; 8298c2ecf20Sopenharmony_ci state |= l->rcv_unacked; 8308c2ecf20Sopenharmony_ci state |= !skb_queue_empty(&l->transmq); 8318c2ecf20Sopenharmony_ci probe = mstate->probing; 8328c2ecf20Sopenharmony_ci probe |= l->silent_intv_cnt; 8338c2ecf20Sopenharmony_ci if (probe || mstate->monitoring) 8348c2ecf20Sopenharmony_ci l->silent_intv_cnt++; 8358c2ecf20Sopenharmony_ci probe |= !skb_queue_empty(&l->deferdq); 8368c2ecf20Sopenharmony_ci if (l->snd_nxt == l->checkpoint) { 8378c2ecf20Sopenharmony_ci tipc_link_update_cwin(l, 0, 0); 8388c2ecf20Sopenharmony_ci probe = true; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci l->checkpoint = l->snd_nxt; 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci case LINK_RESET: 8438c2ecf20Sopenharmony_ci setup = l->rst_cnt++ <= 4; 8448c2ecf20Sopenharmony_ci setup |= !(l->rst_cnt % 16); 8458c2ecf20Sopenharmony_ci mtyp = RESET_MSG; 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci case LINK_ESTABLISHING: 8488c2ecf20Sopenharmony_ci setup = true; 8498c2ecf20Sopenharmony_ci mtyp = ACTIVATE_MSG; 8508c2ecf20Sopenharmony_ci break; 8518c2ecf20Sopenharmony_ci case LINK_PEER_RESET: 8528c2ecf20Sopenharmony_ci case LINK_RESETTING: 8538c2ecf20Sopenharmony_ci case LINK_FAILINGOVER: 8548c2ecf20Sopenharmony_ci break; 8558c2ecf20Sopenharmony_ci default: 8568c2ecf20Sopenharmony_ci break; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (state || probe || setup) 8608c2ecf20Sopenharmony_ci tipc_link_build_proto_msg(l, mtyp, probe, 0, 0, 0, 0, xmitq); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return rc; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci/** 8668c2ecf20Sopenharmony_ci * link_schedule_user - schedule a message sender for wakeup after congestion 8678c2ecf20Sopenharmony_ci * @l: congested link 8688c2ecf20Sopenharmony_ci * @hdr: header of message that is being sent 8698c2ecf20Sopenharmony_ci * Create pseudo msg to send back to user when congestion abates 8708c2ecf20Sopenharmony_ci */ 8718c2ecf20Sopenharmony_cistatic int link_schedule_user(struct tipc_link *l, struct tipc_msg *hdr) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci u32 dnode = tipc_own_addr(l->net); 8748c2ecf20Sopenharmony_ci u32 dport = msg_origport(hdr); 8758c2ecf20Sopenharmony_ci struct sk_buff *skb; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* Create and schedule wakeup pseudo message */ 8788c2ecf20Sopenharmony_ci skb = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, 8798c2ecf20Sopenharmony_ci dnode, l->addr, dport, 0, 0); 8808c2ecf20Sopenharmony_ci if (!skb) 8818c2ecf20Sopenharmony_ci return -ENOBUFS; 8828c2ecf20Sopenharmony_ci msg_set_dest_droppable(buf_msg(skb), true); 8838c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->chain_imp = msg_importance(hdr); 8848c2ecf20Sopenharmony_ci skb_queue_tail(&l->wakeupq, skb); 8858c2ecf20Sopenharmony_ci l->stats.link_congs++; 8868c2ecf20Sopenharmony_ci trace_tipc_link_conges(l, TIPC_DUMP_ALL, "wakeup scheduled!"); 8878c2ecf20Sopenharmony_ci return -ELINKCONG; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci/** 8918c2ecf20Sopenharmony_ci * link_prepare_wakeup - prepare users for wakeup after congestion 8928c2ecf20Sopenharmony_ci * @l: congested link 8938c2ecf20Sopenharmony_ci * Wake up a number of waiting users, as permitted by available space 8948c2ecf20Sopenharmony_ci * in the send queue 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_cistatic void link_prepare_wakeup(struct tipc_link *l) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct sk_buff_head *wakeupq = &l->wakeupq; 8998c2ecf20Sopenharmony_ci struct sk_buff_head *inputq = l->inputq; 9008c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp; 9018c2ecf20Sopenharmony_ci struct sk_buff_head tmpq; 9028c2ecf20Sopenharmony_ci int avail[5] = {0,}; 9038c2ecf20Sopenharmony_ci int imp = 0; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci __skb_queue_head_init(&tmpq); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci for (; imp <= TIPC_SYSTEM_IMPORTANCE; imp++) 9088c2ecf20Sopenharmony_ci avail[imp] = l->backlog[imp].limit - l->backlog[imp].len; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci skb_queue_walk_safe(wakeupq, skb, tmp) { 9118c2ecf20Sopenharmony_ci imp = TIPC_SKB_CB(skb)->chain_imp; 9128c2ecf20Sopenharmony_ci if (avail[imp] <= 0) 9138c2ecf20Sopenharmony_ci continue; 9148c2ecf20Sopenharmony_ci avail[imp]--; 9158c2ecf20Sopenharmony_ci __skb_unlink(skb, wakeupq); 9168c2ecf20Sopenharmony_ci __skb_queue_tail(&tmpq, skb); 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci spin_lock_bh(&inputq->lock); 9208c2ecf20Sopenharmony_ci skb_queue_splice_tail(&tmpq, inputq); 9218c2ecf20Sopenharmony_ci spin_unlock_bh(&inputq->lock); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci/** 9268c2ecf20Sopenharmony_ci * tipc_link_set_skb_retransmit_time - set the time at which retransmission of 9278c2ecf20Sopenharmony_ci * the given skb should be next attempted 9288c2ecf20Sopenharmony_ci * @skb: skb to set a future retransmission time for 9298c2ecf20Sopenharmony_ci * @l: link the skb will be transmitted on 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_cistatic void tipc_link_set_skb_retransmit_time(struct sk_buff *skb, 9328c2ecf20Sopenharmony_ci struct tipc_link *l) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci if (link_is_bc_sndlink(l)) 9358c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM; 9368c2ecf20Sopenharmony_ci else 9378c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->nxt_retr = TIPC_UC_RETR_TIME; 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_civoid tipc_link_reset(struct tipc_link *l) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci struct sk_buff_head list; 9438c2ecf20Sopenharmony_ci u32 imp; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci __skb_queue_head_init(&list); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci l->in_session = false; 9488c2ecf20Sopenharmony_ci /* Force re-synch of peer session number before establishing */ 9498c2ecf20Sopenharmony_ci l->peer_session--; 9508c2ecf20Sopenharmony_ci l->session++; 9518c2ecf20Sopenharmony_ci l->mtu = l->advertised_mtu; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci spin_lock_bh(&l->wakeupq.lock); 9548c2ecf20Sopenharmony_ci skb_queue_splice_init(&l->wakeupq, &list); 9558c2ecf20Sopenharmony_ci spin_unlock_bh(&l->wakeupq.lock); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci spin_lock_bh(&l->inputq->lock); 9588c2ecf20Sopenharmony_ci skb_queue_splice_init(&list, l->inputq); 9598c2ecf20Sopenharmony_ci spin_unlock_bh(&l->inputq->lock); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci __skb_queue_purge(&l->transmq); 9628c2ecf20Sopenharmony_ci __skb_queue_purge(&l->deferdq); 9638c2ecf20Sopenharmony_ci __skb_queue_purge(&l->backlogq); 9648c2ecf20Sopenharmony_ci __skb_queue_purge(&l->failover_deferdq); 9658c2ecf20Sopenharmony_ci for (imp = 0; imp <= TIPC_SYSTEM_IMPORTANCE; imp++) { 9668c2ecf20Sopenharmony_ci l->backlog[imp].len = 0; 9678c2ecf20Sopenharmony_ci l->backlog[imp].target_bskb = NULL; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci kfree_skb(l->reasm_buf); 9708c2ecf20Sopenharmony_ci kfree_skb(l->reasm_tnlmsg); 9718c2ecf20Sopenharmony_ci kfree_skb(l->failover_reasm_skb); 9728c2ecf20Sopenharmony_ci l->reasm_buf = NULL; 9738c2ecf20Sopenharmony_ci l->reasm_tnlmsg = NULL; 9748c2ecf20Sopenharmony_ci l->failover_reasm_skb = NULL; 9758c2ecf20Sopenharmony_ci l->rcv_unacked = 0; 9768c2ecf20Sopenharmony_ci l->snd_nxt = 1; 9778c2ecf20Sopenharmony_ci l->rcv_nxt = 1; 9788c2ecf20Sopenharmony_ci l->snd_nxt_state = 1; 9798c2ecf20Sopenharmony_ci l->rcv_nxt_state = 1; 9808c2ecf20Sopenharmony_ci l->acked = 0; 9818c2ecf20Sopenharmony_ci l->last_gap = 0; 9828c2ecf20Sopenharmony_ci kfree(l->last_ga); 9838c2ecf20Sopenharmony_ci l->last_ga = NULL; 9848c2ecf20Sopenharmony_ci l->silent_intv_cnt = 0; 9858c2ecf20Sopenharmony_ci l->rst_cnt = 0; 9868c2ecf20Sopenharmony_ci l->bc_peer_is_up = false; 9878c2ecf20Sopenharmony_ci memset(&l->mon_state, 0, sizeof(l->mon_state)); 9888c2ecf20Sopenharmony_ci tipc_link_reset_stats(l); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci/** 9928c2ecf20Sopenharmony_ci * tipc_link_xmit(): enqueue buffer list according to queue situation 9938c2ecf20Sopenharmony_ci * @l: link to use 9948c2ecf20Sopenharmony_ci * @list: chain of buffers containing message 9958c2ecf20Sopenharmony_ci * @xmitq: returned list of packets to be sent by caller 9968c2ecf20Sopenharmony_ci * 9978c2ecf20Sopenharmony_ci * Consumes the buffer chain. 9988c2ecf20Sopenharmony_ci * Returns 0 if success, or errno: -ELINKCONG, -EMSGSIZE or -ENOBUFS 9998c2ecf20Sopenharmony_ci * Messages at TIPC_SYSTEM_IMPORTANCE are always accepted 10008c2ecf20Sopenharmony_ci */ 10018c2ecf20Sopenharmony_ciint tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list, 10028c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct sk_buff_head *backlogq = &l->backlogq; 10058c2ecf20Sopenharmony_ci struct sk_buff_head *transmq = &l->transmq; 10068c2ecf20Sopenharmony_ci struct sk_buff *skb, *_skb; 10078c2ecf20Sopenharmony_ci u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1; 10088c2ecf20Sopenharmony_ci u16 ack = l->rcv_nxt - 1; 10098c2ecf20Sopenharmony_ci u16 seqno = l->snd_nxt; 10108c2ecf20Sopenharmony_ci int pkt_cnt = skb_queue_len(list); 10118c2ecf20Sopenharmony_ci unsigned int mss = tipc_link_mss(l); 10128c2ecf20Sopenharmony_ci unsigned int cwin = l->window; 10138c2ecf20Sopenharmony_ci unsigned int mtu = l->mtu; 10148c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 10158c2ecf20Sopenharmony_ci bool new_bundle; 10168c2ecf20Sopenharmony_ci int rc = 0; 10178c2ecf20Sopenharmony_ci int imp; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (pkt_cnt <= 0) 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci hdr = buf_msg(skb_peek(list)); 10238c2ecf20Sopenharmony_ci if (unlikely(msg_size(hdr) > mtu)) { 10248c2ecf20Sopenharmony_ci pr_warn("Too large msg, purging xmit list %d %d %d %d %d!\n", 10258c2ecf20Sopenharmony_ci skb_queue_len(list), msg_user(hdr), 10268c2ecf20Sopenharmony_ci msg_type(hdr), msg_size(hdr), mtu); 10278c2ecf20Sopenharmony_ci __skb_queue_purge(list); 10288c2ecf20Sopenharmony_ci return -EMSGSIZE; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci imp = msg_importance(hdr); 10328c2ecf20Sopenharmony_ci /* Allow oversubscription of one data msg per source at congestion */ 10338c2ecf20Sopenharmony_ci if (unlikely(l->backlog[imp].len >= l->backlog[imp].limit)) { 10348c2ecf20Sopenharmony_ci if (imp == TIPC_SYSTEM_IMPORTANCE) { 10358c2ecf20Sopenharmony_ci pr_warn("%s<%s>, link overflow", link_rst_msg, l->name); 10368c2ecf20Sopenharmony_ci return -ENOBUFS; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci rc = link_schedule_user(l, hdr); 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (pkt_cnt > 1) { 10428c2ecf20Sopenharmony_ci l->stats.sent_fragmented++; 10438c2ecf20Sopenharmony_ci l->stats.sent_fragments += pkt_cnt; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* Prepare each packet for sending, and add to relevant queue: */ 10478c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(list))) { 10488c2ecf20Sopenharmony_ci if (likely(skb_queue_len(transmq) < cwin)) { 10498c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 10508c2ecf20Sopenharmony_ci msg_set_seqno(hdr, seqno); 10518c2ecf20Sopenharmony_ci msg_set_ack(hdr, ack); 10528c2ecf20Sopenharmony_ci msg_set_bcast_ack(hdr, bc_ack); 10538c2ecf20Sopenharmony_ci _skb = skb_clone(skb, GFP_ATOMIC); 10548c2ecf20Sopenharmony_ci if (!_skb) { 10558c2ecf20Sopenharmony_ci kfree_skb(skb); 10568c2ecf20Sopenharmony_ci __skb_queue_purge(list); 10578c2ecf20Sopenharmony_ci return -ENOBUFS; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci __skb_queue_tail(transmq, skb); 10608c2ecf20Sopenharmony_ci tipc_link_set_skb_retransmit_time(skb, l); 10618c2ecf20Sopenharmony_ci __skb_queue_tail(xmitq, _skb); 10628c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->ackers = l->ackers; 10638c2ecf20Sopenharmony_ci l->rcv_unacked = 0; 10648c2ecf20Sopenharmony_ci l->stats.sent_pkts++; 10658c2ecf20Sopenharmony_ci seqno++; 10668c2ecf20Sopenharmony_ci continue; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci if (tipc_msg_try_bundle(l->backlog[imp].target_bskb, &skb, 10698c2ecf20Sopenharmony_ci mss, l->addr, &new_bundle)) { 10708c2ecf20Sopenharmony_ci if (skb) { 10718c2ecf20Sopenharmony_ci /* Keep a ref. to the skb for next try */ 10728c2ecf20Sopenharmony_ci l->backlog[imp].target_bskb = skb; 10738c2ecf20Sopenharmony_ci l->backlog[imp].len++; 10748c2ecf20Sopenharmony_ci __skb_queue_tail(backlogq, skb); 10758c2ecf20Sopenharmony_ci } else { 10768c2ecf20Sopenharmony_ci if (new_bundle) { 10778c2ecf20Sopenharmony_ci l->stats.sent_bundles++; 10788c2ecf20Sopenharmony_ci l->stats.sent_bundled++; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci l->stats.sent_bundled++; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci continue; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci l->backlog[imp].target_bskb = NULL; 10858c2ecf20Sopenharmony_ci l->backlog[imp].len += (1 + skb_queue_len(list)); 10868c2ecf20Sopenharmony_ci __skb_queue_tail(backlogq, skb); 10878c2ecf20Sopenharmony_ci skb_queue_splice_tail_init(list, backlogq); 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci l->snd_nxt = seqno; 10908c2ecf20Sopenharmony_ci return rc; 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic void tipc_link_update_cwin(struct tipc_link *l, int released, 10948c2ecf20Sopenharmony_ci bool retransmitted) 10958c2ecf20Sopenharmony_ci{ 10968c2ecf20Sopenharmony_ci int bklog_len = skb_queue_len(&l->backlogq); 10978c2ecf20Sopenharmony_ci struct sk_buff_head *txq = &l->transmq; 10988c2ecf20Sopenharmony_ci int txq_len = skb_queue_len(txq); 10998c2ecf20Sopenharmony_ci u16 cwin = l->window; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Enter fast recovery */ 11028c2ecf20Sopenharmony_ci if (unlikely(retransmitted)) { 11038c2ecf20Sopenharmony_ci l->ssthresh = max_t(u16, l->window / 2, 300); 11048c2ecf20Sopenharmony_ci l->window = min_t(u16, l->ssthresh, l->window); 11058c2ecf20Sopenharmony_ci return; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci /* Enter slow start */ 11088c2ecf20Sopenharmony_ci if (unlikely(!released)) { 11098c2ecf20Sopenharmony_ci l->ssthresh = max_t(u16, l->window / 2, 300); 11108c2ecf20Sopenharmony_ci l->window = l->min_win; 11118c2ecf20Sopenharmony_ci return; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci /* Don't increase window if no pressure on the transmit queue */ 11148c2ecf20Sopenharmony_ci if (txq_len + bklog_len < cwin) 11158c2ecf20Sopenharmony_ci return; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* Don't increase window if there are holes the transmit queue */ 11188c2ecf20Sopenharmony_ci if (txq_len && l->snd_nxt - buf_seqno(skb_peek(txq)) != txq_len) 11198c2ecf20Sopenharmony_ci return; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci l->cong_acks += released; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* Slow start */ 11248c2ecf20Sopenharmony_ci if (cwin <= l->ssthresh) { 11258c2ecf20Sopenharmony_ci l->window = min_t(u16, cwin + released, l->max_win); 11268c2ecf20Sopenharmony_ci return; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci /* Congestion avoidance */ 11298c2ecf20Sopenharmony_ci if (l->cong_acks < cwin) 11308c2ecf20Sopenharmony_ci return; 11318c2ecf20Sopenharmony_ci l->window = min_t(u16, ++cwin, l->max_win); 11328c2ecf20Sopenharmony_ci l->cong_acks = 0; 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic void tipc_link_advance_backlog(struct tipc_link *l, 11368c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1; 11398c2ecf20Sopenharmony_ci struct sk_buff_head *txq = &l->transmq; 11408c2ecf20Sopenharmony_ci struct sk_buff *skb, *_skb; 11418c2ecf20Sopenharmony_ci u16 ack = l->rcv_nxt - 1; 11428c2ecf20Sopenharmony_ci u16 seqno = l->snd_nxt; 11438c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 11448c2ecf20Sopenharmony_ci u16 cwin = l->window; 11458c2ecf20Sopenharmony_ci u32 imp; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci while (skb_queue_len(txq) < cwin) { 11488c2ecf20Sopenharmony_ci skb = skb_peek(&l->backlogq); 11498c2ecf20Sopenharmony_ci if (!skb) 11508c2ecf20Sopenharmony_ci break; 11518c2ecf20Sopenharmony_ci _skb = skb_clone(skb, GFP_ATOMIC); 11528c2ecf20Sopenharmony_ci if (!_skb) 11538c2ecf20Sopenharmony_ci break; 11548c2ecf20Sopenharmony_ci __skb_dequeue(&l->backlogq); 11558c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 11568c2ecf20Sopenharmony_ci imp = msg_importance(hdr); 11578c2ecf20Sopenharmony_ci l->backlog[imp].len--; 11588c2ecf20Sopenharmony_ci if (unlikely(skb == l->backlog[imp].target_bskb)) 11598c2ecf20Sopenharmony_ci l->backlog[imp].target_bskb = NULL; 11608c2ecf20Sopenharmony_ci __skb_queue_tail(&l->transmq, skb); 11618c2ecf20Sopenharmony_ci tipc_link_set_skb_retransmit_time(skb, l); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci __skb_queue_tail(xmitq, _skb); 11648c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->ackers = l->ackers; 11658c2ecf20Sopenharmony_ci msg_set_seqno(hdr, seqno); 11668c2ecf20Sopenharmony_ci msg_set_ack(hdr, ack); 11678c2ecf20Sopenharmony_ci msg_set_bcast_ack(hdr, bc_ack); 11688c2ecf20Sopenharmony_ci l->rcv_unacked = 0; 11698c2ecf20Sopenharmony_ci l->stats.sent_pkts++; 11708c2ecf20Sopenharmony_ci seqno++; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci l->snd_nxt = seqno; 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci/** 11768c2ecf20Sopenharmony_ci * link_retransmit_failure() - Detect repeated retransmit failures 11778c2ecf20Sopenharmony_ci * @l: tipc link sender 11788c2ecf20Sopenharmony_ci * @r: tipc link receiver (= l in case of unicast) 11798c2ecf20Sopenharmony_ci * @rc: returned code 11808c2ecf20Sopenharmony_ci * 11818c2ecf20Sopenharmony_ci * Return: true if the repeated retransmit failures happens, otherwise 11828c2ecf20Sopenharmony_ci * false 11838c2ecf20Sopenharmony_ci */ 11848c2ecf20Sopenharmony_cistatic bool link_retransmit_failure(struct tipc_link *l, struct tipc_link *r, 11858c2ecf20Sopenharmony_ci int *rc) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci struct sk_buff *skb = skb_peek(&l->transmq); 11888c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (!skb) 11918c2ecf20Sopenharmony_ci return false; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (!TIPC_SKB_CB(skb)->retr_cnt) 11948c2ecf20Sopenharmony_ci return false; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci if (!time_after(jiffies, TIPC_SKB_CB(skb)->retr_stamp + 11978c2ecf20Sopenharmony_ci msecs_to_jiffies(r->tolerance * 10))) 11988c2ecf20Sopenharmony_ci return false; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 12018c2ecf20Sopenharmony_ci if (link_is_bc_sndlink(l) && !less(r->acked, msg_seqno(hdr))) 12028c2ecf20Sopenharmony_ci return false; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci pr_warn("Retransmission failure on link <%s>\n", l->name); 12058c2ecf20Sopenharmony_ci link_print(l, "State of link "); 12068c2ecf20Sopenharmony_ci pr_info("Failed msg: usr %u, typ %u, len %u, err %u\n", 12078c2ecf20Sopenharmony_ci msg_user(hdr), msg_type(hdr), msg_size(hdr), msg_errcode(hdr)); 12088c2ecf20Sopenharmony_ci pr_info("sqno %u, prev: %x, dest: %x\n", 12098c2ecf20Sopenharmony_ci msg_seqno(hdr), msg_prevnode(hdr), msg_destnode(hdr)); 12108c2ecf20Sopenharmony_ci pr_info("retr_stamp %d, retr_cnt %d\n", 12118c2ecf20Sopenharmony_ci jiffies_to_msecs(TIPC_SKB_CB(skb)->retr_stamp), 12128c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->retr_cnt); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci trace_tipc_list_dump(&l->transmq, true, "retrans failure!"); 12158c2ecf20Sopenharmony_ci trace_tipc_link_dump(l, TIPC_DUMP_NONE, "retrans failure!"); 12168c2ecf20Sopenharmony_ci trace_tipc_link_dump(r, TIPC_DUMP_NONE, "retrans failure!"); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (link_is_bc_sndlink(l)) { 12198c2ecf20Sopenharmony_ci r->state = LINK_RESET; 12208c2ecf20Sopenharmony_ci *rc |= TIPC_LINK_DOWN_EVT; 12218c2ecf20Sopenharmony_ci } else { 12228c2ecf20Sopenharmony_ci *rc |= tipc_link_fsm_evt(l, LINK_FAILURE_EVT); 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci return true; 12268c2ecf20Sopenharmony_ci} 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci/* tipc_data_input - deliver data and name distr msgs to upper layer 12298c2ecf20Sopenharmony_ci * 12308c2ecf20Sopenharmony_ci * Consumes buffer if message is of right type 12318c2ecf20Sopenharmony_ci * Node lock must be held 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_cistatic bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb, 12348c2ecf20Sopenharmony_ci struct sk_buff_head *inputq) 12358c2ecf20Sopenharmony_ci{ 12368c2ecf20Sopenharmony_ci struct sk_buff_head *mc_inputq = l->bc_rcvlink->inputq; 12378c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci switch (msg_user(hdr)) { 12408c2ecf20Sopenharmony_ci case TIPC_LOW_IMPORTANCE: 12418c2ecf20Sopenharmony_ci case TIPC_MEDIUM_IMPORTANCE: 12428c2ecf20Sopenharmony_ci case TIPC_HIGH_IMPORTANCE: 12438c2ecf20Sopenharmony_ci case TIPC_CRITICAL_IMPORTANCE: 12448c2ecf20Sopenharmony_ci if (unlikely(msg_in_group(hdr) || msg_mcast(hdr))) { 12458c2ecf20Sopenharmony_ci skb_queue_tail(mc_inputq, skb); 12468c2ecf20Sopenharmony_ci return true; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci fallthrough; 12498c2ecf20Sopenharmony_ci case CONN_MANAGER: 12508c2ecf20Sopenharmony_ci skb_queue_tail(inputq, skb); 12518c2ecf20Sopenharmony_ci return true; 12528c2ecf20Sopenharmony_ci case GROUP_PROTOCOL: 12538c2ecf20Sopenharmony_ci skb_queue_tail(mc_inputq, skb); 12548c2ecf20Sopenharmony_ci return true; 12558c2ecf20Sopenharmony_ci case NAME_DISTRIBUTOR: 12568c2ecf20Sopenharmony_ci l->bc_rcvlink->state = LINK_ESTABLISHED; 12578c2ecf20Sopenharmony_ci skb_queue_tail(l->namedq, skb); 12588c2ecf20Sopenharmony_ci return true; 12598c2ecf20Sopenharmony_ci case MSG_BUNDLER: 12608c2ecf20Sopenharmony_ci case TUNNEL_PROTOCOL: 12618c2ecf20Sopenharmony_ci case MSG_FRAGMENTER: 12628c2ecf20Sopenharmony_ci case BCAST_PROTOCOL: 12638c2ecf20Sopenharmony_ci return false; 12648c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 12658c2ecf20Sopenharmony_ci case MSG_CRYPTO: 12668c2ecf20Sopenharmony_ci if (TIPC_SKB_CB(skb)->decrypted) { 12678c2ecf20Sopenharmony_ci tipc_crypto_msg_rcv(l->net, skb); 12688c2ecf20Sopenharmony_ci return true; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci fallthrough; 12718c2ecf20Sopenharmony_ci#endif 12728c2ecf20Sopenharmony_ci default: 12738c2ecf20Sopenharmony_ci pr_warn("Dropping received illegal msg type\n"); 12748c2ecf20Sopenharmony_ci kfree_skb(skb); 12758c2ecf20Sopenharmony_ci return true; 12768c2ecf20Sopenharmony_ci }; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci/* tipc_link_input - process packet that has passed link protocol check 12808c2ecf20Sopenharmony_ci * 12818c2ecf20Sopenharmony_ci * Consumes buffer 12828c2ecf20Sopenharmony_ci */ 12838c2ecf20Sopenharmony_cistatic int tipc_link_input(struct tipc_link *l, struct sk_buff *skb, 12848c2ecf20Sopenharmony_ci struct sk_buff_head *inputq, 12858c2ecf20Sopenharmony_ci struct sk_buff **reasm_skb) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 12888c2ecf20Sopenharmony_ci struct sk_buff *iskb; 12898c2ecf20Sopenharmony_ci struct sk_buff_head tmpq; 12908c2ecf20Sopenharmony_ci int usr = msg_user(hdr); 12918c2ecf20Sopenharmony_ci int pos = 0; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (usr == MSG_BUNDLER) { 12948c2ecf20Sopenharmony_ci skb_queue_head_init(&tmpq); 12958c2ecf20Sopenharmony_ci l->stats.recv_bundles++; 12968c2ecf20Sopenharmony_ci l->stats.recv_bundled += msg_msgcnt(hdr); 12978c2ecf20Sopenharmony_ci while (tipc_msg_extract(skb, &iskb, &pos)) 12988c2ecf20Sopenharmony_ci tipc_data_input(l, iskb, &tmpq); 12998c2ecf20Sopenharmony_ci tipc_skb_queue_splice_tail(&tmpq, inputq); 13008c2ecf20Sopenharmony_ci return 0; 13018c2ecf20Sopenharmony_ci } else if (usr == MSG_FRAGMENTER) { 13028c2ecf20Sopenharmony_ci l->stats.recv_fragments++; 13038c2ecf20Sopenharmony_ci if (tipc_buf_append(reasm_skb, &skb)) { 13048c2ecf20Sopenharmony_ci l->stats.recv_fragmented++; 13058c2ecf20Sopenharmony_ci tipc_data_input(l, skb, inputq); 13068c2ecf20Sopenharmony_ci } else if (!*reasm_skb && !link_is_bc_rcvlink(l)) { 13078c2ecf20Sopenharmony_ci pr_warn_ratelimited("Unable to build fragment list\n"); 13088c2ecf20Sopenharmony_ci return tipc_link_fsm_evt(l, LINK_FAILURE_EVT); 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci return 0; 13118c2ecf20Sopenharmony_ci } else if (usr == BCAST_PROTOCOL) { 13128c2ecf20Sopenharmony_ci tipc_bcast_lock(l->net); 13138c2ecf20Sopenharmony_ci tipc_link_bc_init_rcv(l->bc_rcvlink, hdr); 13148c2ecf20Sopenharmony_ci tipc_bcast_unlock(l->net); 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci kfree_skb(skb); 13188c2ecf20Sopenharmony_ci return 0; 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci/* tipc_link_tnl_rcv() - receive TUNNEL_PROTOCOL message, drop or process the 13228c2ecf20Sopenharmony_ci * inner message along with the ones in the old link's 13238c2ecf20Sopenharmony_ci * deferdq 13248c2ecf20Sopenharmony_ci * @l: tunnel link 13258c2ecf20Sopenharmony_ci * @skb: TUNNEL_PROTOCOL message 13268c2ecf20Sopenharmony_ci * @inputq: queue to put messages ready for delivery 13278c2ecf20Sopenharmony_ci */ 13288c2ecf20Sopenharmony_cistatic int tipc_link_tnl_rcv(struct tipc_link *l, struct sk_buff *skb, 13298c2ecf20Sopenharmony_ci struct sk_buff_head *inputq) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci struct sk_buff **reasm_skb = &l->failover_reasm_skb; 13328c2ecf20Sopenharmony_ci struct sk_buff **reasm_tnlmsg = &l->reasm_tnlmsg; 13338c2ecf20Sopenharmony_ci struct sk_buff_head *fdefq = &l->failover_deferdq; 13348c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 13358c2ecf20Sopenharmony_ci struct sk_buff *iskb; 13368c2ecf20Sopenharmony_ci int ipos = 0; 13378c2ecf20Sopenharmony_ci int rc = 0; 13388c2ecf20Sopenharmony_ci u16 seqno; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (msg_type(hdr) == SYNCH_MSG) { 13418c2ecf20Sopenharmony_ci kfree_skb(skb); 13428c2ecf20Sopenharmony_ci return 0; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* Not a fragment? */ 13468c2ecf20Sopenharmony_ci if (likely(!msg_nof_fragms(hdr))) { 13478c2ecf20Sopenharmony_ci if (unlikely(!tipc_msg_extract(skb, &iskb, &ipos))) { 13488c2ecf20Sopenharmony_ci pr_warn_ratelimited("Unable to extract msg, defq: %d\n", 13498c2ecf20Sopenharmony_ci skb_queue_len(fdefq)); 13508c2ecf20Sopenharmony_ci return 0; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci kfree_skb(skb); 13538c2ecf20Sopenharmony_ci } else { 13548c2ecf20Sopenharmony_ci /* Set fragment type for buf_append */ 13558c2ecf20Sopenharmony_ci if (msg_fragm_no(hdr) == 1) 13568c2ecf20Sopenharmony_ci msg_set_type(hdr, FIRST_FRAGMENT); 13578c2ecf20Sopenharmony_ci else if (msg_fragm_no(hdr) < msg_nof_fragms(hdr)) 13588c2ecf20Sopenharmony_ci msg_set_type(hdr, FRAGMENT); 13598c2ecf20Sopenharmony_ci else 13608c2ecf20Sopenharmony_ci msg_set_type(hdr, LAST_FRAGMENT); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (!tipc_buf_append(reasm_tnlmsg, &skb)) { 13638c2ecf20Sopenharmony_ci /* Successful but non-complete reassembly? */ 13648c2ecf20Sopenharmony_ci if (*reasm_tnlmsg || link_is_bc_rcvlink(l)) 13658c2ecf20Sopenharmony_ci return 0; 13668c2ecf20Sopenharmony_ci pr_warn_ratelimited("Unable to reassemble tunnel msg\n"); 13678c2ecf20Sopenharmony_ci return tipc_link_fsm_evt(l, LINK_FAILURE_EVT); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci iskb = skb; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci do { 13738c2ecf20Sopenharmony_ci seqno = buf_seqno(iskb); 13748c2ecf20Sopenharmony_ci if (unlikely(less(seqno, l->drop_point))) { 13758c2ecf20Sopenharmony_ci kfree_skb(iskb); 13768c2ecf20Sopenharmony_ci continue; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci if (unlikely(seqno != l->drop_point)) { 13798c2ecf20Sopenharmony_ci __tipc_skb_queue_sorted(fdefq, seqno, iskb); 13808c2ecf20Sopenharmony_ci continue; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci l->drop_point++; 13848c2ecf20Sopenharmony_ci if (!tipc_data_input(l, iskb, inputq)) 13858c2ecf20Sopenharmony_ci rc |= tipc_link_input(l, iskb, inputq, reasm_skb); 13868c2ecf20Sopenharmony_ci if (unlikely(rc)) 13878c2ecf20Sopenharmony_ci break; 13888c2ecf20Sopenharmony_ci } while ((iskb = __tipc_skb_dequeue(fdefq, l->drop_point))); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci return rc; 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci/** 13948c2ecf20Sopenharmony_ci * tipc_get_gap_ack_blks - get Gap ACK blocks from PROTOCOL/STATE_MSG 13958c2ecf20Sopenharmony_ci * @ga: returned pointer to the Gap ACK blocks if any 13968c2ecf20Sopenharmony_ci * @l: the tipc link 13978c2ecf20Sopenharmony_ci * @hdr: the PROTOCOL/STATE_MSG header 13988c2ecf20Sopenharmony_ci * @uc: desired Gap ACK blocks type, i.e. unicast (= 1) or broadcast (= 0) 13998c2ecf20Sopenharmony_ci * 14008c2ecf20Sopenharmony_ci * Return: the total Gap ACK blocks size 14018c2ecf20Sopenharmony_ci */ 14028c2ecf20Sopenharmony_ciu16 tipc_get_gap_ack_blks(struct tipc_gap_ack_blks **ga, struct tipc_link *l, 14038c2ecf20Sopenharmony_ci struct tipc_msg *hdr, bool uc) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci struct tipc_gap_ack_blks *p; 14068c2ecf20Sopenharmony_ci u16 sz = 0; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* Does peer support the Gap ACK blocks feature? */ 14098c2ecf20Sopenharmony_ci if (l->peer_caps & TIPC_GAP_ACK_BLOCK) { 14108c2ecf20Sopenharmony_ci p = (struct tipc_gap_ack_blks *)msg_data(hdr); 14118c2ecf20Sopenharmony_ci sz = ntohs(p->len); 14128c2ecf20Sopenharmony_ci /* Sanity check */ 14138c2ecf20Sopenharmony_ci if (sz == struct_size(p, gacks, size_add(p->ugack_cnt, p->bgack_cnt))) { 14148c2ecf20Sopenharmony_ci /* Good, check if the desired type exists */ 14158c2ecf20Sopenharmony_ci if ((uc && p->ugack_cnt) || (!uc && p->bgack_cnt)) 14168c2ecf20Sopenharmony_ci goto ok; 14178c2ecf20Sopenharmony_ci /* Backward compatible: peer might not support bc, but uc? */ 14188c2ecf20Sopenharmony_ci } else if (uc && sz == struct_size(p, gacks, p->ugack_cnt)) { 14198c2ecf20Sopenharmony_ci if (p->ugack_cnt) { 14208c2ecf20Sopenharmony_ci p->bgack_cnt = 0; 14218c2ecf20Sopenharmony_ci goto ok; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci /* Other cases: ignore! */ 14268c2ecf20Sopenharmony_ci p = NULL; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ciok: 14298c2ecf20Sopenharmony_ci *ga = p; 14308c2ecf20Sopenharmony_ci return sz; 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cistatic u8 __tipc_build_gap_ack_blks(struct tipc_gap_ack_blks *ga, 14348c2ecf20Sopenharmony_ci struct tipc_link *l, u8 start_index) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci struct tipc_gap_ack *gacks = &ga->gacks[start_index]; 14378c2ecf20Sopenharmony_ci struct sk_buff *skb = skb_peek(&l->deferdq); 14388c2ecf20Sopenharmony_ci u16 expect, seqno = 0; 14398c2ecf20Sopenharmony_ci u8 n = 0; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci if (!skb) 14428c2ecf20Sopenharmony_ci return 0; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci expect = buf_seqno(skb); 14458c2ecf20Sopenharmony_ci skb_queue_walk(&l->deferdq, skb) { 14468c2ecf20Sopenharmony_ci seqno = buf_seqno(skb); 14478c2ecf20Sopenharmony_ci if (unlikely(more(seqno, expect))) { 14488c2ecf20Sopenharmony_ci gacks[n].ack = htons(expect - 1); 14498c2ecf20Sopenharmony_ci gacks[n].gap = htons(seqno - expect); 14508c2ecf20Sopenharmony_ci if (++n >= MAX_GAP_ACK_BLKS / 2) { 14518c2ecf20Sopenharmony_ci pr_info_ratelimited("Gacks on %s: %d, ql: %d!\n", 14528c2ecf20Sopenharmony_ci l->name, n, 14538c2ecf20Sopenharmony_ci skb_queue_len(&l->deferdq)); 14548c2ecf20Sopenharmony_ci return n; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci } else if (unlikely(less(seqno, expect))) { 14578c2ecf20Sopenharmony_ci pr_warn("Unexpected skb in deferdq!\n"); 14588c2ecf20Sopenharmony_ci continue; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci expect = seqno + 1; 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* last block */ 14648c2ecf20Sopenharmony_ci gacks[n].ack = htons(seqno); 14658c2ecf20Sopenharmony_ci gacks[n].gap = 0; 14668c2ecf20Sopenharmony_ci n++; 14678c2ecf20Sopenharmony_ci return n; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci/* tipc_build_gap_ack_blks - build Gap ACK blocks 14718c2ecf20Sopenharmony_ci * @l: tipc unicast link 14728c2ecf20Sopenharmony_ci * @hdr: the tipc message buffer to store the Gap ACK blocks after built 14738c2ecf20Sopenharmony_ci * 14748c2ecf20Sopenharmony_ci * The function builds Gap ACK blocks for both the unicast & broadcast receiver 14758c2ecf20Sopenharmony_ci * links of a certain peer, the buffer after built has the network data format 14768c2ecf20Sopenharmony_ci * as found at the struct tipc_gap_ack_blks definition. 14778c2ecf20Sopenharmony_ci * 14788c2ecf20Sopenharmony_ci * returns the actual allocated memory size 14798c2ecf20Sopenharmony_ci */ 14808c2ecf20Sopenharmony_cistatic u16 tipc_build_gap_ack_blks(struct tipc_link *l, struct tipc_msg *hdr) 14818c2ecf20Sopenharmony_ci{ 14828c2ecf20Sopenharmony_ci struct tipc_link *bcl = l->bc_rcvlink; 14838c2ecf20Sopenharmony_ci struct tipc_gap_ack_blks *ga; 14848c2ecf20Sopenharmony_ci u16 len; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci ga = (struct tipc_gap_ack_blks *)msg_data(hdr); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* Start with broadcast link first */ 14898c2ecf20Sopenharmony_ci tipc_bcast_lock(bcl->net); 14908c2ecf20Sopenharmony_ci msg_set_bcast_ack(hdr, bcl->rcv_nxt - 1); 14918c2ecf20Sopenharmony_ci msg_set_bc_gap(hdr, link_bc_rcv_gap(bcl)); 14928c2ecf20Sopenharmony_ci ga->bgack_cnt = __tipc_build_gap_ack_blks(ga, bcl, 0); 14938c2ecf20Sopenharmony_ci tipc_bcast_unlock(bcl->net); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci /* Now for unicast link, but an explicit NACK only (???) */ 14968c2ecf20Sopenharmony_ci ga->ugack_cnt = (msg_seq_gap(hdr)) ? 14978c2ecf20Sopenharmony_ci __tipc_build_gap_ack_blks(ga, l, ga->bgack_cnt) : 0; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* Total len */ 15008c2ecf20Sopenharmony_ci len = struct_size(ga, gacks, size_add(ga->bgack_cnt, ga->ugack_cnt)); 15018c2ecf20Sopenharmony_ci ga->len = htons(len); 15028c2ecf20Sopenharmony_ci return len; 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci/* tipc_link_advance_transmq - advance TIPC link transmq queue by releasing 15068c2ecf20Sopenharmony_ci * acked packets, also doing retransmissions if 15078c2ecf20Sopenharmony_ci * gaps found 15088c2ecf20Sopenharmony_ci * @l: tipc link with transmq queue to be advanced 15098c2ecf20Sopenharmony_ci * @r: tipc link "receiver" i.e. in case of broadcast (= "l" if unicast) 15108c2ecf20Sopenharmony_ci * @acked: seqno of last packet acked by peer without any gaps before 15118c2ecf20Sopenharmony_ci * @gap: # of gap packets 15128c2ecf20Sopenharmony_ci * @ga: buffer pointer to Gap ACK blocks from peer 15138c2ecf20Sopenharmony_ci * @xmitq: queue for accumulating the retransmitted packets if any 15148c2ecf20Sopenharmony_ci * @retransmitted: returned boolean value if a retransmission is really issued 15158c2ecf20Sopenharmony_ci * @rc: returned code e.g. TIPC_LINK_DOWN_EVT if a repeated retransmit failures 15168c2ecf20Sopenharmony_ci * happens (- unlikely case) 15178c2ecf20Sopenharmony_ci * 15188c2ecf20Sopenharmony_ci * Return: the number of packets released from the link transmq 15198c2ecf20Sopenharmony_ci */ 15208c2ecf20Sopenharmony_cistatic int tipc_link_advance_transmq(struct tipc_link *l, struct tipc_link *r, 15218c2ecf20Sopenharmony_ci u16 acked, u16 gap, 15228c2ecf20Sopenharmony_ci struct tipc_gap_ack_blks *ga, 15238c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq, 15248c2ecf20Sopenharmony_ci bool *retransmitted, int *rc) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct tipc_gap_ack_blks *last_ga = r->last_ga, *this_ga = NULL; 15278c2ecf20Sopenharmony_ci struct tipc_gap_ack *gacks = NULL; 15288c2ecf20Sopenharmony_ci struct sk_buff *skb, *_skb, *tmp; 15298c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 15308c2ecf20Sopenharmony_ci u32 qlen = skb_queue_len(&l->transmq); 15318c2ecf20Sopenharmony_ci u16 nacked = acked, ngap = gap, gack_cnt = 0; 15328c2ecf20Sopenharmony_ci u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1; 15338c2ecf20Sopenharmony_ci u16 ack = l->rcv_nxt - 1; 15348c2ecf20Sopenharmony_ci u16 seqno, n = 0; 15358c2ecf20Sopenharmony_ci u16 end = r->acked, start = end, offset = r->last_gap; 15368c2ecf20Sopenharmony_ci u16 si = (last_ga) ? last_ga->start_index : 0; 15378c2ecf20Sopenharmony_ci bool is_uc = !link_is_bc_sndlink(l); 15388c2ecf20Sopenharmony_ci bool bc_has_acked = false; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci trace_tipc_link_retrans(r, acked + 1, acked + gap, &l->transmq); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci /* Determine Gap ACK blocks if any for the particular link */ 15438c2ecf20Sopenharmony_ci if (ga && is_uc) { 15448c2ecf20Sopenharmony_ci /* Get the Gap ACKs, uc part */ 15458c2ecf20Sopenharmony_ci gack_cnt = ga->ugack_cnt; 15468c2ecf20Sopenharmony_ci gacks = &ga->gacks[ga->bgack_cnt]; 15478c2ecf20Sopenharmony_ci } else if (ga) { 15488c2ecf20Sopenharmony_ci /* Copy the Gap ACKs, bc part, for later renewal if needed */ 15498c2ecf20Sopenharmony_ci this_ga = kmemdup(ga, struct_size(ga, gacks, ga->bgack_cnt), 15508c2ecf20Sopenharmony_ci GFP_ATOMIC); 15518c2ecf20Sopenharmony_ci if (likely(this_ga)) { 15528c2ecf20Sopenharmony_ci this_ga->start_index = 0; 15538c2ecf20Sopenharmony_ci /* Start with the bc Gap ACKs */ 15548c2ecf20Sopenharmony_ci gack_cnt = this_ga->bgack_cnt; 15558c2ecf20Sopenharmony_ci gacks = &this_ga->gacks[0]; 15568c2ecf20Sopenharmony_ci } else { 15578c2ecf20Sopenharmony_ci /* Hmm, we can get in trouble..., simply ignore it */ 15588c2ecf20Sopenharmony_ci pr_warn_ratelimited("Ignoring bc Gap ACKs, no memory\n"); 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Advance the link transmq */ 15638c2ecf20Sopenharmony_ci skb_queue_walk_safe(&l->transmq, skb, tmp) { 15648c2ecf20Sopenharmony_ci seqno = buf_seqno(skb); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_cinext_gap_ack: 15678c2ecf20Sopenharmony_ci if (less_eq(seqno, nacked)) { 15688c2ecf20Sopenharmony_ci if (is_uc) 15698c2ecf20Sopenharmony_ci goto release; 15708c2ecf20Sopenharmony_ci /* Skip packets peer has already acked */ 15718c2ecf20Sopenharmony_ci if (!more(seqno, r->acked)) 15728c2ecf20Sopenharmony_ci continue; 15738c2ecf20Sopenharmony_ci /* Get the next of last Gap ACK blocks */ 15748c2ecf20Sopenharmony_ci while (more(seqno, end)) { 15758c2ecf20Sopenharmony_ci if (!last_ga || si >= last_ga->bgack_cnt) 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_ci start = end + offset + 1; 15788c2ecf20Sopenharmony_ci end = ntohs(last_ga->gacks[si].ack); 15798c2ecf20Sopenharmony_ci offset = ntohs(last_ga->gacks[si].gap); 15808c2ecf20Sopenharmony_ci si++; 15818c2ecf20Sopenharmony_ci WARN_ONCE(more(start, end) || 15828c2ecf20Sopenharmony_ci (!offset && 15838c2ecf20Sopenharmony_ci si < last_ga->bgack_cnt) || 15848c2ecf20Sopenharmony_ci si > MAX_GAP_ACK_BLKS, 15858c2ecf20Sopenharmony_ci "Corrupted Gap ACK: %d %d %d %d %d\n", 15868c2ecf20Sopenharmony_ci start, end, offset, si, 15878c2ecf20Sopenharmony_ci last_ga->bgack_cnt); 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci /* Check against the last Gap ACK block */ 15908c2ecf20Sopenharmony_ci if (in_range(seqno, start, end)) 15918c2ecf20Sopenharmony_ci continue; 15928c2ecf20Sopenharmony_ci /* Update/release the packet peer is acking */ 15938c2ecf20Sopenharmony_ci bc_has_acked = true; 15948c2ecf20Sopenharmony_ci if (--TIPC_SKB_CB(skb)->ackers) 15958c2ecf20Sopenharmony_ci continue; 15968c2ecf20Sopenharmony_cirelease: 15978c2ecf20Sopenharmony_ci /* release skb */ 15988c2ecf20Sopenharmony_ci __skb_unlink(skb, &l->transmq); 15998c2ecf20Sopenharmony_ci kfree_skb(skb); 16008c2ecf20Sopenharmony_ci } else if (less_eq(seqno, nacked + ngap)) { 16018c2ecf20Sopenharmony_ci /* First gap: check if repeated retrans failures? */ 16028c2ecf20Sopenharmony_ci if (unlikely(seqno == acked + 1 && 16038c2ecf20Sopenharmony_ci link_retransmit_failure(l, r, rc))) { 16048c2ecf20Sopenharmony_ci /* Ignore this bc Gap ACKs if any */ 16058c2ecf20Sopenharmony_ci kfree(this_ga); 16068c2ecf20Sopenharmony_ci this_ga = NULL; 16078c2ecf20Sopenharmony_ci break; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci /* retransmit skb if unrestricted*/ 16108c2ecf20Sopenharmony_ci if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr)) 16118c2ecf20Sopenharmony_ci continue; 16128c2ecf20Sopenharmony_ci tipc_link_set_skb_retransmit_time(skb, l); 16138c2ecf20Sopenharmony_ci _skb = pskb_copy(skb, GFP_ATOMIC); 16148c2ecf20Sopenharmony_ci if (!_skb) 16158c2ecf20Sopenharmony_ci continue; 16168c2ecf20Sopenharmony_ci hdr = buf_msg(_skb); 16178c2ecf20Sopenharmony_ci msg_set_ack(hdr, ack); 16188c2ecf20Sopenharmony_ci msg_set_bcast_ack(hdr, bc_ack); 16198c2ecf20Sopenharmony_ci _skb->priority = TC_PRIO_CONTROL; 16208c2ecf20Sopenharmony_ci __skb_queue_tail(xmitq, _skb); 16218c2ecf20Sopenharmony_ci l->stats.retransmitted++; 16228c2ecf20Sopenharmony_ci if (!is_uc) 16238c2ecf20Sopenharmony_ci r->stats.retransmitted++; 16248c2ecf20Sopenharmony_ci *retransmitted = true; 16258c2ecf20Sopenharmony_ci /* Increase actual retrans counter & mark first time */ 16268c2ecf20Sopenharmony_ci if (!TIPC_SKB_CB(skb)->retr_cnt++) 16278c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->retr_stamp = jiffies; 16288c2ecf20Sopenharmony_ci } else { 16298c2ecf20Sopenharmony_ci /* retry with Gap ACK blocks if any */ 16308c2ecf20Sopenharmony_ci if (n >= gack_cnt) 16318c2ecf20Sopenharmony_ci break; 16328c2ecf20Sopenharmony_ci nacked = ntohs(gacks[n].ack); 16338c2ecf20Sopenharmony_ci ngap = ntohs(gacks[n].gap); 16348c2ecf20Sopenharmony_ci n++; 16358c2ecf20Sopenharmony_ci goto next_gap_ack; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* Renew last Gap ACK blocks for bc if needed */ 16408c2ecf20Sopenharmony_ci if (bc_has_acked) { 16418c2ecf20Sopenharmony_ci if (this_ga) { 16428c2ecf20Sopenharmony_ci kfree(last_ga); 16438c2ecf20Sopenharmony_ci r->last_ga = this_ga; 16448c2ecf20Sopenharmony_ci r->last_gap = gap; 16458c2ecf20Sopenharmony_ci } else if (last_ga) { 16468c2ecf20Sopenharmony_ci if (less(acked, start)) { 16478c2ecf20Sopenharmony_ci si--; 16488c2ecf20Sopenharmony_ci offset = start - acked - 1; 16498c2ecf20Sopenharmony_ci } else if (less(acked, end)) { 16508c2ecf20Sopenharmony_ci acked = end; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci if (si < last_ga->bgack_cnt) { 16538c2ecf20Sopenharmony_ci last_ga->start_index = si; 16548c2ecf20Sopenharmony_ci r->last_gap = offset; 16558c2ecf20Sopenharmony_ci } else { 16568c2ecf20Sopenharmony_ci kfree(last_ga); 16578c2ecf20Sopenharmony_ci r->last_ga = NULL; 16588c2ecf20Sopenharmony_ci r->last_gap = 0; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci } else { 16618c2ecf20Sopenharmony_ci r->last_gap = 0; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci r->acked = acked; 16648c2ecf20Sopenharmony_ci } else { 16658c2ecf20Sopenharmony_ci kfree(this_ga); 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci return qlen - skb_queue_len(&l->transmq); 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci/* tipc_link_build_state_msg: prepare link state message for transmission 16728c2ecf20Sopenharmony_ci * 16738c2ecf20Sopenharmony_ci * Note that sending of broadcast ack is coordinated among nodes, to reduce 16748c2ecf20Sopenharmony_ci * risk of ack storms towards the sender 16758c2ecf20Sopenharmony_ci */ 16768c2ecf20Sopenharmony_ciint tipc_link_build_state_msg(struct tipc_link *l, struct sk_buff_head *xmitq) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci if (!l) 16798c2ecf20Sopenharmony_ci return 0; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci /* Broadcast ACK must be sent via a unicast link => defer to caller */ 16828c2ecf20Sopenharmony_ci if (link_is_bc_rcvlink(l)) { 16838c2ecf20Sopenharmony_ci if (((l->rcv_nxt ^ tipc_own_addr(l->net)) & 0xf) != 0xf) 16848c2ecf20Sopenharmony_ci return 0; 16858c2ecf20Sopenharmony_ci l->rcv_unacked = 0; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci /* Use snd_nxt to store peer's snd_nxt in broadcast rcv link */ 16888c2ecf20Sopenharmony_ci l->snd_nxt = l->rcv_nxt; 16898c2ecf20Sopenharmony_ci return TIPC_LINK_SND_STATE; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci /* Unicast ACK */ 16928c2ecf20Sopenharmony_ci l->rcv_unacked = 0; 16938c2ecf20Sopenharmony_ci l->stats.sent_acks++; 16948c2ecf20Sopenharmony_ci tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 0, 0, 0, xmitq); 16958c2ecf20Sopenharmony_ci return 0; 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci/* tipc_link_build_reset_msg: prepare link RESET or ACTIVATE message 16998c2ecf20Sopenharmony_ci */ 17008c2ecf20Sopenharmony_civoid tipc_link_build_reset_msg(struct tipc_link *l, struct sk_buff_head *xmitq) 17018c2ecf20Sopenharmony_ci{ 17028c2ecf20Sopenharmony_ci int mtyp = RESET_MSG; 17038c2ecf20Sopenharmony_ci struct sk_buff *skb; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (l->state == LINK_ESTABLISHING) 17068c2ecf20Sopenharmony_ci mtyp = ACTIVATE_MSG; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci tipc_link_build_proto_msg(l, mtyp, 0, 0, 0, 0, 0, xmitq); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci /* Inform peer that this endpoint is going down if applicable */ 17118c2ecf20Sopenharmony_ci skb = skb_peek_tail(xmitq); 17128c2ecf20Sopenharmony_ci if (skb && (l->state == LINK_RESET)) 17138c2ecf20Sopenharmony_ci msg_set_peer_stopping(buf_msg(skb), 1); 17148c2ecf20Sopenharmony_ci} 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci/* tipc_link_build_nack_msg: prepare link nack message for transmission 17178c2ecf20Sopenharmony_ci * Note that sending of broadcast NACK is coordinated among nodes, to 17188c2ecf20Sopenharmony_ci * reduce the risk of NACK storms towards the sender 17198c2ecf20Sopenharmony_ci */ 17208c2ecf20Sopenharmony_cistatic int tipc_link_build_nack_msg(struct tipc_link *l, 17218c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 17228c2ecf20Sopenharmony_ci{ 17238c2ecf20Sopenharmony_ci u32 def_cnt = ++l->stats.deferred_recv; 17248c2ecf20Sopenharmony_ci struct sk_buff_head *dfq = &l->deferdq; 17258c2ecf20Sopenharmony_ci u32 defq_len = skb_queue_len(dfq); 17268c2ecf20Sopenharmony_ci int match1, match2; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci if (link_is_bc_rcvlink(l)) { 17298c2ecf20Sopenharmony_ci match1 = def_cnt & 0xf; 17308c2ecf20Sopenharmony_ci match2 = tipc_own_addr(l->net) & 0xf; 17318c2ecf20Sopenharmony_ci if (match1 == match2) 17328c2ecf20Sopenharmony_ci return TIPC_LINK_SND_STATE; 17338c2ecf20Sopenharmony_ci return 0; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci if (defq_len >= 3 && !((defq_len - 3) % 16)) { 17378c2ecf20Sopenharmony_ci u16 rcvgap = buf_seqno(skb_peek(dfq)) - l->rcv_nxt; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 17408c2ecf20Sopenharmony_ci rcvgap, 0, 0, xmitq); 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci return 0; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci/* tipc_link_rcv - process TIPC packets/messages arriving from off-node 17468c2ecf20Sopenharmony_ci * @l: the link that should handle the message 17478c2ecf20Sopenharmony_ci * @skb: TIPC packet 17488c2ecf20Sopenharmony_ci * @xmitq: queue to place packets to be sent after this call 17498c2ecf20Sopenharmony_ci */ 17508c2ecf20Sopenharmony_ciint tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb, 17518c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct sk_buff_head *defq = &l->deferdq; 17548c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 17558c2ecf20Sopenharmony_ci u16 seqno, rcv_nxt, win_lim; 17568c2ecf20Sopenharmony_ci int released = 0; 17578c2ecf20Sopenharmony_ci int rc = 0; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci /* Verify and update link state */ 17608c2ecf20Sopenharmony_ci if (unlikely(msg_user(hdr) == LINK_PROTOCOL)) 17618c2ecf20Sopenharmony_ci return tipc_link_proto_rcv(l, skb, xmitq); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci /* Don't send probe at next timeout expiration */ 17648c2ecf20Sopenharmony_ci l->silent_intv_cnt = 0; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci do { 17678c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 17688c2ecf20Sopenharmony_ci seqno = msg_seqno(hdr); 17698c2ecf20Sopenharmony_ci rcv_nxt = l->rcv_nxt; 17708c2ecf20Sopenharmony_ci win_lim = rcv_nxt + TIPC_MAX_LINK_WIN; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci if (unlikely(!link_is_up(l))) { 17738c2ecf20Sopenharmony_ci if (l->state == LINK_ESTABLISHING) 17748c2ecf20Sopenharmony_ci rc = TIPC_LINK_UP_EVT; 17758c2ecf20Sopenharmony_ci kfree_skb(skb); 17768c2ecf20Sopenharmony_ci break; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci /* Drop if outside receive window */ 17808c2ecf20Sopenharmony_ci if (unlikely(less(seqno, rcv_nxt) || more(seqno, win_lim))) { 17818c2ecf20Sopenharmony_ci l->stats.duplicates++; 17828c2ecf20Sopenharmony_ci kfree_skb(skb); 17838c2ecf20Sopenharmony_ci break; 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci released += tipc_link_advance_transmq(l, l, msg_ack(hdr), 0, 17868c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL); 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci /* Defer delivery if sequence gap */ 17898c2ecf20Sopenharmony_ci if (unlikely(seqno != rcv_nxt)) { 17908c2ecf20Sopenharmony_ci if (!__tipc_skb_queue_sorted(defq, seqno, skb)) 17918c2ecf20Sopenharmony_ci l->stats.duplicates++; 17928c2ecf20Sopenharmony_ci rc |= tipc_link_build_nack_msg(l, xmitq); 17938c2ecf20Sopenharmony_ci break; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci /* Deliver packet */ 17978c2ecf20Sopenharmony_ci l->rcv_nxt++; 17988c2ecf20Sopenharmony_ci l->stats.recv_pkts++; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (unlikely(msg_user(hdr) == TUNNEL_PROTOCOL)) 18018c2ecf20Sopenharmony_ci rc |= tipc_link_tnl_rcv(l, skb, l->inputq); 18028c2ecf20Sopenharmony_ci else if (!tipc_data_input(l, skb, l->inputq)) 18038c2ecf20Sopenharmony_ci rc |= tipc_link_input(l, skb, l->inputq, &l->reasm_buf); 18048c2ecf20Sopenharmony_ci if (unlikely(++l->rcv_unacked >= TIPC_MIN_LINK_WIN)) 18058c2ecf20Sopenharmony_ci rc |= tipc_link_build_state_msg(l, xmitq); 18068c2ecf20Sopenharmony_ci if (unlikely(rc & ~TIPC_LINK_SND_STATE)) 18078c2ecf20Sopenharmony_ci break; 18088c2ecf20Sopenharmony_ci } while ((skb = __tipc_skb_dequeue(defq, l->rcv_nxt))); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci /* Forward queues and wake up waiting users */ 18118c2ecf20Sopenharmony_ci if (released) { 18128c2ecf20Sopenharmony_ci tipc_link_update_cwin(l, released, 0); 18138c2ecf20Sopenharmony_ci tipc_link_advance_backlog(l, xmitq); 18148c2ecf20Sopenharmony_ci if (unlikely(!skb_queue_empty(&l->wakeupq))) 18158c2ecf20Sopenharmony_ci link_prepare_wakeup(l); 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci return rc; 18188c2ecf20Sopenharmony_ci} 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_cistatic void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, 18218c2ecf20Sopenharmony_ci bool probe_reply, u16 rcvgap, 18228c2ecf20Sopenharmony_ci int tolerance, int priority, 18238c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci struct tipc_mon_state *mstate = &l->mon_state; 18268c2ecf20Sopenharmony_ci struct sk_buff_head *dfq = &l->deferdq; 18278c2ecf20Sopenharmony_ci struct tipc_link *bcl = l->bc_rcvlink; 18288c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 18298c2ecf20Sopenharmony_ci struct sk_buff *skb; 18308c2ecf20Sopenharmony_ci bool node_up = link_is_up(bcl); 18318c2ecf20Sopenharmony_ci u16 glen = 0, bc_rcvgap = 0; 18328c2ecf20Sopenharmony_ci int dlen = 0; 18338c2ecf20Sopenharmony_ci void *data; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci /* Don't send protocol message during reset or link failover */ 18368c2ecf20Sopenharmony_ci if (tipc_link_is_blocked(l)) 18378c2ecf20Sopenharmony_ci return; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (!tipc_link_is_up(l) && (mtyp == STATE_MSG)) 18408c2ecf20Sopenharmony_ci return; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci if ((probe || probe_reply) && !skb_queue_empty(dfq)) 18438c2ecf20Sopenharmony_ci rcvgap = buf_seqno(skb_peek(dfq)) - l->rcv_nxt; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci skb = tipc_msg_create(LINK_PROTOCOL, mtyp, INT_H_SIZE, 18468c2ecf20Sopenharmony_ci tipc_max_domain_size + MAX_GAP_ACK_BLKS_SZ, 18478c2ecf20Sopenharmony_ci l->addr, tipc_own_addr(l->net), 0, 0, 0); 18488c2ecf20Sopenharmony_ci if (!skb) 18498c2ecf20Sopenharmony_ci return; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 18528c2ecf20Sopenharmony_ci data = msg_data(hdr); 18538c2ecf20Sopenharmony_ci msg_set_session(hdr, l->session); 18548c2ecf20Sopenharmony_ci msg_set_bearer_id(hdr, l->bearer_id); 18558c2ecf20Sopenharmony_ci msg_set_net_plane(hdr, l->net_plane); 18568c2ecf20Sopenharmony_ci msg_set_next_sent(hdr, l->snd_nxt); 18578c2ecf20Sopenharmony_ci msg_set_ack(hdr, l->rcv_nxt - 1); 18588c2ecf20Sopenharmony_ci msg_set_bcast_ack(hdr, bcl->rcv_nxt - 1); 18598c2ecf20Sopenharmony_ci msg_set_bc_ack_invalid(hdr, !node_up); 18608c2ecf20Sopenharmony_ci msg_set_last_bcast(hdr, l->bc_sndlink->snd_nxt - 1); 18618c2ecf20Sopenharmony_ci msg_set_link_tolerance(hdr, tolerance); 18628c2ecf20Sopenharmony_ci msg_set_linkprio(hdr, priority); 18638c2ecf20Sopenharmony_ci msg_set_redundant_link(hdr, node_up); 18648c2ecf20Sopenharmony_ci msg_set_seq_gap(hdr, 0); 18658c2ecf20Sopenharmony_ci msg_set_seqno(hdr, l->snd_nxt + U16_MAX / 2); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci if (mtyp == STATE_MSG) { 18688c2ecf20Sopenharmony_ci if (l->peer_caps & TIPC_LINK_PROTO_SEQNO) 18698c2ecf20Sopenharmony_ci msg_set_seqno(hdr, l->snd_nxt_state++); 18708c2ecf20Sopenharmony_ci msg_set_seq_gap(hdr, rcvgap); 18718c2ecf20Sopenharmony_ci bc_rcvgap = link_bc_rcv_gap(bcl); 18728c2ecf20Sopenharmony_ci msg_set_bc_gap(hdr, bc_rcvgap); 18738c2ecf20Sopenharmony_ci msg_set_probe(hdr, probe); 18748c2ecf20Sopenharmony_ci msg_set_is_keepalive(hdr, probe || probe_reply); 18758c2ecf20Sopenharmony_ci if (l->peer_caps & TIPC_GAP_ACK_BLOCK) 18768c2ecf20Sopenharmony_ci glen = tipc_build_gap_ack_blks(l, hdr); 18778c2ecf20Sopenharmony_ci tipc_mon_prep(l->net, data + glen, &dlen, mstate, l->bearer_id); 18788c2ecf20Sopenharmony_ci msg_set_size(hdr, INT_H_SIZE + glen + dlen); 18798c2ecf20Sopenharmony_ci skb_trim(skb, INT_H_SIZE + glen + dlen); 18808c2ecf20Sopenharmony_ci l->stats.sent_states++; 18818c2ecf20Sopenharmony_ci l->rcv_unacked = 0; 18828c2ecf20Sopenharmony_ci } else { 18838c2ecf20Sopenharmony_ci /* RESET_MSG or ACTIVATE_MSG */ 18848c2ecf20Sopenharmony_ci if (mtyp == ACTIVATE_MSG) { 18858c2ecf20Sopenharmony_ci msg_set_dest_session_valid(hdr, 1); 18868c2ecf20Sopenharmony_ci msg_set_dest_session(hdr, l->peer_session); 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci msg_set_max_pkt(hdr, l->advertised_mtu); 18898c2ecf20Sopenharmony_ci strcpy(data, l->if_name); 18908c2ecf20Sopenharmony_ci msg_set_size(hdr, INT_H_SIZE + TIPC_MAX_IF_NAME); 18918c2ecf20Sopenharmony_ci skb_trim(skb, INT_H_SIZE + TIPC_MAX_IF_NAME); 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci if (probe) 18948c2ecf20Sopenharmony_ci l->stats.sent_probes++; 18958c2ecf20Sopenharmony_ci if (rcvgap) 18968c2ecf20Sopenharmony_ci l->stats.sent_nacks++; 18978c2ecf20Sopenharmony_ci if (bc_rcvgap) 18988c2ecf20Sopenharmony_ci bcl->stats.sent_nacks++; 18998c2ecf20Sopenharmony_ci skb->priority = TC_PRIO_CONTROL; 19008c2ecf20Sopenharmony_ci __skb_queue_tail(xmitq, skb); 19018c2ecf20Sopenharmony_ci trace_tipc_proto_build(skb, false, l->name); 19028c2ecf20Sopenharmony_ci} 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_civoid tipc_link_create_dummy_tnl_msg(struct tipc_link *l, 19058c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci u32 onode = tipc_own_addr(l->net); 19088c2ecf20Sopenharmony_ci struct tipc_msg *hdr, *ihdr; 19098c2ecf20Sopenharmony_ci struct sk_buff_head tnlq; 19108c2ecf20Sopenharmony_ci struct sk_buff *skb; 19118c2ecf20Sopenharmony_ci u32 dnode = l->addr; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci __skb_queue_head_init(&tnlq); 19148c2ecf20Sopenharmony_ci skb = tipc_msg_create(TUNNEL_PROTOCOL, FAILOVER_MSG, 19158c2ecf20Sopenharmony_ci INT_H_SIZE, BASIC_H_SIZE, 19168c2ecf20Sopenharmony_ci dnode, onode, 0, 0, 0); 19178c2ecf20Sopenharmony_ci if (!skb) { 19188c2ecf20Sopenharmony_ci pr_warn("%sunable to create tunnel packet\n", link_co_err); 19198c2ecf20Sopenharmony_ci return; 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 19238c2ecf20Sopenharmony_ci msg_set_msgcnt(hdr, 1); 19248c2ecf20Sopenharmony_ci msg_set_bearer_id(hdr, l->peer_bearer_id); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci ihdr = (struct tipc_msg *)msg_data(hdr); 19278c2ecf20Sopenharmony_ci tipc_msg_init(onode, ihdr, TIPC_LOW_IMPORTANCE, TIPC_DIRECT_MSG, 19288c2ecf20Sopenharmony_ci BASIC_H_SIZE, dnode); 19298c2ecf20Sopenharmony_ci msg_set_errcode(ihdr, TIPC_ERR_NO_PORT); 19308c2ecf20Sopenharmony_ci __skb_queue_tail(&tnlq, skb); 19318c2ecf20Sopenharmony_ci tipc_link_xmit(l, &tnlq, xmitq); 19328c2ecf20Sopenharmony_ci} 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci/* tipc_link_tnl_prepare(): prepare and return a list of tunnel packets 19358c2ecf20Sopenharmony_ci * with contents of the link's transmit and backlog queues. 19368c2ecf20Sopenharmony_ci */ 19378c2ecf20Sopenharmony_civoid tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl, 19388c2ecf20Sopenharmony_ci int mtyp, struct sk_buff_head *xmitq) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci struct sk_buff_head *fdefq = &tnl->failover_deferdq; 19418c2ecf20Sopenharmony_ci struct sk_buff *skb, *tnlskb; 19428c2ecf20Sopenharmony_ci struct tipc_msg *hdr, tnlhdr; 19438c2ecf20Sopenharmony_ci struct sk_buff_head *queue = &l->transmq; 19448c2ecf20Sopenharmony_ci struct sk_buff_head tmpxq, tnlq, frags; 19458c2ecf20Sopenharmony_ci u16 pktlen, pktcnt, seqno = l->snd_nxt; 19468c2ecf20Sopenharmony_ci bool pktcnt_need_update = false; 19478c2ecf20Sopenharmony_ci u16 syncpt; 19488c2ecf20Sopenharmony_ci int rc; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci if (!tnl) 19518c2ecf20Sopenharmony_ci return; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci __skb_queue_head_init(&tnlq); 19548c2ecf20Sopenharmony_ci /* Link Synching: 19558c2ecf20Sopenharmony_ci * From now on, send only one single ("dummy") SYNCH message 19568c2ecf20Sopenharmony_ci * to peer. The SYNCH message does not contain any data, just 19578c2ecf20Sopenharmony_ci * a header conveying the synch point to the peer. 19588c2ecf20Sopenharmony_ci */ 19598c2ecf20Sopenharmony_ci if (mtyp == SYNCH_MSG && (tnl->peer_caps & TIPC_TUNNEL_ENHANCED)) { 19608c2ecf20Sopenharmony_ci tnlskb = tipc_msg_create(TUNNEL_PROTOCOL, SYNCH_MSG, 19618c2ecf20Sopenharmony_ci INT_H_SIZE, 0, l->addr, 19628c2ecf20Sopenharmony_ci tipc_own_addr(l->net), 19638c2ecf20Sopenharmony_ci 0, 0, 0); 19648c2ecf20Sopenharmony_ci if (!tnlskb) { 19658c2ecf20Sopenharmony_ci pr_warn("%sunable to create dummy SYNCH_MSG\n", 19668c2ecf20Sopenharmony_ci link_co_err); 19678c2ecf20Sopenharmony_ci return; 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci hdr = buf_msg(tnlskb); 19718c2ecf20Sopenharmony_ci syncpt = l->snd_nxt + skb_queue_len(&l->backlogq) - 1; 19728c2ecf20Sopenharmony_ci msg_set_syncpt(hdr, syncpt); 19738c2ecf20Sopenharmony_ci msg_set_bearer_id(hdr, l->peer_bearer_id); 19748c2ecf20Sopenharmony_ci __skb_queue_tail(&tnlq, tnlskb); 19758c2ecf20Sopenharmony_ci tipc_link_xmit(tnl, &tnlq, xmitq); 19768c2ecf20Sopenharmony_ci return; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci __skb_queue_head_init(&tmpxq); 19808c2ecf20Sopenharmony_ci __skb_queue_head_init(&frags); 19818c2ecf20Sopenharmony_ci /* At least one packet required for safe algorithm => add dummy */ 19828c2ecf20Sopenharmony_ci skb = tipc_msg_create(TIPC_LOW_IMPORTANCE, TIPC_DIRECT_MSG, 19838c2ecf20Sopenharmony_ci BASIC_H_SIZE, 0, l->addr, tipc_own_addr(l->net), 19848c2ecf20Sopenharmony_ci 0, 0, TIPC_ERR_NO_PORT); 19858c2ecf20Sopenharmony_ci if (!skb) { 19868c2ecf20Sopenharmony_ci pr_warn("%sunable to create tunnel packet\n", link_co_err); 19878c2ecf20Sopenharmony_ci return; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci __skb_queue_tail(&tnlq, skb); 19908c2ecf20Sopenharmony_ci tipc_link_xmit(l, &tnlq, &tmpxq); 19918c2ecf20Sopenharmony_ci __skb_queue_purge(&tmpxq); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci /* Initialize reusable tunnel packet header */ 19948c2ecf20Sopenharmony_ci tipc_msg_init(tipc_own_addr(l->net), &tnlhdr, TUNNEL_PROTOCOL, 19958c2ecf20Sopenharmony_ci mtyp, INT_H_SIZE, l->addr); 19968c2ecf20Sopenharmony_ci if (mtyp == SYNCH_MSG) 19978c2ecf20Sopenharmony_ci pktcnt = l->snd_nxt - buf_seqno(skb_peek(&l->transmq)); 19988c2ecf20Sopenharmony_ci else 19998c2ecf20Sopenharmony_ci pktcnt = skb_queue_len(&l->transmq); 20008c2ecf20Sopenharmony_ci pktcnt += skb_queue_len(&l->backlogq); 20018c2ecf20Sopenharmony_ci msg_set_msgcnt(&tnlhdr, pktcnt); 20028c2ecf20Sopenharmony_ci msg_set_bearer_id(&tnlhdr, l->peer_bearer_id); 20038c2ecf20Sopenharmony_citnl: 20048c2ecf20Sopenharmony_ci /* Wrap each packet into a tunnel packet */ 20058c2ecf20Sopenharmony_ci skb_queue_walk(queue, skb) { 20068c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 20078c2ecf20Sopenharmony_ci if (queue == &l->backlogq) 20088c2ecf20Sopenharmony_ci msg_set_seqno(hdr, seqno++); 20098c2ecf20Sopenharmony_ci pktlen = msg_size(hdr); 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci /* Tunnel link MTU is not large enough? This could be 20128c2ecf20Sopenharmony_ci * due to: 20138c2ecf20Sopenharmony_ci * 1) Link MTU has just changed or set differently; 20148c2ecf20Sopenharmony_ci * 2) Or FAILOVER on the top of a SYNCH message 20158c2ecf20Sopenharmony_ci * 20168c2ecf20Sopenharmony_ci * The 2nd case should not happen if peer supports 20178c2ecf20Sopenharmony_ci * TIPC_TUNNEL_ENHANCED 20188c2ecf20Sopenharmony_ci */ 20198c2ecf20Sopenharmony_ci if (pktlen > tnl->mtu - INT_H_SIZE) { 20208c2ecf20Sopenharmony_ci if (mtyp == FAILOVER_MSG && 20218c2ecf20Sopenharmony_ci (tnl->peer_caps & TIPC_TUNNEL_ENHANCED)) { 20228c2ecf20Sopenharmony_ci rc = tipc_msg_fragment(skb, &tnlhdr, tnl->mtu, 20238c2ecf20Sopenharmony_ci &frags); 20248c2ecf20Sopenharmony_ci if (rc) { 20258c2ecf20Sopenharmony_ci pr_warn("%sunable to frag msg: rc %d\n", 20268c2ecf20Sopenharmony_ci link_co_err, rc); 20278c2ecf20Sopenharmony_ci return; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci pktcnt += skb_queue_len(&frags) - 1; 20308c2ecf20Sopenharmony_ci pktcnt_need_update = true; 20318c2ecf20Sopenharmony_ci skb_queue_splice_tail_init(&frags, &tnlq); 20328c2ecf20Sopenharmony_ci continue; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci /* Unluckily, peer doesn't have TIPC_TUNNEL_ENHANCED 20358c2ecf20Sopenharmony_ci * => Just warn it and return! 20368c2ecf20Sopenharmony_ci */ 20378c2ecf20Sopenharmony_ci pr_warn_ratelimited("%stoo large msg <%d, %d>: %d!\n", 20388c2ecf20Sopenharmony_ci link_co_err, msg_user(hdr), 20398c2ecf20Sopenharmony_ci msg_type(hdr), msg_size(hdr)); 20408c2ecf20Sopenharmony_ci return; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci msg_set_size(&tnlhdr, pktlen + INT_H_SIZE); 20448c2ecf20Sopenharmony_ci tnlskb = tipc_buf_acquire(pktlen + INT_H_SIZE, GFP_ATOMIC); 20458c2ecf20Sopenharmony_ci if (!tnlskb) { 20468c2ecf20Sopenharmony_ci pr_warn("%sunable to send packet\n", link_co_err); 20478c2ecf20Sopenharmony_ci return; 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci skb_copy_to_linear_data(tnlskb, &tnlhdr, INT_H_SIZE); 20508c2ecf20Sopenharmony_ci skb_copy_to_linear_data_offset(tnlskb, INT_H_SIZE, hdr, pktlen); 20518c2ecf20Sopenharmony_ci __skb_queue_tail(&tnlq, tnlskb); 20528c2ecf20Sopenharmony_ci } 20538c2ecf20Sopenharmony_ci if (queue != &l->backlogq) { 20548c2ecf20Sopenharmony_ci queue = &l->backlogq; 20558c2ecf20Sopenharmony_ci goto tnl; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci if (pktcnt_need_update) 20598c2ecf20Sopenharmony_ci skb_queue_walk(&tnlq, skb) { 20608c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 20618c2ecf20Sopenharmony_ci msg_set_msgcnt(hdr, pktcnt); 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci tipc_link_xmit(tnl, &tnlq, xmitq); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci if (mtyp == FAILOVER_MSG) { 20678c2ecf20Sopenharmony_ci tnl->drop_point = l->rcv_nxt; 20688c2ecf20Sopenharmony_ci tnl->failover_reasm_skb = l->reasm_buf; 20698c2ecf20Sopenharmony_ci l->reasm_buf = NULL; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci /* Failover the link's deferdq */ 20728c2ecf20Sopenharmony_ci if (unlikely(!skb_queue_empty(fdefq))) { 20738c2ecf20Sopenharmony_ci pr_warn("Link failover deferdq not empty: %d!\n", 20748c2ecf20Sopenharmony_ci skb_queue_len(fdefq)); 20758c2ecf20Sopenharmony_ci __skb_queue_purge(fdefq); 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci skb_queue_splice_init(&l->deferdq, fdefq); 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci} 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci/** 20828c2ecf20Sopenharmony_ci * tipc_link_failover_prepare() - prepare tnl for link failover 20838c2ecf20Sopenharmony_ci * 20848c2ecf20Sopenharmony_ci * This is a special version of the precursor - tipc_link_tnl_prepare(), 20858c2ecf20Sopenharmony_ci * see the tipc_node_link_failover() for details 20868c2ecf20Sopenharmony_ci * 20878c2ecf20Sopenharmony_ci * @l: failover link 20888c2ecf20Sopenharmony_ci * @tnl: tunnel link 20898c2ecf20Sopenharmony_ci * @xmitq: queue for messages to be xmited 20908c2ecf20Sopenharmony_ci */ 20918c2ecf20Sopenharmony_civoid tipc_link_failover_prepare(struct tipc_link *l, struct tipc_link *tnl, 20928c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 20938c2ecf20Sopenharmony_ci{ 20948c2ecf20Sopenharmony_ci struct sk_buff_head *fdefq = &tnl->failover_deferdq; 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci tipc_link_create_dummy_tnl_msg(tnl, xmitq); 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci /* This failover link endpoint was never established before, 20998c2ecf20Sopenharmony_ci * so it has not received anything from peer. 21008c2ecf20Sopenharmony_ci * Otherwise, it must be a normal failover situation or the 21018c2ecf20Sopenharmony_ci * node has entered SELF_DOWN_PEER_LEAVING and both peer nodes 21028c2ecf20Sopenharmony_ci * would have to start over from scratch instead. 21038c2ecf20Sopenharmony_ci */ 21048c2ecf20Sopenharmony_ci tnl->drop_point = 1; 21058c2ecf20Sopenharmony_ci tnl->failover_reasm_skb = NULL; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci /* Initiate the link's failover deferdq */ 21088c2ecf20Sopenharmony_ci if (unlikely(!skb_queue_empty(fdefq))) { 21098c2ecf20Sopenharmony_ci pr_warn("Link failover deferdq not empty: %d!\n", 21108c2ecf20Sopenharmony_ci skb_queue_len(fdefq)); 21118c2ecf20Sopenharmony_ci __skb_queue_purge(fdefq); 21128c2ecf20Sopenharmony_ci } 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci/* tipc_link_validate_msg(): validate message against current link state 21168c2ecf20Sopenharmony_ci * Returns true if message should be accepted, otherwise false 21178c2ecf20Sopenharmony_ci */ 21188c2ecf20Sopenharmony_cibool tipc_link_validate_msg(struct tipc_link *l, struct tipc_msg *hdr) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci u16 curr_session = l->peer_session; 21218c2ecf20Sopenharmony_ci u16 session = msg_session(hdr); 21228c2ecf20Sopenharmony_ci int mtyp = msg_type(hdr); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci if (msg_user(hdr) != LINK_PROTOCOL) 21258c2ecf20Sopenharmony_ci return true; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci switch (mtyp) { 21288c2ecf20Sopenharmony_ci case RESET_MSG: 21298c2ecf20Sopenharmony_ci if (!l->in_session) 21308c2ecf20Sopenharmony_ci return true; 21318c2ecf20Sopenharmony_ci /* Accept only RESET with new session number */ 21328c2ecf20Sopenharmony_ci return more(session, curr_session); 21338c2ecf20Sopenharmony_ci case ACTIVATE_MSG: 21348c2ecf20Sopenharmony_ci if (!l->in_session) 21358c2ecf20Sopenharmony_ci return true; 21368c2ecf20Sopenharmony_ci /* Accept only ACTIVATE with new or current session number */ 21378c2ecf20Sopenharmony_ci return !less(session, curr_session); 21388c2ecf20Sopenharmony_ci case STATE_MSG: 21398c2ecf20Sopenharmony_ci /* Accept only STATE with current session number */ 21408c2ecf20Sopenharmony_ci if (!l->in_session) 21418c2ecf20Sopenharmony_ci return false; 21428c2ecf20Sopenharmony_ci if (session != curr_session) 21438c2ecf20Sopenharmony_ci return false; 21448c2ecf20Sopenharmony_ci /* Extra sanity check */ 21458c2ecf20Sopenharmony_ci if (!link_is_up(l) && msg_ack(hdr)) 21468c2ecf20Sopenharmony_ci return false; 21478c2ecf20Sopenharmony_ci if (!(l->peer_caps & TIPC_LINK_PROTO_SEQNO)) 21488c2ecf20Sopenharmony_ci return true; 21498c2ecf20Sopenharmony_ci /* Accept only STATE with new sequence number */ 21508c2ecf20Sopenharmony_ci return !less(msg_seqno(hdr), l->rcv_nxt_state); 21518c2ecf20Sopenharmony_ci default: 21528c2ecf20Sopenharmony_ci return false; 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci} 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci/* tipc_link_proto_rcv(): receive link level protocol message : 21578c2ecf20Sopenharmony_ci * Note that network plane id propagates through the network, and may 21588c2ecf20Sopenharmony_ci * change at any time. The node with lowest numerical id determines 21598c2ecf20Sopenharmony_ci * network plane 21608c2ecf20Sopenharmony_ci */ 21618c2ecf20Sopenharmony_cistatic int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, 21628c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 21638c2ecf20Sopenharmony_ci{ 21648c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 21658c2ecf20Sopenharmony_ci struct tipc_gap_ack_blks *ga = NULL; 21668c2ecf20Sopenharmony_ci bool reply = msg_probe(hdr), retransmitted = false; 21678c2ecf20Sopenharmony_ci u32 dlen = msg_data_sz(hdr), glen = 0, msg_max; 21688c2ecf20Sopenharmony_ci u16 peers_snd_nxt = msg_next_sent(hdr); 21698c2ecf20Sopenharmony_ci u16 peers_tol = msg_link_tolerance(hdr); 21708c2ecf20Sopenharmony_ci u16 peers_prio = msg_linkprio(hdr); 21718c2ecf20Sopenharmony_ci u16 gap = msg_seq_gap(hdr); 21728c2ecf20Sopenharmony_ci u16 ack = msg_ack(hdr); 21738c2ecf20Sopenharmony_ci u16 rcv_nxt = l->rcv_nxt; 21748c2ecf20Sopenharmony_ci u16 rcvgap = 0; 21758c2ecf20Sopenharmony_ci int mtyp = msg_type(hdr); 21768c2ecf20Sopenharmony_ci int rc = 0, released; 21778c2ecf20Sopenharmony_ci char *if_name; 21788c2ecf20Sopenharmony_ci void *data; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci trace_tipc_proto_rcv(skb, false, l->name); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci if (dlen > U16_MAX) 21838c2ecf20Sopenharmony_ci goto exit; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci if (tipc_link_is_blocked(l) || !xmitq) 21868c2ecf20Sopenharmony_ci goto exit; 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci if (tipc_own_addr(l->net) > msg_prevnode(hdr)) 21898c2ecf20Sopenharmony_ci l->net_plane = msg_net_plane(hdr); 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci if (skb_linearize(skb)) 21928c2ecf20Sopenharmony_ci goto exit; 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 21958c2ecf20Sopenharmony_ci data = msg_data(hdr); 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci if (!tipc_link_validate_msg(l, hdr)) { 21988c2ecf20Sopenharmony_ci trace_tipc_skb_dump(skb, false, "PROTO invalid (1)!"); 21998c2ecf20Sopenharmony_ci trace_tipc_link_dump(l, TIPC_DUMP_NONE, "PROTO invalid (1)!"); 22008c2ecf20Sopenharmony_ci goto exit; 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci switch (mtyp) { 22048c2ecf20Sopenharmony_ci case RESET_MSG: 22058c2ecf20Sopenharmony_ci case ACTIVATE_MSG: 22068c2ecf20Sopenharmony_ci msg_max = msg_max_pkt(hdr); 22078c2ecf20Sopenharmony_ci if (msg_max < tipc_bearer_min_mtu(l->net, l->bearer_id)) 22088c2ecf20Sopenharmony_ci break; 22098c2ecf20Sopenharmony_ci /* Complete own link name with peer's interface name */ 22108c2ecf20Sopenharmony_ci if_name = strrchr(l->name, ':') + 1; 22118c2ecf20Sopenharmony_ci if (sizeof(l->name) - (if_name - l->name) <= TIPC_MAX_IF_NAME) 22128c2ecf20Sopenharmony_ci break; 22138c2ecf20Sopenharmony_ci if (msg_data_sz(hdr) < TIPC_MAX_IF_NAME) 22148c2ecf20Sopenharmony_ci break; 22158c2ecf20Sopenharmony_ci strncpy(if_name, data, TIPC_MAX_IF_NAME); 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci /* Update own tolerance if peer indicates a non-zero value */ 22188c2ecf20Sopenharmony_ci if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL)) { 22198c2ecf20Sopenharmony_ci l->tolerance = peers_tol; 22208c2ecf20Sopenharmony_ci l->bc_rcvlink->tolerance = peers_tol; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci /* Update own priority if peer's priority is higher */ 22238c2ecf20Sopenharmony_ci if (in_range(peers_prio, l->priority + 1, TIPC_MAX_LINK_PRI)) 22248c2ecf20Sopenharmony_ci l->priority = peers_prio; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci /* If peer is going down we want full re-establish cycle */ 22278c2ecf20Sopenharmony_ci if (msg_peer_stopping(hdr)) { 22288c2ecf20Sopenharmony_ci rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT); 22298c2ecf20Sopenharmony_ci break; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci /* If this endpoint was re-created while peer was ESTABLISHING 22338c2ecf20Sopenharmony_ci * it doesn't know current session number. Force re-synch. 22348c2ecf20Sopenharmony_ci */ 22358c2ecf20Sopenharmony_ci if (mtyp == ACTIVATE_MSG && msg_dest_session_valid(hdr) && 22368c2ecf20Sopenharmony_ci l->session != msg_dest_session(hdr)) { 22378c2ecf20Sopenharmony_ci if (less(l->session, msg_dest_session(hdr))) 22388c2ecf20Sopenharmony_ci l->session = msg_dest_session(hdr) + 1; 22398c2ecf20Sopenharmony_ci break; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci /* ACTIVATE_MSG serves as PEER_RESET if link is already down */ 22438c2ecf20Sopenharmony_ci if (mtyp == RESET_MSG || !link_is_up(l)) 22448c2ecf20Sopenharmony_ci rc = tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci /* ACTIVATE_MSG takes up link if it was already locally reset */ 22478c2ecf20Sopenharmony_ci if (mtyp == ACTIVATE_MSG && l->state == LINK_ESTABLISHING) 22488c2ecf20Sopenharmony_ci rc = TIPC_LINK_UP_EVT; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci l->peer_session = msg_session(hdr); 22518c2ecf20Sopenharmony_ci l->in_session = true; 22528c2ecf20Sopenharmony_ci l->peer_bearer_id = msg_bearer_id(hdr); 22538c2ecf20Sopenharmony_ci if (l->mtu > msg_max) 22548c2ecf20Sopenharmony_ci l->mtu = msg_max; 22558c2ecf20Sopenharmony_ci break; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci case STATE_MSG: 22588c2ecf20Sopenharmony_ci /* Validate Gap ACK blocks, drop if invalid */ 22598c2ecf20Sopenharmony_ci glen = tipc_get_gap_ack_blks(&ga, l, hdr, true); 22608c2ecf20Sopenharmony_ci if (glen > dlen) 22618c2ecf20Sopenharmony_ci break; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci l->rcv_nxt_state = msg_seqno(hdr) + 1; 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci /* Update own tolerance if peer indicates a non-zero value */ 22668c2ecf20Sopenharmony_ci if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL)) { 22678c2ecf20Sopenharmony_ci l->tolerance = peers_tol; 22688c2ecf20Sopenharmony_ci l->bc_rcvlink->tolerance = peers_tol; 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci /* Update own prio if peer indicates a different value */ 22718c2ecf20Sopenharmony_ci if ((peers_prio != l->priority) && 22728c2ecf20Sopenharmony_ci in_range(peers_prio, 1, TIPC_MAX_LINK_PRI)) { 22738c2ecf20Sopenharmony_ci l->priority = peers_prio; 22748c2ecf20Sopenharmony_ci rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT); 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci l->silent_intv_cnt = 0; 22788c2ecf20Sopenharmony_ci l->stats.recv_states++; 22798c2ecf20Sopenharmony_ci if (msg_probe(hdr)) 22808c2ecf20Sopenharmony_ci l->stats.recv_probes++; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci if (!link_is_up(l)) { 22838c2ecf20Sopenharmony_ci if (l->state == LINK_ESTABLISHING) 22848c2ecf20Sopenharmony_ci rc = TIPC_LINK_UP_EVT; 22858c2ecf20Sopenharmony_ci break; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci tipc_mon_rcv(l->net, data + glen, dlen - glen, l->addr, 22898c2ecf20Sopenharmony_ci &l->mon_state, l->bearer_id); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci /* Send NACK if peer has sent pkts we haven't received yet */ 22928c2ecf20Sopenharmony_ci if ((reply || msg_is_keepalive(hdr)) && 22938c2ecf20Sopenharmony_ci more(peers_snd_nxt, rcv_nxt) && 22948c2ecf20Sopenharmony_ci !tipc_link_is_synching(l) && 22958c2ecf20Sopenharmony_ci skb_queue_empty(&l->deferdq)) 22968c2ecf20Sopenharmony_ci rcvgap = peers_snd_nxt - l->rcv_nxt; 22978c2ecf20Sopenharmony_ci if (rcvgap || reply) 22988c2ecf20Sopenharmony_ci tipc_link_build_proto_msg(l, STATE_MSG, 0, reply, 22998c2ecf20Sopenharmony_ci rcvgap, 0, 0, xmitq); 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci released = tipc_link_advance_transmq(l, l, ack, gap, ga, xmitq, 23028c2ecf20Sopenharmony_ci &retransmitted, &rc); 23038c2ecf20Sopenharmony_ci if (gap) 23048c2ecf20Sopenharmony_ci l->stats.recv_nacks++; 23058c2ecf20Sopenharmony_ci if (released || retransmitted) 23068c2ecf20Sopenharmony_ci tipc_link_update_cwin(l, released, retransmitted); 23078c2ecf20Sopenharmony_ci if (released) 23088c2ecf20Sopenharmony_ci tipc_link_advance_backlog(l, xmitq); 23098c2ecf20Sopenharmony_ci if (unlikely(!skb_queue_empty(&l->wakeupq))) 23108c2ecf20Sopenharmony_ci link_prepare_wakeup(l); 23118c2ecf20Sopenharmony_ci } 23128c2ecf20Sopenharmony_ciexit: 23138c2ecf20Sopenharmony_ci kfree_skb(skb); 23148c2ecf20Sopenharmony_ci return rc; 23158c2ecf20Sopenharmony_ci} 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci/* tipc_link_build_bc_proto_msg() - create broadcast protocol message 23188c2ecf20Sopenharmony_ci */ 23198c2ecf20Sopenharmony_cistatic bool tipc_link_build_bc_proto_msg(struct tipc_link *l, bool bcast, 23208c2ecf20Sopenharmony_ci u16 peers_snd_nxt, 23218c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 23228c2ecf20Sopenharmony_ci{ 23238c2ecf20Sopenharmony_ci struct sk_buff *skb; 23248c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 23258c2ecf20Sopenharmony_ci struct sk_buff *dfrd_skb = skb_peek(&l->deferdq); 23268c2ecf20Sopenharmony_ci u16 ack = l->rcv_nxt - 1; 23278c2ecf20Sopenharmony_ci u16 gap_to = peers_snd_nxt - 1; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci skb = tipc_msg_create(BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, 23308c2ecf20Sopenharmony_ci 0, l->addr, tipc_own_addr(l->net), 0, 0, 0); 23318c2ecf20Sopenharmony_ci if (!skb) 23328c2ecf20Sopenharmony_ci return false; 23338c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 23348c2ecf20Sopenharmony_ci msg_set_last_bcast(hdr, l->bc_sndlink->snd_nxt - 1); 23358c2ecf20Sopenharmony_ci msg_set_bcast_ack(hdr, ack); 23368c2ecf20Sopenharmony_ci msg_set_bcgap_after(hdr, ack); 23378c2ecf20Sopenharmony_ci if (dfrd_skb) 23388c2ecf20Sopenharmony_ci gap_to = buf_seqno(dfrd_skb) - 1; 23398c2ecf20Sopenharmony_ci msg_set_bcgap_to(hdr, gap_to); 23408c2ecf20Sopenharmony_ci msg_set_non_seq(hdr, bcast); 23418c2ecf20Sopenharmony_ci __skb_queue_tail(xmitq, skb); 23428c2ecf20Sopenharmony_ci return true; 23438c2ecf20Sopenharmony_ci} 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci/* tipc_link_build_bc_init_msg() - synchronize broadcast link endpoints. 23468c2ecf20Sopenharmony_ci * 23478c2ecf20Sopenharmony_ci * Give a newly added peer node the sequence number where it should 23488c2ecf20Sopenharmony_ci * start receiving and acking broadcast packets. 23498c2ecf20Sopenharmony_ci */ 23508c2ecf20Sopenharmony_cistatic void tipc_link_build_bc_init_msg(struct tipc_link *l, 23518c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 23528c2ecf20Sopenharmony_ci{ 23538c2ecf20Sopenharmony_ci struct sk_buff_head list; 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci __skb_queue_head_init(&list); 23568c2ecf20Sopenharmony_ci if (!tipc_link_build_bc_proto_msg(l->bc_rcvlink, false, 0, &list)) 23578c2ecf20Sopenharmony_ci return; 23588c2ecf20Sopenharmony_ci msg_set_bc_ack_invalid(buf_msg(skb_peek(&list)), true); 23598c2ecf20Sopenharmony_ci tipc_link_xmit(l, &list, xmitq); 23608c2ecf20Sopenharmony_ci} 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci/* tipc_link_bc_init_rcv - receive initial broadcast synch data from peer 23638c2ecf20Sopenharmony_ci */ 23648c2ecf20Sopenharmony_civoid tipc_link_bc_init_rcv(struct tipc_link *l, struct tipc_msg *hdr) 23658c2ecf20Sopenharmony_ci{ 23668c2ecf20Sopenharmony_ci int mtyp = msg_type(hdr); 23678c2ecf20Sopenharmony_ci u16 peers_snd_nxt = msg_bc_snd_nxt(hdr); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci if (link_is_up(l)) 23708c2ecf20Sopenharmony_ci return; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci if (msg_user(hdr) == BCAST_PROTOCOL) { 23738c2ecf20Sopenharmony_ci l->rcv_nxt = peers_snd_nxt; 23748c2ecf20Sopenharmony_ci l->state = LINK_ESTABLISHED; 23758c2ecf20Sopenharmony_ci return; 23768c2ecf20Sopenharmony_ci } 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci if (l->peer_caps & TIPC_BCAST_SYNCH) 23798c2ecf20Sopenharmony_ci return; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci if (msg_peer_node_is_up(hdr)) 23828c2ecf20Sopenharmony_ci return; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci /* Compatibility: accept older, less safe initial synch data */ 23858c2ecf20Sopenharmony_ci if ((mtyp == RESET_MSG) || (mtyp == ACTIVATE_MSG)) 23868c2ecf20Sopenharmony_ci l->rcv_nxt = peers_snd_nxt; 23878c2ecf20Sopenharmony_ci} 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci/* tipc_link_bc_sync_rcv - update rcv link according to peer's send state 23908c2ecf20Sopenharmony_ci */ 23918c2ecf20Sopenharmony_ciint tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr, 23928c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 23938c2ecf20Sopenharmony_ci{ 23948c2ecf20Sopenharmony_ci u16 peers_snd_nxt = msg_bc_snd_nxt(hdr); 23958c2ecf20Sopenharmony_ci int rc = 0; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci if (!link_is_up(l)) 23988c2ecf20Sopenharmony_ci return rc; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci if (!msg_peer_node_is_up(hdr)) 24018c2ecf20Sopenharmony_ci return rc; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci /* Open when peer ackowledges our bcast init msg (pkt #1) */ 24048c2ecf20Sopenharmony_ci if (msg_ack(hdr)) 24058c2ecf20Sopenharmony_ci l->bc_peer_is_up = true; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci if (!l->bc_peer_is_up) 24088c2ecf20Sopenharmony_ci return rc; 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci /* Ignore if peers_snd_nxt goes beyond receive window */ 24118c2ecf20Sopenharmony_ci if (more(peers_snd_nxt, l->rcv_nxt + l->window)) 24128c2ecf20Sopenharmony_ci return rc; 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci l->snd_nxt = peers_snd_nxt; 24158c2ecf20Sopenharmony_ci if (link_bc_rcv_gap(l)) 24168c2ecf20Sopenharmony_ci rc |= TIPC_LINK_SND_STATE; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci /* Return now if sender supports nack via STATE messages */ 24198c2ecf20Sopenharmony_ci if (l->peer_caps & TIPC_BCAST_STATE_NACK) 24208c2ecf20Sopenharmony_ci return rc; 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci /* Otherwise, be backwards compatible */ 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci if (!more(peers_snd_nxt, l->rcv_nxt)) { 24258c2ecf20Sopenharmony_ci l->nack_state = BC_NACK_SND_CONDITIONAL; 24268c2ecf20Sopenharmony_ci return 0; 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci /* Don't NACK if one was recently sent or peeked */ 24308c2ecf20Sopenharmony_ci if (l->nack_state == BC_NACK_SND_SUPPRESS) { 24318c2ecf20Sopenharmony_ci l->nack_state = BC_NACK_SND_UNCONDITIONAL; 24328c2ecf20Sopenharmony_ci return 0; 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci /* Conditionally delay NACK sending until next synch rcv */ 24368c2ecf20Sopenharmony_ci if (l->nack_state == BC_NACK_SND_CONDITIONAL) { 24378c2ecf20Sopenharmony_ci l->nack_state = BC_NACK_SND_UNCONDITIONAL; 24388c2ecf20Sopenharmony_ci if ((peers_snd_nxt - l->rcv_nxt) < TIPC_MIN_LINK_WIN) 24398c2ecf20Sopenharmony_ci return 0; 24408c2ecf20Sopenharmony_ci } 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci /* Send NACK now but suppress next one */ 24438c2ecf20Sopenharmony_ci tipc_link_build_bc_proto_msg(l, true, peers_snd_nxt, xmitq); 24448c2ecf20Sopenharmony_ci l->nack_state = BC_NACK_SND_SUPPRESS; 24458c2ecf20Sopenharmony_ci return 0; 24468c2ecf20Sopenharmony_ci} 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ciint tipc_link_bc_ack_rcv(struct tipc_link *r, u16 acked, u16 gap, 24498c2ecf20Sopenharmony_ci struct tipc_gap_ack_blks *ga, 24508c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq, 24518c2ecf20Sopenharmony_ci struct sk_buff_head *retrq) 24528c2ecf20Sopenharmony_ci{ 24538c2ecf20Sopenharmony_ci struct tipc_link *l = r->bc_sndlink; 24548c2ecf20Sopenharmony_ci bool unused = false; 24558c2ecf20Sopenharmony_ci int rc = 0; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci if (!link_is_up(r) || !r->bc_peer_is_up) 24588c2ecf20Sopenharmony_ci return 0; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (gap) { 24618c2ecf20Sopenharmony_ci l->stats.recv_nacks++; 24628c2ecf20Sopenharmony_ci r->stats.recv_nacks++; 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci if (less(acked, r->acked) || (acked == r->acked && !gap && !ga)) 24668c2ecf20Sopenharmony_ci return 0; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci trace_tipc_link_bc_ack(r, acked, gap, &l->transmq); 24698c2ecf20Sopenharmony_ci tipc_link_advance_transmq(l, r, acked, gap, ga, retrq, &unused, &rc); 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci tipc_link_advance_backlog(l, xmitq); 24728c2ecf20Sopenharmony_ci if (unlikely(!skb_queue_empty(&l->wakeupq))) 24738c2ecf20Sopenharmony_ci link_prepare_wakeup(l); 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci return rc; 24768c2ecf20Sopenharmony_ci} 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci/* tipc_link_bc_nack_rcv(): receive broadcast nack message 24798c2ecf20Sopenharmony_ci * This function is here for backwards compatibility, since 24808c2ecf20Sopenharmony_ci * no BCAST_PROTOCOL/STATE messages occur from TIPC v2.5. 24818c2ecf20Sopenharmony_ci */ 24828c2ecf20Sopenharmony_ciint tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb, 24838c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 24848c2ecf20Sopenharmony_ci{ 24858c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 24868c2ecf20Sopenharmony_ci u32 dnode = msg_destnode(hdr); 24878c2ecf20Sopenharmony_ci int mtyp = msg_type(hdr); 24888c2ecf20Sopenharmony_ci u16 acked = msg_bcast_ack(hdr); 24898c2ecf20Sopenharmony_ci u16 from = acked + 1; 24908c2ecf20Sopenharmony_ci u16 to = msg_bcgap_to(hdr); 24918c2ecf20Sopenharmony_ci u16 peers_snd_nxt = to + 1; 24928c2ecf20Sopenharmony_ci int rc = 0; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci kfree_skb(skb); 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci if (!tipc_link_is_up(l) || !l->bc_peer_is_up) 24978c2ecf20Sopenharmony_ci return 0; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci if (mtyp != STATE_MSG) 25008c2ecf20Sopenharmony_ci return 0; 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci if (dnode == tipc_own_addr(l->net)) { 25038c2ecf20Sopenharmony_ci rc = tipc_link_bc_ack_rcv(l, acked, to - acked, NULL, xmitq, 25048c2ecf20Sopenharmony_ci xmitq); 25058c2ecf20Sopenharmony_ci l->stats.recv_nacks++; 25068c2ecf20Sopenharmony_ci return rc; 25078c2ecf20Sopenharmony_ci } 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci /* Msg for other node => suppress own NACK at next sync if applicable */ 25108c2ecf20Sopenharmony_ci if (more(peers_snd_nxt, l->rcv_nxt) && !less(l->rcv_nxt, from)) 25118c2ecf20Sopenharmony_ci l->nack_state = BC_NACK_SND_SUPPRESS; 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci return 0; 25148c2ecf20Sopenharmony_ci} 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_civoid tipc_link_set_queue_limits(struct tipc_link *l, u32 min_win, u32 max_win) 25178c2ecf20Sopenharmony_ci{ 25188c2ecf20Sopenharmony_ci int max_bulk = TIPC_MAX_PUBL / (l->mtu / ITEM_SIZE); 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci l->min_win = min_win; 25218c2ecf20Sopenharmony_ci l->ssthresh = max_win; 25228c2ecf20Sopenharmony_ci l->max_win = max_win; 25238c2ecf20Sopenharmony_ci l->window = min_win; 25248c2ecf20Sopenharmony_ci l->backlog[TIPC_LOW_IMPORTANCE].limit = min_win * 2; 25258c2ecf20Sopenharmony_ci l->backlog[TIPC_MEDIUM_IMPORTANCE].limit = min_win * 4; 25268c2ecf20Sopenharmony_ci l->backlog[TIPC_HIGH_IMPORTANCE].limit = min_win * 6; 25278c2ecf20Sopenharmony_ci l->backlog[TIPC_CRITICAL_IMPORTANCE].limit = min_win * 8; 25288c2ecf20Sopenharmony_ci l->backlog[TIPC_SYSTEM_IMPORTANCE].limit = max_bulk; 25298c2ecf20Sopenharmony_ci} 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci/** 25328c2ecf20Sopenharmony_ci * link_reset_stats - reset link statistics 25338c2ecf20Sopenharmony_ci * @l: pointer to link 25348c2ecf20Sopenharmony_ci */ 25358c2ecf20Sopenharmony_civoid tipc_link_reset_stats(struct tipc_link *l) 25368c2ecf20Sopenharmony_ci{ 25378c2ecf20Sopenharmony_ci memset(&l->stats, 0, sizeof(l->stats)); 25388c2ecf20Sopenharmony_ci} 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_cistatic void link_print(struct tipc_link *l, const char *str) 25418c2ecf20Sopenharmony_ci{ 25428c2ecf20Sopenharmony_ci struct sk_buff *hskb = skb_peek(&l->transmq); 25438c2ecf20Sopenharmony_ci u16 head = hskb ? msg_seqno(buf_msg(hskb)) : l->snd_nxt - 1; 25448c2ecf20Sopenharmony_ci u16 tail = l->snd_nxt - 1; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci pr_info("%s Link <%s> state %x\n", str, l->name, l->state); 25478c2ecf20Sopenharmony_ci pr_info("XMTQ: %u [%u-%u], BKLGQ: %u, SNDNX: %u, RCVNX: %u\n", 25488c2ecf20Sopenharmony_ci skb_queue_len(&l->transmq), head, tail, 25498c2ecf20Sopenharmony_ci skb_queue_len(&l->backlogq), l->snd_nxt, l->rcv_nxt); 25508c2ecf20Sopenharmony_ci} 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci/* Parse and validate nested (link) properties valid for media, bearer and link 25538c2ecf20Sopenharmony_ci */ 25548c2ecf20Sopenharmony_ciint tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]) 25558c2ecf20Sopenharmony_ci{ 25568c2ecf20Sopenharmony_ci int err; 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(props, TIPC_NLA_PROP_MAX, prop, 25598c2ecf20Sopenharmony_ci tipc_nl_prop_policy, NULL); 25608c2ecf20Sopenharmony_ci if (err) 25618c2ecf20Sopenharmony_ci return err; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_PRIO]) { 25648c2ecf20Sopenharmony_ci u32 prio; 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); 25678c2ecf20Sopenharmony_ci if (prio > TIPC_MAX_LINK_PRI) 25688c2ecf20Sopenharmony_ci return -EINVAL; 25698c2ecf20Sopenharmony_ci } 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_TOL]) { 25728c2ecf20Sopenharmony_ci u32 tol; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]); 25758c2ecf20Sopenharmony_ci if ((tol < TIPC_MIN_LINK_TOL) || (tol > TIPC_MAX_LINK_TOL)) 25768c2ecf20Sopenharmony_ci return -EINVAL; 25778c2ecf20Sopenharmony_ci } 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_WIN]) { 25808c2ecf20Sopenharmony_ci u32 max_win; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci max_win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 25838c2ecf20Sopenharmony_ci if (max_win < TIPC_DEF_LINK_WIN || max_win > TIPC_MAX_LINK_WIN) 25848c2ecf20Sopenharmony_ci return -EINVAL; 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci return 0; 25888c2ecf20Sopenharmony_ci} 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_cistatic int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s) 25918c2ecf20Sopenharmony_ci{ 25928c2ecf20Sopenharmony_ci int i; 25938c2ecf20Sopenharmony_ci struct nlattr *stats; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci struct nla_map { 25968c2ecf20Sopenharmony_ci u32 key; 25978c2ecf20Sopenharmony_ci u32 val; 25988c2ecf20Sopenharmony_ci }; 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci struct nla_map map[] = { 26018c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_INFO, 0}, 26028c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_FRAGMENTS, s->recv_fragments}, 26038c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_FRAGMENTED, s->recv_fragmented}, 26048c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_BUNDLES, s->recv_bundles}, 26058c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_BUNDLED, s->recv_bundled}, 26068c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_INFO, 0}, 26078c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_FRAGMENTS, s->sent_fragments}, 26088c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_FRAGMENTED, s->sent_fragmented}, 26098c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_BUNDLES, s->sent_bundles}, 26108c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_BUNDLED, s->sent_bundled}, 26118c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_PROF_TOT, (s->msg_length_counts) ? 26128c2ecf20Sopenharmony_ci s->msg_length_counts : 1}, 26138c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_CNT, s->msg_length_counts}, 26148c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_TOT, s->msg_lengths_total}, 26158c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_P0, s->msg_length_profile[0]}, 26168c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_P1, s->msg_length_profile[1]}, 26178c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_P2, s->msg_length_profile[2]}, 26188c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_P3, s->msg_length_profile[3]}, 26198c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_P4, s->msg_length_profile[4]}, 26208c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_P5, s->msg_length_profile[5]}, 26218c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MSG_LEN_P6, s->msg_length_profile[6]}, 26228c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_STATES, s->recv_states}, 26238c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_PROBES, s->recv_probes}, 26248c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_NACKS, s->recv_nacks}, 26258c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_DEFERRED, s->deferred_recv}, 26268c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_STATES, s->sent_states}, 26278c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_PROBES, s->sent_probes}, 26288c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_NACKS, s->sent_nacks}, 26298c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_ACKS, s->sent_acks}, 26308c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RETRANSMITTED, s->retransmitted}, 26318c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_DUPLICATES, s->duplicates}, 26328c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_LINK_CONGS, s->link_congs}, 26338c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MAX_QUEUE, s->max_queue_sz}, 26348c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_AVG_QUEUE, s->queue_sz_counts ? 26358c2ecf20Sopenharmony_ci (s->accu_queue_sz / s->queue_sz_counts) : 0} 26368c2ecf20Sopenharmony_ci }; 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci stats = nla_nest_start_noflag(skb, TIPC_NLA_LINK_STATS); 26398c2ecf20Sopenharmony_ci if (!stats) 26408c2ecf20Sopenharmony_ci return -EMSGSIZE; 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(map); i++) 26438c2ecf20Sopenharmony_ci if (nla_put_u32(skb, map[i].key, map[i].val)) 26448c2ecf20Sopenharmony_ci goto msg_full; 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci nla_nest_end(skb, stats); 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci return 0; 26498c2ecf20Sopenharmony_cimsg_full: 26508c2ecf20Sopenharmony_ci nla_nest_cancel(skb, stats); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci return -EMSGSIZE; 26538c2ecf20Sopenharmony_ci} 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci/* Caller should hold appropriate locks to protect the link */ 26568c2ecf20Sopenharmony_ciint __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg, 26578c2ecf20Sopenharmony_ci struct tipc_link *link, int nlflags) 26588c2ecf20Sopenharmony_ci{ 26598c2ecf20Sopenharmony_ci u32 self = tipc_own_addr(net); 26608c2ecf20Sopenharmony_ci struct nlattr *attrs; 26618c2ecf20Sopenharmony_ci struct nlattr *prop; 26628c2ecf20Sopenharmony_ci void *hdr; 26638c2ecf20Sopenharmony_ci int err; 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, 26668c2ecf20Sopenharmony_ci nlflags, TIPC_NL_LINK_GET); 26678c2ecf20Sopenharmony_ci if (!hdr) 26688c2ecf20Sopenharmony_ci return -EMSGSIZE; 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_LINK); 26718c2ecf20Sopenharmony_ci if (!attrs) 26728c2ecf20Sopenharmony_ci goto msg_full; 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, link->name)) 26758c2ecf20Sopenharmony_ci goto attr_msg_full; 26768c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_LINK_DEST, tipc_cluster_mask(self))) 26778c2ecf20Sopenharmony_ci goto attr_msg_full; 26788c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->mtu)) 26798c2ecf20Sopenharmony_ci goto attr_msg_full; 26808c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, link->stats.recv_pkts)) 26818c2ecf20Sopenharmony_ci goto attr_msg_full; 26828c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, link->stats.sent_pkts)) 26838c2ecf20Sopenharmony_ci goto attr_msg_full; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci if (tipc_link_is_up(link)) 26868c2ecf20Sopenharmony_ci if (nla_put_flag(msg->skb, TIPC_NLA_LINK_UP)) 26878c2ecf20Sopenharmony_ci goto attr_msg_full; 26888c2ecf20Sopenharmony_ci if (link->active) 26898c2ecf20Sopenharmony_ci if (nla_put_flag(msg->skb, TIPC_NLA_LINK_ACTIVE)) 26908c2ecf20Sopenharmony_ci goto attr_msg_full; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci prop = nla_nest_start_noflag(msg->skb, TIPC_NLA_LINK_PROP); 26938c2ecf20Sopenharmony_ci if (!prop) 26948c2ecf20Sopenharmony_ci goto attr_msg_full; 26958c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, link->priority)) 26968c2ecf20Sopenharmony_ci goto prop_msg_full; 26978c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, link->tolerance)) 26988c2ecf20Sopenharmony_ci goto prop_msg_full; 26998c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, 27008c2ecf20Sopenharmony_ci link->window)) 27018c2ecf20Sopenharmony_ci goto prop_msg_full; 27028c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, link->priority)) 27038c2ecf20Sopenharmony_ci goto prop_msg_full; 27048c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, prop); 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci err = __tipc_nl_add_stats(msg->skb, &link->stats); 27078c2ecf20Sopenharmony_ci if (err) 27088c2ecf20Sopenharmony_ci goto attr_msg_full; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, attrs); 27118c2ecf20Sopenharmony_ci genlmsg_end(msg->skb, hdr); 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci return 0; 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ciprop_msg_full: 27168c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, prop); 27178c2ecf20Sopenharmony_ciattr_msg_full: 27188c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, attrs); 27198c2ecf20Sopenharmony_cimsg_full: 27208c2ecf20Sopenharmony_ci genlmsg_cancel(msg->skb, hdr); 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci return -EMSGSIZE; 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_cistatic int __tipc_nl_add_bc_link_stat(struct sk_buff *skb, 27268c2ecf20Sopenharmony_ci struct tipc_stats *stats) 27278c2ecf20Sopenharmony_ci{ 27288c2ecf20Sopenharmony_ci int i; 27298c2ecf20Sopenharmony_ci struct nlattr *nest; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci struct nla_map { 27328c2ecf20Sopenharmony_ci __u32 key; 27338c2ecf20Sopenharmony_ci __u32 val; 27348c2ecf20Sopenharmony_ci }; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci struct nla_map map[] = { 27378c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_INFO, stats->recv_pkts}, 27388c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_FRAGMENTS, stats->recv_fragments}, 27398c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_FRAGMENTED, stats->recv_fragmented}, 27408c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_BUNDLES, stats->recv_bundles}, 27418c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_BUNDLED, stats->recv_bundled}, 27428c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_INFO, stats->sent_pkts}, 27438c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_FRAGMENTS, stats->sent_fragments}, 27448c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_FRAGMENTED, stats->sent_fragmented}, 27458c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_BUNDLES, stats->sent_bundles}, 27468c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_BUNDLED, stats->sent_bundled}, 27478c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_NACKS, stats->recv_nacks}, 27488c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RX_DEFERRED, stats->deferred_recv}, 27498c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_NACKS, stats->sent_nacks}, 27508c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_TX_ACKS, stats->sent_acks}, 27518c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_RETRANSMITTED, stats->retransmitted}, 27528c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_DUPLICATES, stats->duplicates}, 27538c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_LINK_CONGS, stats->link_congs}, 27548c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_MAX_QUEUE, stats->max_queue_sz}, 27558c2ecf20Sopenharmony_ci {TIPC_NLA_STATS_AVG_QUEUE, stats->queue_sz_counts ? 27568c2ecf20Sopenharmony_ci (stats->accu_queue_sz / stats->queue_sz_counts) : 0} 27578c2ecf20Sopenharmony_ci }; 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci nest = nla_nest_start_noflag(skb, TIPC_NLA_LINK_STATS); 27608c2ecf20Sopenharmony_ci if (!nest) 27618c2ecf20Sopenharmony_ci return -EMSGSIZE; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(map); i++) 27648c2ecf20Sopenharmony_ci if (nla_put_u32(skb, map[i].key, map[i].val)) 27658c2ecf20Sopenharmony_ci goto msg_full; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci nla_nest_end(skb, nest); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci return 0; 27708c2ecf20Sopenharmony_cimsg_full: 27718c2ecf20Sopenharmony_ci nla_nest_cancel(skb, nest); 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci return -EMSGSIZE; 27748c2ecf20Sopenharmony_ci} 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ciint tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg, 27778c2ecf20Sopenharmony_ci struct tipc_link *bcl) 27788c2ecf20Sopenharmony_ci{ 27798c2ecf20Sopenharmony_ci int err; 27808c2ecf20Sopenharmony_ci void *hdr; 27818c2ecf20Sopenharmony_ci struct nlattr *attrs; 27828c2ecf20Sopenharmony_ci struct nlattr *prop; 27838c2ecf20Sopenharmony_ci u32 bc_mode = tipc_bcast_get_mode(net); 27848c2ecf20Sopenharmony_ci u32 bc_ratio = tipc_bcast_get_broadcast_ratio(net); 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci if (!bcl) 27878c2ecf20Sopenharmony_ci return 0; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci tipc_bcast_lock(net); 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, 27928c2ecf20Sopenharmony_ci NLM_F_MULTI, TIPC_NL_LINK_GET); 27938c2ecf20Sopenharmony_ci if (!hdr) { 27948c2ecf20Sopenharmony_ci tipc_bcast_unlock(net); 27958c2ecf20Sopenharmony_ci return -EMSGSIZE; 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_LINK); 27998c2ecf20Sopenharmony_ci if (!attrs) 28008c2ecf20Sopenharmony_ci goto msg_full; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci /* The broadcast link is always up */ 28038c2ecf20Sopenharmony_ci if (nla_put_flag(msg->skb, TIPC_NLA_LINK_UP)) 28048c2ecf20Sopenharmony_ci goto attr_msg_full; 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci if (nla_put_flag(msg->skb, TIPC_NLA_LINK_BROADCAST)) 28078c2ecf20Sopenharmony_ci goto attr_msg_full; 28088c2ecf20Sopenharmony_ci if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, bcl->name)) 28098c2ecf20Sopenharmony_ci goto attr_msg_full; 28108c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, 0)) 28118c2ecf20Sopenharmony_ci goto attr_msg_full; 28128c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, 0)) 28138c2ecf20Sopenharmony_ci goto attr_msg_full; 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci prop = nla_nest_start_noflag(msg->skb, TIPC_NLA_LINK_PROP); 28168c2ecf20Sopenharmony_ci if (!prop) 28178c2ecf20Sopenharmony_ci goto attr_msg_full; 28188c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bcl->max_win)) 28198c2ecf20Sopenharmony_ci goto prop_msg_full; 28208c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_BROADCAST, bc_mode)) 28218c2ecf20Sopenharmony_ci goto prop_msg_full; 28228c2ecf20Sopenharmony_ci if (bc_mode & BCLINK_MODE_SEL) 28238c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_BROADCAST_RATIO, 28248c2ecf20Sopenharmony_ci bc_ratio)) 28258c2ecf20Sopenharmony_ci goto prop_msg_full; 28268c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, prop); 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci err = __tipc_nl_add_bc_link_stat(msg->skb, &bcl->stats); 28298c2ecf20Sopenharmony_ci if (err) 28308c2ecf20Sopenharmony_ci goto attr_msg_full; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci tipc_bcast_unlock(net); 28338c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, attrs); 28348c2ecf20Sopenharmony_ci genlmsg_end(msg->skb, hdr); 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci return 0; 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ciprop_msg_full: 28398c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, prop); 28408c2ecf20Sopenharmony_ciattr_msg_full: 28418c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, attrs); 28428c2ecf20Sopenharmony_cimsg_full: 28438c2ecf20Sopenharmony_ci tipc_bcast_unlock(net); 28448c2ecf20Sopenharmony_ci genlmsg_cancel(msg->skb, hdr); 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci return -EMSGSIZE; 28478c2ecf20Sopenharmony_ci} 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_civoid tipc_link_set_tolerance(struct tipc_link *l, u32 tol, 28508c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 28518c2ecf20Sopenharmony_ci{ 28528c2ecf20Sopenharmony_ci l->tolerance = tol; 28538c2ecf20Sopenharmony_ci if (l->bc_rcvlink) 28548c2ecf20Sopenharmony_ci l->bc_rcvlink->tolerance = tol; 28558c2ecf20Sopenharmony_ci if (link_is_up(l)) 28568c2ecf20Sopenharmony_ci tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 0, tol, 0, xmitq); 28578c2ecf20Sopenharmony_ci} 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_civoid tipc_link_set_prio(struct tipc_link *l, u32 prio, 28608c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 28618c2ecf20Sopenharmony_ci{ 28628c2ecf20Sopenharmony_ci l->priority = prio; 28638c2ecf20Sopenharmony_ci tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 0, 0, prio, xmitq); 28648c2ecf20Sopenharmony_ci} 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_civoid tipc_link_set_abort_limit(struct tipc_link *l, u32 limit) 28678c2ecf20Sopenharmony_ci{ 28688c2ecf20Sopenharmony_ci l->abort_limit = limit; 28698c2ecf20Sopenharmony_ci} 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci/** 28728c2ecf20Sopenharmony_ci * tipc_link_dump - dump TIPC link data 28738c2ecf20Sopenharmony_ci * @l: tipc link to be dumped 28748c2ecf20Sopenharmony_ci * @dqueues: bitmask to decide if any link queue to be dumped? 28758c2ecf20Sopenharmony_ci * - TIPC_DUMP_NONE: don't dump link queues 28768c2ecf20Sopenharmony_ci * - TIPC_DUMP_TRANSMQ: dump link transmq queue 28778c2ecf20Sopenharmony_ci * - TIPC_DUMP_BACKLOGQ: dump link backlog queue 28788c2ecf20Sopenharmony_ci * - TIPC_DUMP_DEFERDQ: dump link deferd queue 28798c2ecf20Sopenharmony_ci * - TIPC_DUMP_INPUTQ: dump link input queue 28808c2ecf20Sopenharmony_ci * - TIPC_DUMP_WAKEUP: dump link wakeup queue 28818c2ecf20Sopenharmony_ci * - TIPC_DUMP_ALL: dump all the link queues above 28828c2ecf20Sopenharmony_ci * @buf: returned buffer of dump data in format 28838c2ecf20Sopenharmony_ci */ 28848c2ecf20Sopenharmony_ciint tipc_link_dump(struct tipc_link *l, u16 dqueues, char *buf) 28858c2ecf20Sopenharmony_ci{ 28868c2ecf20Sopenharmony_ci int i = 0; 28878c2ecf20Sopenharmony_ci size_t sz = (dqueues) ? LINK_LMAX : LINK_LMIN; 28888c2ecf20Sopenharmony_ci struct sk_buff_head *list; 28898c2ecf20Sopenharmony_ci struct sk_buff *hskb, *tskb; 28908c2ecf20Sopenharmony_ci u32 len; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci if (!l) { 28938c2ecf20Sopenharmony_ci i += scnprintf(buf, sz, "link data: (null)\n"); 28948c2ecf20Sopenharmony_ci return i; 28958c2ecf20Sopenharmony_ci } 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci i += scnprintf(buf, sz, "link data: %x", l->addr); 28988c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %x", l->state); 28998c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->in_session); 29008c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->session); 29018c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->peer_session); 29028c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->snd_nxt); 29038c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->rcv_nxt); 29048c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->snd_nxt_state); 29058c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->rcv_nxt_state); 29068c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %x", l->peer_caps); 29078c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->silent_intv_cnt); 29088c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->rst_cnt); 29098c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", 0); 29108c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", 0); 29118c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " %u", l->acked); 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci list = &l->transmq; 29148c2ecf20Sopenharmony_ci len = skb_queue_len(list); 29158c2ecf20Sopenharmony_ci hskb = skb_peek(list); 29168c2ecf20Sopenharmony_ci tskb = skb_peek_tail(list); 29178c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " | %u %u %u", len, 29188c2ecf20Sopenharmony_ci (hskb) ? msg_seqno(buf_msg(hskb)) : 0, 29198c2ecf20Sopenharmony_ci (tskb) ? msg_seqno(buf_msg(tskb)) : 0); 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci list = &l->deferdq; 29228c2ecf20Sopenharmony_ci len = skb_queue_len(list); 29238c2ecf20Sopenharmony_ci hskb = skb_peek(list); 29248c2ecf20Sopenharmony_ci tskb = skb_peek_tail(list); 29258c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " | %u %u %u", len, 29268c2ecf20Sopenharmony_ci (hskb) ? msg_seqno(buf_msg(hskb)) : 0, 29278c2ecf20Sopenharmony_ci (tskb) ? msg_seqno(buf_msg(tskb)) : 0); 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci list = &l->backlogq; 29308c2ecf20Sopenharmony_ci len = skb_queue_len(list); 29318c2ecf20Sopenharmony_ci hskb = skb_peek(list); 29328c2ecf20Sopenharmony_ci tskb = skb_peek_tail(list); 29338c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " | %u %u %u", len, 29348c2ecf20Sopenharmony_ci (hskb) ? msg_seqno(buf_msg(hskb)) : 0, 29358c2ecf20Sopenharmony_ci (tskb) ? msg_seqno(buf_msg(tskb)) : 0); 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci list = l->inputq; 29388c2ecf20Sopenharmony_ci len = skb_queue_len(list); 29398c2ecf20Sopenharmony_ci hskb = skb_peek(list); 29408c2ecf20Sopenharmony_ci tskb = skb_peek_tail(list); 29418c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, " | %u %u %u\n", len, 29428c2ecf20Sopenharmony_ci (hskb) ? msg_seqno(buf_msg(hskb)) : 0, 29438c2ecf20Sopenharmony_ci (tskb) ? msg_seqno(buf_msg(tskb)) : 0); 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci if (dqueues & TIPC_DUMP_TRANSMQ) { 29468c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "transmq: "); 29478c2ecf20Sopenharmony_ci i += tipc_list_dump(&l->transmq, false, buf + i); 29488c2ecf20Sopenharmony_ci } 29498c2ecf20Sopenharmony_ci if (dqueues & TIPC_DUMP_BACKLOGQ) { 29508c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, 29518c2ecf20Sopenharmony_ci "backlogq: <%u %u %u %u %u>, ", 29528c2ecf20Sopenharmony_ci l->backlog[TIPC_LOW_IMPORTANCE].len, 29538c2ecf20Sopenharmony_ci l->backlog[TIPC_MEDIUM_IMPORTANCE].len, 29548c2ecf20Sopenharmony_ci l->backlog[TIPC_HIGH_IMPORTANCE].len, 29558c2ecf20Sopenharmony_ci l->backlog[TIPC_CRITICAL_IMPORTANCE].len, 29568c2ecf20Sopenharmony_ci l->backlog[TIPC_SYSTEM_IMPORTANCE].len); 29578c2ecf20Sopenharmony_ci i += tipc_list_dump(&l->backlogq, false, buf + i); 29588c2ecf20Sopenharmony_ci } 29598c2ecf20Sopenharmony_ci if (dqueues & TIPC_DUMP_DEFERDQ) { 29608c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "deferdq: "); 29618c2ecf20Sopenharmony_ci i += tipc_list_dump(&l->deferdq, false, buf + i); 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci if (dqueues & TIPC_DUMP_INPUTQ) { 29648c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "inputq: "); 29658c2ecf20Sopenharmony_ci i += tipc_list_dump(l->inputq, false, buf + i); 29668c2ecf20Sopenharmony_ci } 29678c2ecf20Sopenharmony_ci if (dqueues & TIPC_DUMP_WAKEUP) { 29688c2ecf20Sopenharmony_ci i += scnprintf(buf + i, sz - i, "wakeup: "); 29698c2ecf20Sopenharmony_ci i += tipc_list_dump(&l->wakeupq, false, buf + i); 29708c2ecf20Sopenharmony_ci } 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci return i; 29738c2ecf20Sopenharmony_ci} 2974