18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* SCTP kernel implementation 38c2ecf20Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 48c2ecf20Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 58c2ecf20Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file is part of the SCTP kernel implementation 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * These functions handle output processing. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the 128c2ecf20Sopenharmony_ci * email address(es): 138c2ecf20Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Written or modified by: 168c2ecf20Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 178c2ecf20Sopenharmony_ci * Karl Knutson <karl@athena.chicago.il.us> 188c2ecf20Sopenharmony_ci * Jon Grimm <jgrimm@austin.ibm.com> 198c2ecf20Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/types.h> 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/wait.h> 278c2ecf20Sopenharmony_ci#include <linux/time.h> 288c2ecf20Sopenharmony_ci#include <linux/ip.h> 298c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 308c2ecf20Sopenharmony_ci#include <linux/init.h> 318c2ecf20Sopenharmony_ci#include <linux/slab.h> 328c2ecf20Sopenharmony_ci#include <net/inet_ecn.h> 338c2ecf20Sopenharmony_ci#include <net/ip.h> 348c2ecf20Sopenharmony_ci#include <net/icmp.h> 358c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/socket.h> /* for sa_family_t */ 388c2ecf20Sopenharmony_ci#include <net/sock.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h> 418c2ecf20Sopenharmony_ci#include <net/sctp/sm.h> 428c2ecf20Sopenharmony_ci#include <net/sctp/checksum.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Forward declarations for private helpers. */ 458c2ecf20Sopenharmony_cistatic enum sctp_xmit __sctp_packet_append_chunk(struct sctp_packet *packet, 468c2ecf20Sopenharmony_ci struct sctp_chunk *chunk); 478c2ecf20Sopenharmony_cistatic enum sctp_xmit sctp_packet_can_append_data(struct sctp_packet *packet, 488c2ecf20Sopenharmony_ci struct sctp_chunk *chunk); 498c2ecf20Sopenharmony_cistatic void sctp_packet_append_data(struct sctp_packet *packet, 508c2ecf20Sopenharmony_ci struct sctp_chunk *chunk); 518c2ecf20Sopenharmony_cistatic enum sctp_xmit sctp_packet_will_fit(struct sctp_packet *packet, 528c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 538c2ecf20Sopenharmony_ci u16 chunk_len); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void sctp_packet_reset(struct sctp_packet *packet) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci /* sctp_packet_transmit() relies on this to reset size to the 588c2ecf20Sopenharmony_ci * current overhead after sending packets. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci packet->size = packet->overhead; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci packet->has_cookie_echo = 0; 638c2ecf20Sopenharmony_ci packet->has_sack = 0; 648c2ecf20Sopenharmony_ci packet->has_data = 0; 658c2ecf20Sopenharmony_ci packet->has_auth = 0; 668c2ecf20Sopenharmony_ci packet->ipfragok = 0; 678c2ecf20Sopenharmony_ci packet->auth = NULL; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Config a packet. 718c2ecf20Sopenharmony_ci * This appears to be a followup set of initializations. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_civoid sctp_packet_config(struct sctp_packet *packet, __u32 vtag, 748c2ecf20Sopenharmony_ci int ecn_capable) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct sctp_transport *tp = packet->transport; 778c2ecf20Sopenharmony_ci struct sctp_association *asoc = tp->asoc; 788c2ecf20Sopenharmony_ci struct sctp_sock *sp = NULL; 798c2ecf20Sopenharmony_ci struct sock *sk; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); 828c2ecf20Sopenharmony_ci packet->vtag = vtag; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* do the following jobs only once for a flush schedule */ 858c2ecf20Sopenharmony_ci if (!sctp_packet_empty(packet)) 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* set packet max_size with pathmtu, then calculate overhead */ 898c2ecf20Sopenharmony_ci packet->max_size = tp->pathmtu; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (asoc) { 928c2ecf20Sopenharmony_ci sk = asoc->base.sk; 938c2ecf20Sopenharmony_ci sp = sctp_sk(sk); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci packet->overhead = sctp_mtu_payload(sp, 0, 0); 968c2ecf20Sopenharmony_ci packet->size = packet->overhead; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!asoc) 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* update dst or transport pathmtu if in need */ 1028c2ecf20Sopenharmony_ci if (!sctp_transport_dst_check(tp)) { 1038c2ecf20Sopenharmony_ci sctp_transport_route(tp, NULL, sp); 1048c2ecf20Sopenharmony_ci if (asoc->param_flags & SPP_PMTUD_ENABLE) 1058c2ecf20Sopenharmony_ci sctp_assoc_sync_pmtu(asoc); 1068c2ecf20Sopenharmony_ci } else if (!sctp_transport_pmtu_check(tp)) { 1078c2ecf20Sopenharmony_ci if (asoc->param_flags & SPP_PMTUD_ENABLE) 1088c2ecf20Sopenharmony_ci sctp_assoc_sync_pmtu(asoc); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (asoc->pmtu_pending) { 1128c2ecf20Sopenharmony_ci if (asoc->param_flags & SPP_PMTUD_ENABLE) 1138c2ecf20Sopenharmony_ci sctp_assoc_sync_pmtu(asoc); 1148c2ecf20Sopenharmony_ci asoc->pmtu_pending = 0; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* If there a is a prepend chunk stick it on the list before 1188c2ecf20Sopenharmony_ci * any other chunks get appended. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci if (ecn_capable) { 1218c2ecf20Sopenharmony_ci struct sctp_chunk *chunk = sctp_get_ecne_prepend(asoc); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (chunk) 1248c2ecf20Sopenharmony_ci sctp_packet_append_chunk(packet, chunk); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!tp->dst) 1288c2ecf20Sopenharmony_ci return; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* set packet max_size with gso_max_size if gso is enabled*/ 1318c2ecf20Sopenharmony_ci rcu_read_lock(); 1328c2ecf20Sopenharmony_ci if (__sk_dst_get(sk) != tp->dst) { 1338c2ecf20Sopenharmony_ci dst_hold(tp->dst); 1348c2ecf20Sopenharmony_ci sk_setup_caps(sk, tp->dst); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci packet->max_size = sk_can_gso(sk) ? tp->dst->dev->gso_max_size 1378c2ecf20Sopenharmony_ci : asoc->pathmtu; 1388c2ecf20Sopenharmony_ci rcu_read_unlock(); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* Initialize the packet structure. */ 1428c2ecf20Sopenharmony_civoid sctp_packet_init(struct sctp_packet *packet, 1438c2ecf20Sopenharmony_ci struct sctp_transport *transport, 1448c2ecf20Sopenharmony_ci __u16 sport, __u16 dport) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci pr_debug("%s: packet:%p transport:%p\n", __func__, packet, transport); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci packet->transport = transport; 1498c2ecf20Sopenharmony_ci packet->source_port = sport; 1508c2ecf20Sopenharmony_ci packet->destination_port = dport; 1518c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&packet->chunk_list); 1528c2ecf20Sopenharmony_ci /* The overhead will be calculated by sctp_packet_config() */ 1538c2ecf20Sopenharmony_ci packet->overhead = 0; 1548c2ecf20Sopenharmony_ci sctp_packet_reset(packet); 1558c2ecf20Sopenharmony_ci packet->vtag = 0; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* Free a packet. */ 1598c2ecf20Sopenharmony_civoid sctp_packet_free(struct sctp_packet *packet) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, *tmp; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci pr_debug("%s: packet:%p\n", __func__, packet); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) { 1668c2ecf20Sopenharmony_ci list_del_init(&chunk->list); 1678c2ecf20Sopenharmony_ci sctp_chunk_free(chunk); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* This routine tries to append the chunk to the offered packet. If adding 1728c2ecf20Sopenharmony_ci * the chunk causes the packet to exceed the path MTU and COOKIE_ECHO chunk 1738c2ecf20Sopenharmony_ci * is not present in the packet, it transmits the input packet. 1748c2ecf20Sopenharmony_ci * Data can be bundled with a packet containing a COOKIE_ECHO chunk as long 1758c2ecf20Sopenharmony_ci * as it can fit in the packet, but any more data that does not fit in this 1768c2ecf20Sopenharmony_ci * packet can be sent only after receiving the COOKIE_ACK. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_cienum sctp_xmit sctp_packet_transmit_chunk(struct sctp_packet *packet, 1798c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 1808c2ecf20Sopenharmony_ci int one_packet, gfp_t gfp) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci enum sctp_xmit retval; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci pr_debug("%s: packet:%p size:%zu chunk:%p size:%d\n", __func__, 1858c2ecf20Sopenharmony_ci packet, packet->size, chunk, chunk->skb ? chunk->skb->len : -1); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) { 1888c2ecf20Sopenharmony_ci case SCTP_XMIT_PMTU_FULL: 1898c2ecf20Sopenharmony_ci if (!packet->has_cookie_echo) { 1908c2ecf20Sopenharmony_ci int error = 0; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci error = sctp_packet_transmit(packet, gfp); 1938c2ecf20Sopenharmony_ci if (error < 0) 1948c2ecf20Sopenharmony_ci chunk->skb->sk->sk_err = -error; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* If we have an empty packet, then we can NOT ever 1978c2ecf20Sopenharmony_ci * return PMTU_FULL. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci if (!one_packet) 2008c2ecf20Sopenharmony_ci retval = sctp_packet_append_chunk(packet, 2018c2ecf20Sopenharmony_ci chunk); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci case SCTP_XMIT_RWND_FULL: 2068c2ecf20Sopenharmony_ci case SCTP_XMIT_OK: 2078c2ecf20Sopenharmony_ci case SCTP_XMIT_DELAY: 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return retval; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* Try to bundle an auth chunk into the packet. */ 2158c2ecf20Sopenharmony_cistatic enum sctp_xmit sctp_packet_bundle_auth(struct sctp_packet *pkt, 2168c2ecf20Sopenharmony_ci struct sctp_chunk *chunk) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct sctp_association *asoc = pkt->transport->asoc; 2198c2ecf20Sopenharmony_ci enum sctp_xmit retval = SCTP_XMIT_OK; 2208c2ecf20Sopenharmony_ci struct sctp_chunk *auth; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* if we don't have an association, we can't do authentication */ 2238c2ecf20Sopenharmony_ci if (!asoc) 2248c2ecf20Sopenharmony_ci return retval; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* See if this is an auth chunk we are bundling or if 2278c2ecf20Sopenharmony_ci * auth is already bundled. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->has_auth) 2308c2ecf20Sopenharmony_ci return retval; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* if the peer did not request this chunk to be authenticated, 2338c2ecf20Sopenharmony_ci * don't do it 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci if (!chunk->auth) 2368c2ecf20Sopenharmony_ci return retval; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci auth = sctp_make_auth(asoc, chunk->shkey->key_id); 2398c2ecf20Sopenharmony_ci if (!auth) 2408c2ecf20Sopenharmony_ci return retval; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci auth->shkey = chunk->shkey; 2438c2ecf20Sopenharmony_ci sctp_auth_shkey_hold(auth->shkey); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci retval = __sctp_packet_append_chunk(pkt, auth); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (retval != SCTP_XMIT_OK) 2488c2ecf20Sopenharmony_ci sctp_chunk_free(auth); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return retval; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* Try to bundle a SACK with the packet. */ 2548c2ecf20Sopenharmony_cistatic enum sctp_xmit sctp_packet_bundle_sack(struct sctp_packet *pkt, 2558c2ecf20Sopenharmony_ci struct sctp_chunk *chunk) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci enum sctp_xmit retval = SCTP_XMIT_OK; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* If sending DATA and haven't aleady bundled a SACK, try to 2608c2ecf20Sopenharmony_ci * bundle one in to the packet. 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ci if (sctp_chunk_is_data(chunk) && !pkt->has_sack && 2638c2ecf20Sopenharmony_ci !pkt->has_cookie_echo) { 2648c2ecf20Sopenharmony_ci struct sctp_association *asoc; 2658c2ecf20Sopenharmony_ci struct timer_list *timer; 2668c2ecf20Sopenharmony_ci asoc = pkt->transport->asoc; 2678c2ecf20Sopenharmony_ci timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* If the SACK timer is running, we have a pending SACK */ 2708c2ecf20Sopenharmony_ci if (timer_pending(timer)) { 2718c2ecf20Sopenharmony_ci struct sctp_chunk *sack; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (pkt->transport->sack_generation != 2748c2ecf20Sopenharmony_ci pkt->transport->asoc->peer.sack_generation) 2758c2ecf20Sopenharmony_ci return retval; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci asoc->a_rwnd = asoc->rwnd; 2788c2ecf20Sopenharmony_ci sack = sctp_make_sack(asoc); 2798c2ecf20Sopenharmony_ci if (sack) { 2808c2ecf20Sopenharmony_ci retval = __sctp_packet_append_chunk(pkt, sack); 2818c2ecf20Sopenharmony_ci if (retval != SCTP_XMIT_OK) { 2828c2ecf20Sopenharmony_ci sctp_chunk_free(sack); 2838c2ecf20Sopenharmony_ci goto out; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci SCTP_INC_STATS(asoc->base.net, 2868c2ecf20Sopenharmony_ci SCTP_MIB_OUTCTRLCHUNKS); 2878c2ecf20Sopenharmony_ci asoc->stats.octrlchunks++; 2888c2ecf20Sopenharmony_ci asoc->peer.sack_needed = 0; 2898c2ecf20Sopenharmony_ci if (del_timer(timer)) 2908c2ecf20Sopenharmony_ci sctp_association_put(asoc); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ciout: 2958c2ecf20Sopenharmony_ci return retval; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* Append a chunk to the offered packet reporting back any inability to do 3008c2ecf20Sopenharmony_ci * so. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic enum sctp_xmit __sctp_packet_append_chunk(struct sctp_packet *packet, 3038c2ecf20Sopenharmony_ci struct sctp_chunk *chunk) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci __u16 chunk_len = SCTP_PAD4(ntohs(chunk->chunk_hdr->length)); 3068c2ecf20Sopenharmony_ci enum sctp_xmit retval = SCTP_XMIT_OK; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Check to see if this chunk will fit into the packet */ 3098c2ecf20Sopenharmony_ci retval = sctp_packet_will_fit(packet, chunk, chunk_len); 3108c2ecf20Sopenharmony_ci if (retval != SCTP_XMIT_OK) 3118c2ecf20Sopenharmony_ci goto finish; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* We believe that this chunk is OK to add to the packet */ 3148c2ecf20Sopenharmony_ci switch (chunk->chunk_hdr->type) { 3158c2ecf20Sopenharmony_ci case SCTP_CID_DATA: 3168c2ecf20Sopenharmony_ci case SCTP_CID_I_DATA: 3178c2ecf20Sopenharmony_ci /* Account for the data being in the packet */ 3188c2ecf20Sopenharmony_ci sctp_packet_append_data(packet, chunk); 3198c2ecf20Sopenharmony_ci /* Disallow SACK bundling after DATA. */ 3208c2ecf20Sopenharmony_ci packet->has_sack = 1; 3218c2ecf20Sopenharmony_ci /* Disallow AUTH bundling after DATA */ 3228c2ecf20Sopenharmony_ci packet->has_auth = 1; 3238c2ecf20Sopenharmony_ci /* Let it be knows that packet has DATA in it */ 3248c2ecf20Sopenharmony_ci packet->has_data = 1; 3258c2ecf20Sopenharmony_ci /* timestamp the chunk for rtx purposes */ 3268c2ecf20Sopenharmony_ci chunk->sent_at = jiffies; 3278c2ecf20Sopenharmony_ci /* Mainly used for prsctp RTX policy */ 3288c2ecf20Sopenharmony_ci chunk->sent_count++; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci case SCTP_CID_COOKIE_ECHO: 3318c2ecf20Sopenharmony_ci packet->has_cookie_echo = 1; 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci case SCTP_CID_SACK: 3358c2ecf20Sopenharmony_ci packet->has_sack = 1; 3368c2ecf20Sopenharmony_ci if (chunk->asoc) 3378c2ecf20Sopenharmony_ci chunk->asoc->stats.osacks++; 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci case SCTP_CID_AUTH: 3418c2ecf20Sopenharmony_ci packet->has_auth = 1; 3428c2ecf20Sopenharmony_ci packet->auth = chunk; 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* It is OK to send this chunk. */ 3478c2ecf20Sopenharmony_ci list_add_tail(&chunk->list, &packet->chunk_list); 3488c2ecf20Sopenharmony_ci packet->size += chunk_len; 3498c2ecf20Sopenharmony_ci chunk->transport = packet->transport; 3508c2ecf20Sopenharmony_cifinish: 3518c2ecf20Sopenharmony_ci return retval; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/* Append a chunk to the offered packet reporting back any inability to do 3558c2ecf20Sopenharmony_ci * so. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_cienum sctp_xmit sctp_packet_append_chunk(struct sctp_packet *packet, 3588c2ecf20Sopenharmony_ci struct sctp_chunk *chunk) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci enum sctp_xmit retval = SCTP_XMIT_OK; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci pr_debug("%s: packet:%p chunk:%p\n", __func__, packet, chunk); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* Data chunks are special. Before seeing what else we can 3658c2ecf20Sopenharmony_ci * bundle into this packet, check to see if we are allowed to 3668c2ecf20Sopenharmony_ci * send this DATA. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci if (sctp_chunk_is_data(chunk)) { 3698c2ecf20Sopenharmony_ci retval = sctp_packet_can_append_data(packet, chunk); 3708c2ecf20Sopenharmony_ci if (retval != SCTP_XMIT_OK) 3718c2ecf20Sopenharmony_ci goto finish; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Try to bundle AUTH chunk */ 3758c2ecf20Sopenharmony_ci retval = sctp_packet_bundle_auth(packet, chunk); 3768c2ecf20Sopenharmony_ci if (retval != SCTP_XMIT_OK) 3778c2ecf20Sopenharmony_ci goto finish; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Try to bundle SACK chunk */ 3808c2ecf20Sopenharmony_ci retval = sctp_packet_bundle_sack(packet, chunk); 3818c2ecf20Sopenharmony_ci if (retval != SCTP_XMIT_OK) 3828c2ecf20Sopenharmony_ci goto finish; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci retval = __sctp_packet_append_chunk(packet, chunk); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cifinish: 3878c2ecf20Sopenharmony_ci return retval; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic void sctp_packet_gso_append(struct sk_buff *head, struct sk_buff *skb) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci if (SCTP_OUTPUT_CB(head)->last == head) 3938c2ecf20Sopenharmony_ci skb_shinfo(head)->frag_list = skb; 3948c2ecf20Sopenharmony_ci else 3958c2ecf20Sopenharmony_ci SCTP_OUTPUT_CB(head)->last->next = skb; 3968c2ecf20Sopenharmony_ci SCTP_OUTPUT_CB(head)->last = skb; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci head->truesize += skb->truesize; 3998c2ecf20Sopenharmony_ci head->data_len += skb->len; 4008c2ecf20Sopenharmony_ci head->len += skb->len; 4018c2ecf20Sopenharmony_ci refcount_add(skb->truesize, &head->sk->sk_wmem_alloc); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci __skb_header_release(skb); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int sctp_packet_pack(struct sctp_packet *packet, 4078c2ecf20Sopenharmony_ci struct sk_buff *head, int gso, gfp_t gfp) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct sctp_transport *tp = packet->transport; 4108c2ecf20Sopenharmony_ci struct sctp_auth_chunk *auth = NULL; 4118c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, *tmp; 4128c2ecf20Sopenharmony_ci int pkt_count = 0, pkt_size; 4138c2ecf20Sopenharmony_ci struct sock *sk = head->sk; 4148c2ecf20Sopenharmony_ci struct sk_buff *nskb; 4158c2ecf20Sopenharmony_ci int auth_len = 0; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (gso) { 4188c2ecf20Sopenharmony_ci skb_shinfo(head)->gso_type = sk->sk_gso_type; 4198c2ecf20Sopenharmony_ci SCTP_OUTPUT_CB(head)->last = head; 4208c2ecf20Sopenharmony_ci } else { 4218c2ecf20Sopenharmony_ci nskb = head; 4228c2ecf20Sopenharmony_ci pkt_size = packet->size; 4238c2ecf20Sopenharmony_ci goto merge; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci do { 4278c2ecf20Sopenharmony_ci /* calculate the pkt_size and alloc nskb */ 4288c2ecf20Sopenharmony_ci pkt_size = packet->overhead; 4298c2ecf20Sopenharmony_ci list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, 4308c2ecf20Sopenharmony_ci list) { 4318c2ecf20Sopenharmony_ci int padded = SCTP_PAD4(chunk->skb->len); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (chunk == packet->auth) 4348c2ecf20Sopenharmony_ci auth_len = padded; 4358c2ecf20Sopenharmony_ci else if (auth_len + padded + packet->overhead > 4368c2ecf20Sopenharmony_ci tp->pathmtu) 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci else if (pkt_size + padded > tp->pathmtu) 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci pkt_size += padded; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci nskb = alloc_skb(pkt_size + MAX_HEADER, gfp); 4438c2ecf20Sopenharmony_ci if (!nskb) 4448c2ecf20Sopenharmony_ci return 0; 4458c2ecf20Sopenharmony_ci skb_reserve(nskb, packet->overhead + MAX_HEADER); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cimerge: 4488c2ecf20Sopenharmony_ci /* merge chunks into nskb and append nskb into head list */ 4498c2ecf20Sopenharmony_ci pkt_size -= packet->overhead; 4508c2ecf20Sopenharmony_ci list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) { 4518c2ecf20Sopenharmony_ci int padding; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci list_del_init(&chunk->list); 4548c2ecf20Sopenharmony_ci if (sctp_chunk_is_data(chunk)) { 4558c2ecf20Sopenharmony_ci if (!sctp_chunk_retransmitted(chunk) && 4568c2ecf20Sopenharmony_ci !tp->rto_pending) { 4578c2ecf20Sopenharmony_ci chunk->rtt_in_progress = 1; 4588c2ecf20Sopenharmony_ci tp->rto_pending = 1; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci padding = SCTP_PAD4(chunk->skb->len) - chunk->skb->len; 4638c2ecf20Sopenharmony_ci if (padding) 4648c2ecf20Sopenharmony_ci skb_put_zero(chunk->skb, padding); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (chunk == packet->auth) 4678c2ecf20Sopenharmony_ci auth = (struct sctp_auth_chunk *) 4688c2ecf20Sopenharmony_ci skb_tail_pointer(nskb); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci skb_put_data(nskb, chunk->skb->data, chunk->skb->len); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci pr_debug("*** Chunk:%p[%s] %s 0x%x, length:%d, chunk->skb->len:%d, rtt_in_progress:%d\n", 4738c2ecf20Sopenharmony_ci chunk, 4748c2ecf20Sopenharmony_ci sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)), 4758c2ecf20Sopenharmony_ci chunk->has_tsn ? "TSN" : "No TSN", 4768c2ecf20Sopenharmony_ci chunk->has_tsn ? ntohl(chunk->subh.data_hdr->tsn) : 0, 4778c2ecf20Sopenharmony_ci ntohs(chunk->chunk_hdr->length), chunk->skb->len, 4788c2ecf20Sopenharmony_ci chunk->rtt_in_progress); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci pkt_size -= SCTP_PAD4(chunk->skb->len); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (!sctp_chunk_is_data(chunk) && chunk != packet->auth) 4838c2ecf20Sopenharmony_ci sctp_chunk_free(chunk); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (!pkt_size) 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (auth) { 4908c2ecf20Sopenharmony_ci sctp_auth_calculate_hmac(tp->asoc, nskb, auth, 4918c2ecf20Sopenharmony_ci packet->auth->shkey, gfp); 4928c2ecf20Sopenharmony_ci /* free auth if no more chunks, or add it back */ 4938c2ecf20Sopenharmony_ci if (list_empty(&packet->chunk_list)) 4948c2ecf20Sopenharmony_ci sctp_chunk_free(packet->auth); 4958c2ecf20Sopenharmony_ci else 4968c2ecf20Sopenharmony_ci list_add(&packet->auth->list, 4978c2ecf20Sopenharmony_ci &packet->chunk_list); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (gso) 5018c2ecf20Sopenharmony_ci sctp_packet_gso_append(head, nskb); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci pkt_count++; 5048c2ecf20Sopenharmony_ci } while (!list_empty(&packet->chunk_list)); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (gso) { 5078c2ecf20Sopenharmony_ci memset(head->cb, 0, max(sizeof(struct inet_skb_parm), 5088c2ecf20Sopenharmony_ci sizeof(struct inet6_skb_parm))); 5098c2ecf20Sopenharmony_ci skb_shinfo(head)->gso_segs = pkt_count; 5108c2ecf20Sopenharmony_ci skb_shinfo(head)->gso_size = GSO_BY_FRAGS; 5118c2ecf20Sopenharmony_ci rcu_read_lock(); 5128c2ecf20Sopenharmony_ci if (skb_dst(head) != tp->dst) { 5138c2ecf20Sopenharmony_ci dst_hold(tp->dst); 5148c2ecf20Sopenharmony_ci sk_setup_caps(sk, tp->dst); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci rcu_read_unlock(); 5178c2ecf20Sopenharmony_ci goto chksum; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (sctp_checksum_disable) 5218c2ecf20Sopenharmony_ci return 1; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (!(skb_dst(head)->dev->features & NETIF_F_SCTP_CRC) || 5248c2ecf20Sopenharmony_ci dst_xfrm(skb_dst(head)) || packet->ipfragok) { 5258c2ecf20Sopenharmony_ci struct sctphdr *sh = 5268c2ecf20Sopenharmony_ci (struct sctphdr *)skb_transport_header(head); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci sh->checksum = sctp_compute_cksum(head, 0); 5298c2ecf20Sopenharmony_ci } else { 5308c2ecf20Sopenharmony_cichksum: 5318c2ecf20Sopenharmony_ci head->ip_summed = CHECKSUM_PARTIAL; 5328c2ecf20Sopenharmony_ci head->csum_not_inet = 1; 5338c2ecf20Sopenharmony_ci head->csum_start = skb_transport_header(head) - head->head; 5348c2ecf20Sopenharmony_ci head->csum_offset = offsetof(struct sctphdr, checksum); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return pkt_count; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/* All packets are sent to the network through this function from 5418c2ecf20Sopenharmony_ci * sctp_outq_tail(). 5428c2ecf20Sopenharmony_ci * 5438c2ecf20Sopenharmony_ci * The return value is always 0 for now. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ciint sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct sctp_transport *tp = packet->transport; 5488c2ecf20Sopenharmony_ci struct sctp_association *asoc = tp->asoc; 5498c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, *tmp; 5508c2ecf20Sopenharmony_ci int pkt_count, gso = 0; 5518c2ecf20Sopenharmony_ci struct dst_entry *dst; 5528c2ecf20Sopenharmony_ci struct sk_buff *head; 5538c2ecf20Sopenharmony_ci struct sctphdr *sh; 5548c2ecf20Sopenharmony_ci struct sock *sk; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci pr_debug("%s: packet:%p\n", __func__, packet); 5578c2ecf20Sopenharmony_ci if (list_empty(&packet->chunk_list)) 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci chunk = list_entry(packet->chunk_list.next, struct sctp_chunk, list); 5608c2ecf20Sopenharmony_ci sk = chunk->skb->sk; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* check gso */ 5638c2ecf20Sopenharmony_ci if (packet->size > tp->pathmtu && !packet->ipfragok) { 5648c2ecf20Sopenharmony_ci if (!sk_can_gso(sk)) { 5658c2ecf20Sopenharmony_ci pr_err_once("Trying to GSO but underlying device doesn't support it."); 5668c2ecf20Sopenharmony_ci goto out; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci gso = 1; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* alloc head skb */ 5728c2ecf20Sopenharmony_ci head = alloc_skb((gso ? packet->overhead : packet->size) + 5738c2ecf20Sopenharmony_ci MAX_HEADER, gfp); 5748c2ecf20Sopenharmony_ci if (!head) 5758c2ecf20Sopenharmony_ci goto out; 5768c2ecf20Sopenharmony_ci skb_reserve(head, packet->overhead + MAX_HEADER); 5778c2ecf20Sopenharmony_ci skb_set_owner_w(head, sk); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* set sctp header */ 5808c2ecf20Sopenharmony_ci sh = skb_push(head, sizeof(struct sctphdr)); 5818c2ecf20Sopenharmony_ci skb_reset_transport_header(head); 5828c2ecf20Sopenharmony_ci sh->source = htons(packet->source_port); 5838c2ecf20Sopenharmony_ci sh->dest = htons(packet->destination_port); 5848c2ecf20Sopenharmony_ci sh->vtag = htonl(packet->vtag); 5858c2ecf20Sopenharmony_ci sh->checksum = 0; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* drop packet if no dst */ 5888c2ecf20Sopenharmony_ci dst = dst_clone(tp->dst); 5898c2ecf20Sopenharmony_ci if (!dst) { 5908c2ecf20Sopenharmony_ci IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); 5918c2ecf20Sopenharmony_ci kfree_skb(head); 5928c2ecf20Sopenharmony_ci goto out; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci skb_dst_set(head, dst); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* pack up chunks */ 5978c2ecf20Sopenharmony_ci pkt_count = sctp_packet_pack(packet, head, gso, gfp); 5988c2ecf20Sopenharmony_ci if (!pkt_count) { 5998c2ecf20Sopenharmony_ci kfree_skb(head); 6008c2ecf20Sopenharmony_ci goto out; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci pr_debug("***sctp_transmit_packet*** skb->len:%d\n", head->len); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* start autoclose timer */ 6058c2ecf20Sopenharmony_ci if (packet->has_data && sctp_state(asoc, ESTABLISHED) && 6068c2ecf20Sopenharmony_ci asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]) { 6078c2ecf20Sopenharmony_ci struct timer_list *timer = 6088c2ecf20Sopenharmony_ci &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; 6098c2ecf20Sopenharmony_ci unsigned long timeout = 6108c2ecf20Sopenharmony_ci asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (!mod_timer(timer, jiffies + timeout)) 6138c2ecf20Sopenharmony_ci sctp_association_hold(asoc); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* sctp xmit */ 6178c2ecf20Sopenharmony_ci tp->af_specific->ecn_capable(sk); 6188c2ecf20Sopenharmony_ci if (asoc) { 6198c2ecf20Sopenharmony_ci asoc->stats.opackets += pkt_count; 6208c2ecf20Sopenharmony_ci if (asoc->peer.last_sent_to != tp) 6218c2ecf20Sopenharmony_ci asoc->peer.last_sent_to = tp; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci head->ignore_df = packet->ipfragok; 6248c2ecf20Sopenharmony_ci if (tp->dst_pending_confirm) 6258c2ecf20Sopenharmony_ci skb_set_dst_pending_confirm(head, 1); 6268c2ecf20Sopenharmony_ci /* neighbour should be confirmed on successful transmission or 6278c2ecf20Sopenharmony_ci * positive error 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci if (tp->af_specific->sctp_xmit(head, tp) >= 0 && 6308c2ecf20Sopenharmony_ci tp->dst_pending_confirm) 6318c2ecf20Sopenharmony_ci tp->dst_pending_confirm = 0; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ciout: 6348c2ecf20Sopenharmony_ci list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) { 6358c2ecf20Sopenharmony_ci list_del_init(&chunk->list); 6368c2ecf20Sopenharmony_ci if (!sctp_chunk_is_data(chunk)) 6378c2ecf20Sopenharmony_ci sctp_chunk_free(chunk); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci sctp_packet_reset(packet); 6408c2ecf20Sopenharmony_ci return 0; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/******************************************************************** 6448c2ecf20Sopenharmony_ci * 2nd Level Abstractions 6458c2ecf20Sopenharmony_ci ********************************************************************/ 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/* This private function check to see if a chunk can be added */ 6488c2ecf20Sopenharmony_cistatic enum sctp_xmit sctp_packet_can_append_data(struct sctp_packet *packet, 6498c2ecf20Sopenharmony_ci struct sctp_chunk *chunk) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci size_t datasize, rwnd, inflight, flight_size; 6528c2ecf20Sopenharmony_ci struct sctp_transport *transport = packet->transport; 6538c2ecf20Sopenharmony_ci struct sctp_association *asoc = transport->asoc; 6548c2ecf20Sopenharmony_ci struct sctp_outq *q = &asoc->outqueue; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* RFC 2960 6.1 Transmission of DATA Chunks 6578c2ecf20Sopenharmony_ci * 6588c2ecf20Sopenharmony_ci * A) At any given time, the data sender MUST NOT transmit new data to 6598c2ecf20Sopenharmony_ci * any destination transport address if its peer's rwnd indicates 6608c2ecf20Sopenharmony_ci * that the peer has no buffer space (i.e. rwnd is 0, see Section 6618c2ecf20Sopenharmony_ci * 6.2.1). However, regardless of the value of rwnd (including if it 6628c2ecf20Sopenharmony_ci * is 0), the data sender can always have one DATA chunk in flight to 6638c2ecf20Sopenharmony_ci * the receiver if allowed by cwnd (see rule B below). This rule 6648c2ecf20Sopenharmony_ci * allows the sender to probe for a change in rwnd that the sender 6658c2ecf20Sopenharmony_ci * missed due to the SACK having been lost in transit from the data 6668c2ecf20Sopenharmony_ci * receiver to the data sender. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci rwnd = asoc->peer.rwnd; 6708c2ecf20Sopenharmony_ci inflight = q->outstanding_bytes; 6718c2ecf20Sopenharmony_ci flight_size = transport->flight_size; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci datasize = sctp_data_size(chunk); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (datasize > rwnd && inflight > 0) 6768c2ecf20Sopenharmony_ci /* We have (at least) one data chunk in flight, 6778c2ecf20Sopenharmony_ci * so we can't fall back to rule 6.1 B). 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_ci return SCTP_XMIT_RWND_FULL; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci /* RFC 2960 6.1 Transmission of DATA Chunks 6828c2ecf20Sopenharmony_ci * 6838c2ecf20Sopenharmony_ci * B) At any given time, the sender MUST NOT transmit new data 6848c2ecf20Sopenharmony_ci * to a given transport address if it has cwnd or more bytes 6858c2ecf20Sopenharmony_ci * of data outstanding to that transport address. 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_ci /* RFC 7.2.4 & the Implementers Guide 2.8. 6888c2ecf20Sopenharmony_ci * 6898c2ecf20Sopenharmony_ci * 3) ... 6908c2ecf20Sopenharmony_ci * When a Fast Retransmit is being performed the sender SHOULD 6918c2ecf20Sopenharmony_ci * ignore the value of cwnd and SHOULD NOT delay retransmission. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci if (chunk->fast_retransmit != SCTP_NEED_FRTX && 6948c2ecf20Sopenharmony_ci flight_size >= transport->cwnd) 6958c2ecf20Sopenharmony_ci return SCTP_XMIT_RWND_FULL; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* Nagle's algorithm to solve small-packet problem: 6988c2ecf20Sopenharmony_ci * Inhibit the sending of new chunks when new outgoing data arrives 6998c2ecf20Sopenharmony_ci * if any previously transmitted data on the connection remains 7008c2ecf20Sopenharmony_ci * unacknowledged. 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && 7048c2ecf20Sopenharmony_ci !asoc->force_delay) 7058c2ecf20Sopenharmony_ci /* Nothing unacked */ 7068c2ecf20Sopenharmony_ci return SCTP_XMIT_OK; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (!sctp_packet_empty(packet)) 7098c2ecf20Sopenharmony_ci /* Append to packet */ 7108c2ecf20Sopenharmony_ci return SCTP_XMIT_OK; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (!sctp_state(asoc, ESTABLISHED)) 7138c2ecf20Sopenharmony_ci return SCTP_XMIT_OK; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* Check whether this chunk and all the rest of pending data will fit 7168c2ecf20Sopenharmony_ci * or delay in hopes of bundling a full sized packet. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ci if (chunk->skb->len + q->out_qlen > transport->pathmtu - 7198c2ecf20Sopenharmony_ci packet->overhead - sctp_datachk_len(&chunk->asoc->stream) - 4) 7208c2ecf20Sopenharmony_ci /* Enough data queued to fill a packet */ 7218c2ecf20Sopenharmony_ci return SCTP_XMIT_OK; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* Don't delay large message writes that may have been fragmented */ 7248c2ecf20Sopenharmony_ci if (!chunk->msg->can_delay) 7258c2ecf20Sopenharmony_ci return SCTP_XMIT_OK; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* Defer until all data acked or packet full */ 7288c2ecf20Sopenharmony_ci return SCTP_XMIT_DELAY; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci/* This private function does management things when adding DATA chunk */ 7328c2ecf20Sopenharmony_cistatic void sctp_packet_append_data(struct sctp_packet *packet, 7338c2ecf20Sopenharmony_ci struct sctp_chunk *chunk) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct sctp_transport *transport = packet->transport; 7368c2ecf20Sopenharmony_ci size_t datasize = sctp_data_size(chunk); 7378c2ecf20Sopenharmony_ci struct sctp_association *asoc = transport->asoc; 7388c2ecf20Sopenharmony_ci u32 rwnd = asoc->peer.rwnd; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* Keep track of how many bytes are in flight over this transport. */ 7418c2ecf20Sopenharmony_ci transport->flight_size += datasize; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* Keep track of how many bytes are in flight to the receiver. */ 7448c2ecf20Sopenharmony_ci asoc->outqueue.outstanding_bytes += datasize; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* Update our view of the receiver's rwnd. */ 7478c2ecf20Sopenharmony_ci if (datasize < rwnd) 7488c2ecf20Sopenharmony_ci rwnd -= datasize; 7498c2ecf20Sopenharmony_ci else 7508c2ecf20Sopenharmony_ci rwnd = 0; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci asoc->peer.rwnd = rwnd; 7538c2ecf20Sopenharmony_ci sctp_chunk_assign_tsn(chunk); 7548c2ecf20Sopenharmony_ci asoc->stream.si->assign_number(chunk); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic enum sctp_xmit sctp_packet_will_fit(struct sctp_packet *packet, 7588c2ecf20Sopenharmony_ci struct sctp_chunk *chunk, 7598c2ecf20Sopenharmony_ci u16 chunk_len) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci enum sctp_xmit retval = SCTP_XMIT_OK; 7628c2ecf20Sopenharmony_ci size_t psize, pmtu, maxsize; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* Don't bundle in this packet if this chunk's auth key doesn't 7658c2ecf20Sopenharmony_ci * match other chunks already enqueued on this packet. Also, 7668c2ecf20Sopenharmony_ci * don't bundle the chunk with auth key if other chunks in this 7678c2ecf20Sopenharmony_ci * packet don't have auth key. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_ci if ((packet->auth && chunk->shkey != packet->auth->shkey) || 7708c2ecf20Sopenharmony_ci (!packet->auth && chunk->shkey && 7718c2ecf20Sopenharmony_ci chunk->chunk_hdr->type != SCTP_CID_AUTH)) 7728c2ecf20Sopenharmony_ci return SCTP_XMIT_PMTU_FULL; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci psize = packet->size; 7758c2ecf20Sopenharmony_ci if (packet->transport->asoc) 7768c2ecf20Sopenharmony_ci pmtu = packet->transport->asoc->pathmtu; 7778c2ecf20Sopenharmony_ci else 7788c2ecf20Sopenharmony_ci pmtu = packet->transport->pathmtu; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* Decide if we need to fragment or resubmit later. */ 7818c2ecf20Sopenharmony_ci if (psize + chunk_len > pmtu) { 7828c2ecf20Sopenharmony_ci /* It's OK to fragment at IP level if any one of the following 7838c2ecf20Sopenharmony_ci * is true: 7848c2ecf20Sopenharmony_ci * 1. The packet is empty (meaning this chunk is greater 7858c2ecf20Sopenharmony_ci * the MTU) 7868c2ecf20Sopenharmony_ci * 2. The packet doesn't have any data in it yet and data 7878c2ecf20Sopenharmony_ci * requires authentication. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_ci if (sctp_packet_empty(packet) || 7908c2ecf20Sopenharmony_ci (!packet->has_data && chunk->auth)) { 7918c2ecf20Sopenharmony_ci /* We no longer do re-fragmentation. 7928c2ecf20Sopenharmony_ci * Just fragment at the IP layer, if we 7938c2ecf20Sopenharmony_ci * actually hit this condition 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_ci packet->ipfragok = 1; 7968c2ecf20Sopenharmony_ci goto out; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* Similarly, if this chunk was built before a PMTU 8008c2ecf20Sopenharmony_ci * reduction, we have to fragment it at IP level now. So 8018c2ecf20Sopenharmony_ci * if the packet already contains something, we need to 8028c2ecf20Sopenharmony_ci * flush. 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_ci maxsize = pmtu - packet->overhead; 8058c2ecf20Sopenharmony_ci if (packet->auth) 8068c2ecf20Sopenharmony_ci maxsize -= SCTP_PAD4(packet->auth->skb->len); 8078c2ecf20Sopenharmony_ci if (chunk_len > maxsize) 8088c2ecf20Sopenharmony_ci retval = SCTP_XMIT_PMTU_FULL; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* It is also okay to fragment if the chunk we are 8118c2ecf20Sopenharmony_ci * adding is a control chunk, but only if current packet 8128c2ecf20Sopenharmony_ci * is not a GSO one otherwise it causes fragmentation of 8138c2ecf20Sopenharmony_ci * a large frame. So in this case we allow the 8148c2ecf20Sopenharmony_ci * fragmentation by forcing it to be in a new packet. 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_ci if (!sctp_chunk_is_data(chunk) && packet->has_data) 8178c2ecf20Sopenharmony_ci retval = SCTP_XMIT_PMTU_FULL; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (psize + chunk_len > packet->max_size) 8208c2ecf20Sopenharmony_ci /* Hit GSO/PMTU limit, gotta flush */ 8218c2ecf20Sopenharmony_ci retval = SCTP_XMIT_PMTU_FULL; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (!packet->transport->burst_limited && 8248c2ecf20Sopenharmony_ci psize + chunk_len > (packet->transport->cwnd >> 1)) 8258c2ecf20Sopenharmony_ci /* Do not allow a single GSO packet to use more 8268c2ecf20Sopenharmony_ci * than half of cwnd. 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci retval = SCTP_XMIT_PMTU_FULL; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (packet->transport->burst_limited && 8318c2ecf20Sopenharmony_ci psize + chunk_len > (packet->transport->burst_limited >> 1)) 8328c2ecf20Sopenharmony_ci /* Do not allow a single GSO packet to use more 8338c2ecf20Sopenharmony_ci * than half of original cwnd. 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_ci retval = SCTP_XMIT_PMTU_FULL; 8368c2ecf20Sopenharmony_ci /* Otherwise it will fit in the GSO packet */ 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ciout: 8408c2ecf20Sopenharmony_ci return retval; 8418c2ecf20Sopenharmony_ci} 842