162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* SCTP kernel implementation 362306a36Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 462306a36Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 562306a36Sopenharmony_ci * Copyright (c) 2001-2003 International Business Machines, Corp. 662306a36Sopenharmony_ci * Copyright (c) 2001 Intel Corp. 762306a36Sopenharmony_ci * Copyright (c) 2001 Nokia, Inc. 862306a36Sopenharmony_ci * Copyright (c) 2001 La Monte H.P. Yarroll 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This file is part of the SCTP kernel implementation 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * These functions handle all input from the IP layer into SCTP. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Please send any bug reports or fixes you make to the 1562306a36Sopenharmony_ci * email address(es): 1662306a36Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Written or modified by: 1962306a36Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 2062306a36Sopenharmony_ci * Karl Knutson <karl@athena.chicago.il.us> 2162306a36Sopenharmony_ci * Xingang Guo <xingang.guo@intel.com> 2262306a36Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 2362306a36Sopenharmony_ci * Hui Huang <hui.huang@nokia.com> 2462306a36Sopenharmony_ci * Daisy Chang <daisyc@us.ibm.com> 2562306a36Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 2662306a36Sopenharmony_ci * Ardelle Fan <ardelle.fan@intel.com> 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/types.h> 3062306a36Sopenharmony_ci#include <linux/list.h> /* For struct list_head */ 3162306a36Sopenharmony_ci#include <linux/socket.h> 3262306a36Sopenharmony_ci#include <linux/ip.h> 3362306a36Sopenharmony_ci#include <linux/time.h> /* For struct timeval */ 3462306a36Sopenharmony_ci#include <linux/slab.h> 3562306a36Sopenharmony_ci#include <net/ip.h> 3662306a36Sopenharmony_ci#include <net/icmp.h> 3762306a36Sopenharmony_ci#include <net/snmp.h> 3862306a36Sopenharmony_ci#include <net/sock.h> 3962306a36Sopenharmony_ci#include <net/xfrm.h> 4062306a36Sopenharmony_ci#include <net/sctp/sctp.h> 4162306a36Sopenharmony_ci#include <net/sctp/sm.h> 4262306a36Sopenharmony_ci#include <net/sctp/checksum.h> 4362306a36Sopenharmony_ci#include <net/net_namespace.h> 4462306a36Sopenharmony_ci#include <linux/rhashtable.h> 4562306a36Sopenharmony_ci#include <net/sock_reuseport.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* Forward declarations for internal helpers. */ 4862306a36Sopenharmony_cistatic int sctp_rcv_ootb(struct sk_buff *); 4962306a36Sopenharmony_cistatic struct sctp_association *__sctp_rcv_lookup(struct net *net, 5062306a36Sopenharmony_ci struct sk_buff *skb, 5162306a36Sopenharmony_ci const union sctp_addr *paddr, 5262306a36Sopenharmony_ci const union sctp_addr *laddr, 5362306a36Sopenharmony_ci struct sctp_transport **transportp, 5462306a36Sopenharmony_ci int dif, int sdif); 5562306a36Sopenharmony_cistatic struct sctp_endpoint *__sctp_rcv_lookup_endpoint( 5662306a36Sopenharmony_ci struct net *net, struct sk_buff *skb, 5762306a36Sopenharmony_ci const union sctp_addr *laddr, 5862306a36Sopenharmony_ci const union sctp_addr *daddr, 5962306a36Sopenharmony_ci int dif, int sdif); 6062306a36Sopenharmony_cistatic struct sctp_association *__sctp_lookup_association( 6162306a36Sopenharmony_ci struct net *net, 6262306a36Sopenharmony_ci const union sctp_addr *local, 6362306a36Sopenharmony_ci const union sctp_addr *peer, 6462306a36Sopenharmony_ci struct sctp_transport **pt, 6562306a36Sopenharmony_ci int dif, int sdif); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int sctp_add_backlog(struct sock *sk, struct sk_buff *skb); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Calculate the SCTP checksum of an SCTP packet. */ 7162306a36Sopenharmony_cistatic inline int sctp_rcv_checksum(struct net *net, struct sk_buff *skb) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct sctphdr *sh = sctp_hdr(skb); 7462306a36Sopenharmony_ci __le32 cmp = sh->checksum; 7562306a36Sopenharmony_ci __le32 val = sctp_compute_cksum(skb, 0); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (val != cmp) { 7862306a36Sopenharmony_ci /* CRC failure, dump it. */ 7962306a36Sopenharmony_ci __SCTP_INC_STATS(net, SCTP_MIB_CHECKSUMERRORS); 8062306a36Sopenharmony_ci return -1; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * This is the routine which IP calls when receiving an SCTP packet. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ciint sctp_rcv(struct sk_buff *skb) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct sock *sk; 9162306a36Sopenharmony_ci struct sctp_association *asoc; 9262306a36Sopenharmony_ci struct sctp_endpoint *ep = NULL; 9362306a36Sopenharmony_ci struct sctp_ep_common *rcvr; 9462306a36Sopenharmony_ci struct sctp_transport *transport = NULL; 9562306a36Sopenharmony_ci struct sctp_chunk *chunk; 9662306a36Sopenharmony_ci union sctp_addr src; 9762306a36Sopenharmony_ci union sctp_addr dest; 9862306a36Sopenharmony_ci int family; 9962306a36Sopenharmony_ci struct sctp_af *af; 10062306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 10162306a36Sopenharmony_ci bool is_gso = skb_is_gso(skb) && skb_is_gso_sctp(skb); 10262306a36Sopenharmony_ci int dif, sdif; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (skb->pkt_type != PACKET_HOST) 10562306a36Sopenharmony_ci goto discard_it; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci __SCTP_INC_STATS(net, SCTP_MIB_INSCTPPACKS); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* If packet is too small to contain a single chunk, let's not 11062306a36Sopenharmony_ci * waste time on it anymore. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci if (skb->len < sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) + 11362306a36Sopenharmony_ci skb_transport_offset(skb)) 11462306a36Sopenharmony_ci goto discard_it; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* If the packet is fragmented and we need to do crc checking, 11762306a36Sopenharmony_ci * it's better to just linearize it otherwise crc computing 11862306a36Sopenharmony_ci * takes longer. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci if ((!is_gso && skb_linearize(skb)) || 12162306a36Sopenharmony_ci !pskb_may_pull(skb, sizeof(struct sctphdr))) 12262306a36Sopenharmony_ci goto discard_it; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Pull up the IP header. */ 12562306a36Sopenharmony_ci __skb_pull(skb, skb_transport_offset(skb)); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci skb->csum_valid = 0; /* Previous value not applicable */ 12862306a36Sopenharmony_ci if (skb_csum_unnecessary(skb)) 12962306a36Sopenharmony_ci __skb_decr_checksum_unnecessary(skb); 13062306a36Sopenharmony_ci else if (!sctp_checksum_disable && 13162306a36Sopenharmony_ci !is_gso && 13262306a36Sopenharmony_ci sctp_rcv_checksum(net, skb) < 0) 13362306a36Sopenharmony_ci goto discard_it; 13462306a36Sopenharmony_ci skb->csum_valid = 1; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci __skb_pull(skb, sizeof(struct sctphdr)); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci family = ipver2af(ip_hdr(skb)->version); 13962306a36Sopenharmony_ci af = sctp_get_af_specific(family); 14062306a36Sopenharmony_ci if (unlikely(!af)) 14162306a36Sopenharmony_ci goto discard_it; 14262306a36Sopenharmony_ci SCTP_INPUT_CB(skb)->af = af; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* Initialize local addresses for lookups. */ 14562306a36Sopenharmony_ci af->from_skb(&src, skb, 1); 14662306a36Sopenharmony_ci af->from_skb(&dest, skb, 0); 14762306a36Sopenharmony_ci dif = af->skb_iif(skb); 14862306a36Sopenharmony_ci sdif = af->skb_sdif(skb); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* If the packet is to or from a non-unicast address, 15162306a36Sopenharmony_ci * silently discard the packet. 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * This is not clearly defined in the RFC except in section 15462306a36Sopenharmony_ci * 8.4 - OOTB handling. However, based on the book "Stream Control 15562306a36Sopenharmony_ci * Transmission Protocol" 2.1, "It is important to note that the 15662306a36Sopenharmony_ci * IP address of an SCTP transport address must be a routable 15762306a36Sopenharmony_ci * unicast address. In other words, IP multicast addresses and 15862306a36Sopenharmony_ci * IP broadcast addresses cannot be used in an SCTP transport 15962306a36Sopenharmony_ci * address." 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci if (!af->addr_valid(&src, NULL, skb) || 16262306a36Sopenharmony_ci !af->addr_valid(&dest, NULL, skb)) 16362306a36Sopenharmony_ci goto discard_it; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci asoc = __sctp_rcv_lookup(net, skb, &src, &dest, &transport, dif, sdif); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (!asoc) 16862306a36Sopenharmony_ci ep = __sctp_rcv_lookup_endpoint(net, skb, &dest, &src, dif, sdif); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Retrieve the common input handling substructure. */ 17162306a36Sopenharmony_ci rcvr = asoc ? &asoc->base : &ep->base; 17262306a36Sopenharmony_ci sk = rcvr->sk; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* 17562306a36Sopenharmony_ci * RFC 2960, 8.4 - Handle "Out of the blue" Packets. 17662306a36Sopenharmony_ci * An SCTP packet is called an "out of the blue" (OOTB) 17762306a36Sopenharmony_ci * packet if it is correctly formed, i.e., passed the 17862306a36Sopenharmony_ci * receiver's checksum check, but the receiver is not 17962306a36Sopenharmony_ci * able to identify the association to which this 18062306a36Sopenharmony_ci * packet belongs. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (!asoc) { 18362306a36Sopenharmony_ci if (sctp_rcv_ootb(skb)) { 18462306a36Sopenharmony_ci __SCTP_INC_STATS(net, SCTP_MIB_OUTOFBLUES); 18562306a36Sopenharmony_ci goto discard_release; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family)) 19062306a36Sopenharmony_ci goto discard_release; 19162306a36Sopenharmony_ci nf_reset_ct(skb); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (sk_filter(sk, skb)) 19462306a36Sopenharmony_ci goto discard_release; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* Create an SCTP packet structure. */ 19762306a36Sopenharmony_ci chunk = sctp_chunkify(skb, asoc, sk, GFP_ATOMIC); 19862306a36Sopenharmony_ci if (!chunk) 19962306a36Sopenharmony_ci goto discard_release; 20062306a36Sopenharmony_ci SCTP_INPUT_CB(skb)->chunk = chunk; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Remember what endpoint is to handle this packet. */ 20362306a36Sopenharmony_ci chunk->rcvr = rcvr; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Remember the SCTP header. */ 20662306a36Sopenharmony_ci chunk->sctp_hdr = sctp_hdr(skb); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Set the source and destination addresses of the incoming chunk. */ 20962306a36Sopenharmony_ci sctp_init_addrs(chunk, &src, &dest); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Remember where we came from. */ 21262306a36Sopenharmony_ci chunk->transport = transport; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* Acquire access to the sock lock. Note: We are safe from other 21562306a36Sopenharmony_ci * bottom halves on this lock, but a user may be in the lock too, 21662306a36Sopenharmony_ci * so check if it is busy. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci bh_lock_sock(sk); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (sk != rcvr->sk) { 22162306a36Sopenharmony_ci /* Our cached sk is different from the rcvr->sk. This is 22262306a36Sopenharmony_ci * because migrate()/accept() may have moved the association 22362306a36Sopenharmony_ci * to a new socket and released all the sockets. So now we 22462306a36Sopenharmony_ci * are holding a lock on the old socket while the user may 22562306a36Sopenharmony_ci * be doing something with the new socket. Switch our veiw 22662306a36Sopenharmony_ci * of the current sk. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci bh_unlock_sock(sk); 22962306a36Sopenharmony_ci sk = rcvr->sk; 23062306a36Sopenharmony_ci bh_lock_sock(sk); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (sock_owned_by_user(sk) || !sctp_newsk_ready(sk)) { 23462306a36Sopenharmony_ci if (sctp_add_backlog(sk, skb)) { 23562306a36Sopenharmony_ci bh_unlock_sock(sk); 23662306a36Sopenharmony_ci sctp_chunk_free(chunk); 23762306a36Sopenharmony_ci skb = NULL; /* sctp_chunk_free already freed the skb */ 23862306a36Sopenharmony_ci goto discard_release; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci __SCTP_INC_STATS(net, SCTP_MIB_IN_PKT_BACKLOG); 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci __SCTP_INC_STATS(net, SCTP_MIB_IN_PKT_SOFTIRQ); 24362306a36Sopenharmony_ci sctp_inq_push(&chunk->rcvr->inqueue, chunk); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci bh_unlock_sock(sk); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Release the asoc/ep ref we took in the lookup calls. */ 24962306a36Sopenharmony_ci if (transport) 25062306a36Sopenharmony_ci sctp_transport_put(transport); 25162306a36Sopenharmony_ci else 25262306a36Sopenharmony_ci sctp_endpoint_put(ep); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cidiscard_it: 25762306a36Sopenharmony_ci __SCTP_INC_STATS(net, SCTP_MIB_IN_PKT_DISCARDS); 25862306a36Sopenharmony_ci kfree_skb(skb); 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cidiscard_release: 26262306a36Sopenharmony_ci /* Release the asoc/ep ref we took in the lookup calls. */ 26362306a36Sopenharmony_ci if (transport) 26462306a36Sopenharmony_ci sctp_transport_put(transport); 26562306a36Sopenharmony_ci else 26662306a36Sopenharmony_ci sctp_endpoint_put(ep); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci goto discard_it; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* Process the backlog queue of the socket. Every skb on 27262306a36Sopenharmony_ci * the backlog holds a ref on an association or endpoint. 27362306a36Sopenharmony_ci * We hold this ref throughout the state machine to make 27462306a36Sopenharmony_ci * sure that the structure we need is still around. 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ciint sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; 27962306a36Sopenharmony_ci struct sctp_inq *inqueue = &chunk->rcvr->inqueue; 28062306a36Sopenharmony_ci struct sctp_transport *t = chunk->transport; 28162306a36Sopenharmony_ci struct sctp_ep_common *rcvr = NULL; 28262306a36Sopenharmony_ci int backloged = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci rcvr = chunk->rcvr; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* If the rcvr is dead then the association or endpoint 28762306a36Sopenharmony_ci * has been deleted and we can safely drop the chunk 28862306a36Sopenharmony_ci * and refs that we are holding. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci if (rcvr->dead) { 29162306a36Sopenharmony_ci sctp_chunk_free(chunk); 29262306a36Sopenharmony_ci goto done; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (unlikely(rcvr->sk != sk)) { 29662306a36Sopenharmony_ci /* In this case, the association moved from one socket to 29762306a36Sopenharmony_ci * another. We are currently sitting on the backlog of the 29862306a36Sopenharmony_ci * old socket, so we need to move. 29962306a36Sopenharmony_ci * However, since we are here in the process context we 30062306a36Sopenharmony_ci * need to take make sure that the user doesn't own 30162306a36Sopenharmony_ci * the new socket when we process the packet. 30262306a36Sopenharmony_ci * If the new socket is user-owned, queue the chunk to the 30362306a36Sopenharmony_ci * backlog of the new socket without dropping any refs. 30462306a36Sopenharmony_ci * Otherwise, we can safely push the chunk on the inqueue. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci sk = rcvr->sk; 30862306a36Sopenharmony_ci local_bh_disable(); 30962306a36Sopenharmony_ci bh_lock_sock(sk); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (sock_owned_by_user(sk) || !sctp_newsk_ready(sk)) { 31262306a36Sopenharmony_ci if (sk_add_backlog(sk, skb, READ_ONCE(sk->sk_rcvbuf))) 31362306a36Sopenharmony_ci sctp_chunk_free(chunk); 31462306a36Sopenharmony_ci else 31562306a36Sopenharmony_ci backloged = 1; 31662306a36Sopenharmony_ci } else 31762306a36Sopenharmony_ci sctp_inq_push(inqueue, chunk); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci bh_unlock_sock(sk); 32062306a36Sopenharmony_ci local_bh_enable(); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* If the chunk was backloged again, don't drop refs */ 32362306a36Sopenharmony_ci if (backloged) 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci } else { 32662306a36Sopenharmony_ci if (!sctp_newsk_ready(sk)) { 32762306a36Sopenharmony_ci if (!sk_add_backlog(sk, skb, READ_ONCE(sk->sk_rcvbuf))) 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci sctp_chunk_free(chunk); 33062306a36Sopenharmony_ci } else { 33162306a36Sopenharmony_ci sctp_inq_push(inqueue, chunk); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cidone: 33662306a36Sopenharmony_ci /* Release the refs we took in sctp_add_backlog */ 33762306a36Sopenharmony_ci if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) 33862306a36Sopenharmony_ci sctp_transport_put(t); 33962306a36Sopenharmony_ci else if (SCTP_EP_TYPE_SOCKET == rcvr->type) 34062306a36Sopenharmony_ci sctp_endpoint_put(sctp_ep(rcvr)); 34162306a36Sopenharmony_ci else 34262306a36Sopenharmony_ci BUG(); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int sctp_add_backlog(struct sock *sk, struct sk_buff *skb) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; 35062306a36Sopenharmony_ci struct sctp_transport *t = chunk->transport; 35162306a36Sopenharmony_ci struct sctp_ep_common *rcvr = chunk->rcvr; 35262306a36Sopenharmony_ci int ret; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ret = sk_add_backlog(sk, skb, READ_ONCE(sk->sk_rcvbuf)); 35562306a36Sopenharmony_ci if (!ret) { 35662306a36Sopenharmony_ci /* Hold the assoc/ep while hanging on the backlog queue. 35762306a36Sopenharmony_ci * This way, we know structures we need will not disappear 35862306a36Sopenharmony_ci * from us 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) 36162306a36Sopenharmony_ci sctp_transport_hold(t); 36262306a36Sopenharmony_ci else if (SCTP_EP_TYPE_SOCKET == rcvr->type) 36362306a36Sopenharmony_ci sctp_endpoint_hold(sctp_ep(rcvr)); 36462306a36Sopenharmony_ci else 36562306a36Sopenharmony_ci BUG(); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/* Handle icmp frag needed error. */ 37262306a36Sopenharmony_civoid sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, 37362306a36Sopenharmony_ci struct sctp_transport *t, __u32 pmtu) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci if (!t || 37662306a36Sopenharmony_ci (t->pathmtu <= pmtu && 37762306a36Sopenharmony_ci t->pl.probe_size + sctp_transport_pl_hlen(t) <= pmtu)) 37862306a36Sopenharmony_ci return; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (sock_owned_by_user(sk)) { 38162306a36Sopenharmony_ci atomic_set(&t->mtu_info, pmtu); 38262306a36Sopenharmony_ci asoc->pmtu_pending = 1; 38362306a36Sopenharmony_ci t->pmtu_pending = 1; 38462306a36Sopenharmony_ci return; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (!(t->param_flags & SPP_PMTUD_ENABLE)) 38862306a36Sopenharmony_ci /* We can't allow retransmitting in such case, as the 38962306a36Sopenharmony_ci * retransmission would be sized just as before, and thus we 39062306a36Sopenharmony_ci * would get another icmp, and retransmit again. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ci return; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* Update transports view of the MTU. Return if no update was needed. 39562306a36Sopenharmony_ci * If an update wasn't needed/possible, it also doesn't make sense to 39662306a36Sopenharmony_ci * try to retransmit now. 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci if (!sctp_transport_update_pmtu(t, pmtu)) 39962306a36Sopenharmony_ci return; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Update association pmtu. */ 40262306a36Sopenharmony_ci sctp_assoc_sync_pmtu(asoc); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* Retransmit with the new pmtu setting. */ 40562306a36Sopenharmony_ci sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_civoid sctp_icmp_redirect(struct sock *sk, struct sctp_transport *t, 40962306a36Sopenharmony_ci struct sk_buff *skb) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct dst_entry *dst; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (sock_owned_by_user(sk) || !t) 41462306a36Sopenharmony_ci return; 41562306a36Sopenharmony_ci dst = sctp_transport_dst_check(t); 41662306a36Sopenharmony_ci if (dst) 41762306a36Sopenharmony_ci dst->ops->redirect(dst, sk, skb); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/* 42162306a36Sopenharmony_ci * SCTP Implementer's Guide, 2.37 ICMP handling procedures 42262306a36Sopenharmony_ci * 42362306a36Sopenharmony_ci * ICMP8) If the ICMP code is a "Unrecognized next header type encountered" 42462306a36Sopenharmony_ci * or a "Protocol Unreachable" treat this message as an abort 42562306a36Sopenharmony_ci * with the T bit set. 42662306a36Sopenharmony_ci * 42762306a36Sopenharmony_ci * This function sends an event to the state machine, which will abort the 42862306a36Sopenharmony_ci * association. 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_civoid sctp_icmp_proto_unreachable(struct sock *sk, 43262306a36Sopenharmony_ci struct sctp_association *asoc, 43362306a36Sopenharmony_ci struct sctp_transport *t) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci if (sock_owned_by_user(sk)) { 43662306a36Sopenharmony_ci if (timer_pending(&t->proto_unreach_timer)) 43762306a36Sopenharmony_ci return; 43862306a36Sopenharmony_ci else { 43962306a36Sopenharmony_ci if (!mod_timer(&t->proto_unreach_timer, 44062306a36Sopenharmony_ci jiffies + (HZ/20))) 44162306a36Sopenharmony_ci sctp_transport_hold(t); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci } else { 44462306a36Sopenharmony_ci struct net *net = sock_net(sk); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci pr_debug("%s: unrecognized next header type " 44762306a36Sopenharmony_ci "encountered!\n", __func__); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (del_timer(&t->proto_unreach_timer)) 45062306a36Sopenharmony_ci sctp_transport_put(t); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci sctp_do_sm(net, SCTP_EVENT_T_OTHER, 45362306a36Sopenharmony_ci SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH), 45462306a36Sopenharmony_ci asoc->state, asoc->ep, asoc, t, 45562306a36Sopenharmony_ci GFP_ATOMIC); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/* Common lookup code for icmp/icmpv6 error handler. */ 46062306a36Sopenharmony_cistruct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb, 46162306a36Sopenharmony_ci struct sctphdr *sctphdr, 46262306a36Sopenharmony_ci struct sctp_association **app, 46362306a36Sopenharmony_ci struct sctp_transport **tpp) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct sctp_init_chunk *chunkhdr, _chunkhdr; 46662306a36Sopenharmony_ci union sctp_addr saddr; 46762306a36Sopenharmony_ci union sctp_addr daddr; 46862306a36Sopenharmony_ci struct sctp_af *af; 46962306a36Sopenharmony_ci struct sock *sk = NULL; 47062306a36Sopenharmony_ci struct sctp_association *asoc; 47162306a36Sopenharmony_ci struct sctp_transport *transport = NULL; 47262306a36Sopenharmony_ci __u32 vtag = ntohl(sctphdr->vtag); 47362306a36Sopenharmony_ci int sdif = inet_sdif(skb); 47462306a36Sopenharmony_ci int dif = inet_iif(skb); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci *app = NULL; *tpp = NULL; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci af = sctp_get_af_specific(family); 47962306a36Sopenharmony_ci if (unlikely(!af)) { 48062306a36Sopenharmony_ci return NULL; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Initialize local addresses for lookups. */ 48462306a36Sopenharmony_ci af->from_skb(&saddr, skb, 1); 48562306a36Sopenharmony_ci af->from_skb(&daddr, skb, 0); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* Look for an association that matches the incoming ICMP error 48862306a36Sopenharmony_ci * packet. 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_ci asoc = __sctp_lookup_association(net, &saddr, &daddr, &transport, dif, sdif); 49162306a36Sopenharmony_ci if (!asoc) 49262306a36Sopenharmony_ci return NULL; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci sk = asoc->base.sk; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* RFC 4960, Appendix C. ICMP Handling 49762306a36Sopenharmony_ci * 49862306a36Sopenharmony_ci * ICMP6) An implementation MUST validate that the Verification Tag 49962306a36Sopenharmony_ci * contained in the ICMP message matches the Verification Tag of 50062306a36Sopenharmony_ci * the peer. If the Verification Tag is not 0 and does NOT 50162306a36Sopenharmony_ci * match, discard the ICMP message. If it is 0 and the ICMP 50262306a36Sopenharmony_ci * message contains enough bytes to verify that the chunk type is 50362306a36Sopenharmony_ci * an INIT chunk and that the Initiate Tag matches the tag of the 50462306a36Sopenharmony_ci * peer, continue with ICMP7. If the ICMP message is too short 50562306a36Sopenharmony_ci * or the chunk type or the Initiate Tag does not match, silently 50662306a36Sopenharmony_ci * discard the packet. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci if (vtag == 0) { 50962306a36Sopenharmony_ci /* chunk header + first 4 octects of init header */ 51062306a36Sopenharmony_ci chunkhdr = skb_header_pointer(skb, skb_transport_offset(skb) + 51162306a36Sopenharmony_ci sizeof(struct sctphdr), 51262306a36Sopenharmony_ci sizeof(struct sctp_chunkhdr) + 51362306a36Sopenharmony_ci sizeof(__be32), &_chunkhdr); 51462306a36Sopenharmony_ci if (!chunkhdr || 51562306a36Sopenharmony_ci chunkhdr->chunk_hdr.type != SCTP_CID_INIT || 51662306a36Sopenharmony_ci ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) 51762306a36Sopenharmony_ci goto out; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci } else if (vtag != asoc->c.peer_vtag) { 52062306a36Sopenharmony_ci goto out; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci bh_lock_sock(sk); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* If too many ICMPs get dropped on busy 52662306a36Sopenharmony_ci * servers this needs to be solved differently. 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_ci if (sock_owned_by_user(sk)) 52962306a36Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci *app = asoc; 53262306a36Sopenharmony_ci *tpp = transport; 53362306a36Sopenharmony_ci return sk; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ciout: 53662306a36Sopenharmony_ci sctp_transport_put(transport); 53762306a36Sopenharmony_ci return NULL; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci/* Common cleanup code for icmp/icmpv6 error handler. */ 54162306a36Sopenharmony_civoid sctp_err_finish(struct sock *sk, struct sctp_transport *t) 54262306a36Sopenharmony_ci __releases(&((__sk)->sk_lock.slock)) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci bh_unlock_sock(sk); 54562306a36Sopenharmony_ci sctp_transport_put(t); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic void sctp_v4_err_handle(struct sctp_transport *t, struct sk_buff *skb, 54962306a36Sopenharmony_ci __u8 type, __u8 code, __u32 info) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct sctp_association *asoc = t->asoc; 55262306a36Sopenharmony_ci struct sock *sk = asoc->base.sk; 55362306a36Sopenharmony_ci int err = 0; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci switch (type) { 55662306a36Sopenharmony_ci case ICMP_PARAMETERPROB: 55762306a36Sopenharmony_ci err = EPROTO; 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci case ICMP_DEST_UNREACH: 56062306a36Sopenharmony_ci if (code > NR_ICMP_UNREACH) 56162306a36Sopenharmony_ci return; 56262306a36Sopenharmony_ci if (code == ICMP_FRAG_NEEDED) { 56362306a36Sopenharmony_ci sctp_icmp_frag_needed(sk, asoc, t, SCTP_TRUNC4(info)); 56462306a36Sopenharmony_ci return; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci if (code == ICMP_PROT_UNREACH) { 56762306a36Sopenharmony_ci sctp_icmp_proto_unreachable(sk, asoc, t); 56862306a36Sopenharmony_ci return; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci err = icmp_err_convert[code].errno; 57162306a36Sopenharmony_ci break; 57262306a36Sopenharmony_ci case ICMP_TIME_EXCEEDED: 57362306a36Sopenharmony_ci if (code == ICMP_EXC_FRAGTIME) 57462306a36Sopenharmony_ci return; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci err = EHOSTUNREACH; 57762306a36Sopenharmony_ci break; 57862306a36Sopenharmony_ci case ICMP_REDIRECT: 57962306a36Sopenharmony_ci sctp_icmp_redirect(sk, t, skb); 58062306a36Sopenharmony_ci return; 58162306a36Sopenharmony_ci default: 58262306a36Sopenharmony_ci return; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci if (!sock_owned_by_user(sk) && inet_test_bit(RECVERR, sk)) { 58562306a36Sopenharmony_ci sk->sk_err = err; 58662306a36Sopenharmony_ci sk_error_report(sk); 58762306a36Sopenharmony_ci } else { /* Only an error on timeout */ 58862306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err_soft, err); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci/* 59362306a36Sopenharmony_ci * This routine is called by the ICMP module when it gets some 59462306a36Sopenharmony_ci * sort of error condition. If err < 0 then the socket should 59562306a36Sopenharmony_ci * be closed and the error returned to the user. If err > 0 59662306a36Sopenharmony_ci * it's just the icmp type << 8 | icmp code. After adjustment 59762306a36Sopenharmony_ci * header points to the first 8 bytes of the sctp header. We need 59862306a36Sopenharmony_ci * to find the appropriate port. 59962306a36Sopenharmony_ci * 60062306a36Sopenharmony_ci * The locking strategy used here is very "optimistic". When 60162306a36Sopenharmony_ci * someone else accesses the socket the ICMP is just dropped 60262306a36Sopenharmony_ci * and for some paths there is no check at all. 60362306a36Sopenharmony_ci * A more general error queue to queue errors for later handling 60462306a36Sopenharmony_ci * is probably better. 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_ciint sctp_v4_err(struct sk_buff *skb, __u32 info) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci const struct iphdr *iph = (const struct iphdr *)skb->data; 61062306a36Sopenharmony_ci const int type = icmp_hdr(skb)->type; 61162306a36Sopenharmony_ci const int code = icmp_hdr(skb)->code; 61262306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 61362306a36Sopenharmony_ci struct sctp_transport *transport; 61462306a36Sopenharmony_ci struct sctp_association *asoc; 61562306a36Sopenharmony_ci __u16 saveip, savesctp; 61662306a36Sopenharmony_ci struct sock *sk; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* Fix up skb to look at the embedded net header. */ 61962306a36Sopenharmony_ci saveip = skb->network_header; 62062306a36Sopenharmony_ci savesctp = skb->transport_header; 62162306a36Sopenharmony_ci skb_reset_network_header(skb); 62262306a36Sopenharmony_ci skb_set_transport_header(skb, iph->ihl * 4); 62362306a36Sopenharmony_ci sk = sctp_err_lookup(net, AF_INET, skb, sctp_hdr(skb), &asoc, &transport); 62462306a36Sopenharmony_ci /* Put back, the original values. */ 62562306a36Sopenharmony_ci skb->network_header = saveip; 62662306a36Sopenharmony_ci skb->transport_header = savesctp; 62762306a36Sopenharmony_ci if (!sk) { 62862306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); 62962306a36Sopenharmony_ci return -ENOENT; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci sctp_v4_err_handle(transport, skb, type, code, info); 63362306a36Sopenharmony_ci sctp_err_finish(sk, transport); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return 0; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ciint sctp_udp_v4_err(struct sock *sk, struct sk_buff *skb) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 64162306a36Sopenharmony_ci struct sctp_association *asoc; 64262306a36Sopenharmony_ci struct sctp_transport *t; 64362306a36Sopenharmony_ci struct icmphdr *hdr; 64462306a36Sopenharmony_ci __u32 info = 0; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci skb->transport_header += sizeof(struct udphdr); 64762306a36Sopenharmony_ci sk = sctp_err_lookup(net, AF_INET, skb, sctp_hdr(skb), &asoc, &t); 64862306a36Sopenharmony_ci if (!sk) { 64962306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); 65062306a36Sopenharmony_ci return -ENOENT; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci skb->transport_header -= sizeof(struct udphdr); 65462306a36Sopenharmony_ci hdr = (struct icmphdr *)(skb_network_header(skb) - sizeof(struct icmphdr)); 65562306a36Sopenharmony_ci if (hdr->type == ICMP_REDIRECT) { 65662306a36Sopenharmony_ci /* can't be handled without outer iphdr known, leave it to udp_err */ 65762306a36Sopenharmony_ci sctp_err_finish(sk, t); 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci if (hdr->type == ICMP_DEST_UNREACH && hdr->code == ICMP_FRAG_NEEDED) 66162306a36Sopenharmony_ci info = ntohs(hdr->un.frag.mtu); 66262306a36Sopenharmony_ci sctp_v4_err_handle(t, skb, hdr->type, hdr->code, info); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci sctp_err_finish(sk, t); 66562306a36Sopenharmony_ci return 1; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci/* 66962306a36Sopenharmony_ci * RFC 2960, 8.4 - Handle "Out of the blue" Packets. 67062306a36Sopenharmony_ci * 67162306a36Sopenharmony_ci * This function scans all the chunks in the OOTB packet to determine if 67262306a36Sopenharmony_ci * the packet should be discarded right away. If a response might be needed 67362306a36Sopenharmony_ci * for this packet, or, if further processing is possible, the packet will 67462306a36Sopenharmony_ci * be queued to a proper inqueue for the next phase of handling. 67562306a36Sopenharmony_ci * 67662306a36Sopenharmony_ci * Output: 67762306a36Sopenharmony_ci * Return 0 - If further processing is needed. 67862306a36Sopenharmony_ci * Return 1 - If the packet can be discarded right away. 67962306a36Sopenharmony_ci */ 68062306a36Sopenharmony_cistatic int sctp_rcv_ootb(struct sk_buff *skb) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct sctp_chunkhdr *ch, _ch; 68362306a36Sopenharmony_ci int ch_end, offset = 0; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* Scan through all the chunks in the packet. */ 68662306a36Sopenharmony_ci do { 68762306a36Sopenharmony_ci /* Make sure we have at least the header there */ 68862306a36Sopenharmony_ci if (offset + sizeof(_ch) > skb->len) 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci ch = skb_header_pointer(skb, offset, sizeof(*ch), &_ch); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* Break out if chunk length is less then minimal. */ 69462306a36Sopenharmony_ci if (!ch || ntohs(ch->length) < sizeof(_ch)) 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci ch_end = offset + SCTP_PAD4(ntohs(ch->length)); 69862306a36Sopenharmony_ci if (ch_end > skb->len) 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the 70262306a36Sopenharmony_ci * receiver MUST silently discard the OOTB packet and take no 70362306a36Sopenharmony_ci * further action. 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci if (SCTP_CID_ABORT == ch->type) 70662306a36Sopenharmony_ci goto discard; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* RFC 8.4, 6) If the packet contains a SHUTDOWN COMPLETE 70962306a36Sopenharmony_ci * chunk, the receiver should silently discard the packet 71062306a36Sopenharmony_ci * and take no further action. 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_ci if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type) 71362306a36Sopenharmony_ci goto discard; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* RFC 4460, 2.11.2 71662306a36Sopenharmony_ci * This will discard packets with INIT chunk bundled as 71762306a36Sopenharmony_ci * subsequent chunks in the packet. When INIT is first, 71862306a36Sopenharmony_ci * the normal INIT processing will discard the chunk. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ci if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data) 72162306a36Sopenharmony_ci goto discard; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci offset = ch_end; 72462306a36Sopenharmony_ci } while (ch_end < skb->len); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cidiscard: 72962306a36Sopenharmony_ci return 1; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci/* Insert endpoint into the hash table. */ 73362306a36Sopenharmony_cistatic int __sctp_hash_endpoint(struct sctp_endpoint *ep) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct sock *sk = ep->base.sk; 73662306a36Sopenharmony_ci struct net *net = sock_net(sk); 73762306a36Sopenharmony_ci struct sctp_hashbucket *head; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci ep->hashent = sctp_ep_hashfn(net, ep->base.bind_addr.port); 74062306a36Sopenharmony_ci head = &sctp_ep_hashtable[ep->hashent]; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (sk->sk_reuseport) { 74362306a36Sopenharmony_ci bool any = sctp_is_ep_boundall(sk); 74462306a36Sopenharmony_ci struct sctp_endpoint *ep2; 74562306a36Sopenharmony_ci struct list_head *list; 74662306a36Sopenharmony_ci int cnt = 0, err = 1; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci list_for_each(list, &ep->base.bind_addr.address_list) 74962306a36Sopenharmony_ci cnt++; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci sctp_for_each_hentry(ep2, &head->chain) { 75262306a36Sopenharmony_ci struct sock *sk2 = ep2->base.sk; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (!net_eq(sock_net(sk2), net) || sk2 == sk || 75562306a36Sopenharmony_ci !uid_eq(sock_i_uid(sk2), sock_i_uid(sk)) || 75662306a36Sopenharmony_ci !sk2->sk_reuseport) 75762306a36Sopenharmony_ci continue; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci err = sctp_bind_addrs_check(sctp_sk(sk2), 76062306a36Sopenharmony_ci sctp_sk(sk), cnt); 76162306a36Sopenharmony_ci if (!err) { 76262306a36Sopenharmony_ci err = reuseport_add_sock(sk, sk2, any); 76362306a36Sopenharmony_ci if (err) 76462306a36Sopenharmony_ci return err; 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci } else if (err < 0) { 76762306a36Sopenharmony_ci return err; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (err) { 77262306a36Sopenharmony_ci err = reuseport_alloc(sk, any); 77362306a36Sopenharmony_ci if (err) 77462306a36Sopenharmony_ci return err; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci write_lock(&head->lock); 77962306a36Sopenharmony_ci hlist_add_head(&ep->node, &head->chain); 78062306a36Sopenharmony_ci write_unlock(&head->lock); 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci/* Add an endpoint to the hash. Local BH-safe. */ 78562306a36Sopenharmony_ciint sctp_hash_endpoint(struct sctp_endpoint *ep) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci int err; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci local_bh_disable(); 79062306a36Sopenharmony_ci err = __sctp_hash_endpoint(ep); 79162306a36Sopenharmony_ci local_bh_enable(); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci return err; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci/* Remove endpoint from the hash table. */ 79762306a36Sopenharmony_cistatic void __sctp_unhash_endpoint(struct sctp_endpoint *ep) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci struct sock *sk = ep->base.sk; 80062306a36Sopenharmony_ci struct sctp_hashbucket *head; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci ep->hashent = sctp_ep_hashfn(sock_net(sk), ep->base.bind_addr.port); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci head = &sctp_ep_hashtable[ep->hashent]; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (rcu_access_pointer(sk->sk_reuseport_cb)) 80762306a36Sopenharmony_ci reuseport_detach_sock(sk); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci write_lock(&head->lock); 81062306a36Sopenharmony_ci hlist_del_init(&ep->node); 81162306a36Sopenharmony_ci write_unlock(&head->lock); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci/* Remove endpoint from the hash. Local BH-safe. */ 81562306a36Sopenharmony_civoid sctp_unhash_endpoint(struct sctp_endpoint *ep) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci local_bh_disable(); 81862306a36Sopenharmony_ci __sctp_unhash_endpoint(ep); 81962306a36Sopenharmony_ci local_bh_enable(); 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic inline __u32 sctp_hashfn(const struct net *net, __be16 lport, 82362306a36Sopenharmony_ci const union sctp_addr *paddr, __u32 seed) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci __u32 addr; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (paddr->sa.sa_family == AF_INET6) 82862306a36Sopenharmony_ci addr = jhash(&paddr->v6.sin6_addr, 16, seed); 82962306a36Sopenharmony_ci else 83062306a36Sopenharmony_ci addr = (__force __u32)paddr->v4.sin_addr.s_addr; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci return jhash_3words(addr, ((__force __u32)paddr->v4.sin_port) << 16 | 83362306a36Sopenharmony_ci (__force __u32)lport, net_hash_mix(net), seed); 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci/* Look up an endpoint. */ 83762306a36Sopenharmony_cistatic struct sctp_endpoint *__sctp_rcv_lookup_endpoint( 83862306a36Sopenharmony_ci struct net *net, struct sk_buff *skb, 83962306a36Sopenharmony_ci const union sctp_addr *laddr, 84062306a36Sopenharmony_ci const union sctp_addr *paddr, 84162306a36Sopenharmony_ci int dif, int sdif) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci struct sctp_hashbucket *head; 84462306a36Sopenharmony_ci struct sctp_endpoint *ep; 84562306a36Sopenharmony_ci struct sock *sk; 84662306a36Sopenharmony_ci __be16 lport; 84762306a36Sopenharmony_ci int hash; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci lport = laddr->v4.sin_port; 85062306a36Sopenharmony_ci hash = sctp_ep_hashfn(net, ntohs(lport)); 85162306a36Sopenharmony_ci head = &sctp_ep_hashtable[hash]; 85262306a36Sopenharmony_ci read_lock(&head->lock); 85362306a36Sopenharmony_ci sctp_for_each_hentry(ep, &head->chain) { 85462306a36Sopenharmony_ci if (sctp_endpoint_is_match(ep, net, laddr, dif, sdif)) 85562306a36Sopenharmony_ci goto hit; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci ep = sctp_sk(net->sctp.ctl_sock)->ep; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cihit: 86162306a36Sopenharmony_ci sk = ep->base.sk; 86262306a36Sopenharmony_ci if (sk->sk_reuseport) { 86362306a36Sopenharmony_ci __u32 phash = sctp_hashfn(net, lport, paddr, 0); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci sk = reuseport_select_sock(sk, phash, skb, 86662306a36Sopenharmony_ci sizeof(struct sctphdr)); 86762306a36Sopenharmony_ci if (sk) 86862306a36Sopenharmony_ci ep = sctp_sk(sk)->ep; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci sctp_endpoint_hold(ep); 87162306a36Sopenharmony_ci read_unlock(&head->lock); 87262306a36Sopenharmony_ci return ep; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci/* rhashtable for transport */ 87662306a36Sopenharmony_cistruct sctp_hash_cmp_arg { 87762306a36Sopenharmony_ci const union sctp_addr *paddr; 87862306a36Sopenharmony_ci const struct net *net; 87962306a36Sopenharmony_ci __be16 lport; 88062306a36Sopenharmony_ci}; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg, 88362306a36Sopenharmony_ci const void *ptr) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct sctp_transport *t = (struct sctp_transport *)ptr; 88662306a36Sopenharmony_ci const struct sctp_hash_cmp_arg *x = arg->key; 88762306a36Sopenharmony_ci int err = 1; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (!sctp_cmp_addr_exact(&t->ipaddr, x->paddr)) 89062306a36Sopenharmony_ci return err; 89162306a36Sopenharmony_ci if (!sctp_transport_hold(t)) 89262306a36Sopenharmony_ci return err; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci if (!net_eq(t->asoc->base.net, x->net)) 89562306a36Sopenharmony_ci goto out; 89662306a36Sopenharmony_ci if (x->lport != htons(t->asoc->base.bind_addr.port)) 89762306a36Sopenharmony_ci goto out; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci err = 0; 90062306a36Sopenharmony_ciout: 90162306a36Sopenharmony_ci sctp_transport_put(t); 90262306a36Sopenharmony_ci return err; 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic inline __u32 sctp_hash_obj(const void *data, u32 len, u32 seed) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci const struct sctp_transport *t = data; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci return sctp_hashfn(t->asoc->base.net, 91062306a36Sopenharmony_ci htons(t->asoc->base.bind_addr.port), 91162306a36Sopenharmony_ci &t->ipaddr, seed); 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic inline __u32 sctp_hash_key(const void *data, u32 len, u32 seed) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci const struct sctp_hash_cmp_arg *x = data; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci return sctp_hashfn(x->net, x->lport, x->paddr, seed); 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistatic const struct rhashtable_params sctp_hash_params = { 92262306a36Sopenharmony_ci .head_offset = offsetof(struct sctp_transport, node), 92362306a36Sopenharmony_ci .hashfn = sctp_hash_key, 92462306a36Sopenharmony_ci .obj_hashfn = sctp_hash_obj, 92562306a36Sopenharmony_ci .obj_cmpfn = sctp_hash_cmp, 92662306a36Sopenharmony_ci .automatic_shrinking = true, 92762306a36Sopenharmony_ci}; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ciint sctp_transport_hashtable_init(void) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci return rhltable_init(&sctp_transport_hashtable, &sctp_hash_params); 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_civoid sctp_transport_hashtable_destroy(void) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci rhltable_destroy(&sctp_transport_hashtable); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ciint sctp_hash_transport(struct sctp_transport *t) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct sctp_transport *transport; 94262306a36Sopenharmony_ci struct rhlist_head *tmp, *list; 94362306a36Sopenharmony_ci struct sctp_hash_cmp_arg arg; 94462306a36Sopenharmony_ci int err; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (t->asoc->temp) 94762306a36Sopenharmony_ci return 0; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci arg.net = t->asoc->base.net; 95062306a36Sopenharmony_ci arg.paddr = &t->ipaddr; 95162306a36Sopenharmony_ci arg.lport = htons(t->asoc->base.bind_addr.port); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci rcu_read_lock(); 95462306a36Sopenharmony_ci list = rhltable_lookup(&sctp_transport_hashtable, &arg, 95562306a36Sopenharmony_ci sctp_hash_params); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci rhl_for_each_entry_rcu(transport, tmp, list, node) 95862306a36Sopenharmony_ci if (transport->asoc->ep == t->asoc->ep) { 95962306a36Sopenharmony_ci rcu_read_unlock(); 96062306a36Sopenharmony_ci return -EEXIST; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci rcu_read_unlock(); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci err = rhltable_insert_key(&sctp_transport_hashtable, &arg, 96562306a36Sopenharmony_ci &t->node, sctp_hash_params); 96662306a36Sopenharmony_ci if (err) 96762306a36Sopenharmony_ci pr_err_once("insert transport fail, errno %d\n", err); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci return err; 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_civoid sctp_unhash_transport(struct sctp_transport *t) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci if (t->asoc->temp) 97562306a36Sopenharmony_ci return; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci rhltable_remove(&sctp_transport_hashtable, &t->node, 97862306a36Sopenharmony_ci sctp_hash_params); 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cibool sctp_sk_bound_dev_eq(struct net *net, int bound_dev_if, int dif, int sdif) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci bool l3mdev_accept = true; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) 98662306a36Sopenharmony_ci l3mdev_accept = !!READ_ONCE(net->sctp.l3mdev_accept); 98762306a36Sopenharmony_ci#endif 98862306a36Sopenharmony_ci return inet_bound_dev_eq(l3mdev_accept, bound_dev_if, dif, sdif); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci/* return a transport with holding it */ 99262306a36Sopenharmony_cistruct sctp_transport *sctp_addrs_lookup_transport( 99362306a36Sopenharmony_ci struct net *net, 99462306a36Sopenharmony_ci const union sctp_addr *laddr, 99562306a36Sopenharmony_ci const union sctp_addr *paddr, 99662306a36Sopenharmony_ci int dif, int sdif) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci struct rhlist_head *tmp, *list; 99962306a36Sopenharmony_ci struct sctp_transport *t; 100062306a36Sopenharmony_ci int bound_dev_if; 100162306a36Sopenharmony_ci struct sctp_hash_cmp_arg arg = { 100262306a36Sopenharmony_ci .paddr = paddr, 100362306a36Sopenharmony_ci .net = net, 100462306a36Sopenharmony_ci .lport = laddr->v4.sin_port, 100562306a36Sopenharmony_ci }; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci list = rhltable_lookup(&sctp_transport_hashtable, &arg, 100862306a36Sopenharmony_ci sctp_hash_params); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci rhl_for_each_entry_rcu(t, tmp, list, node) { 101162306a36Sopenharmony_ci if (!sctp_transport_hold(t)) 101262306a36Sopenharmony_ci continue; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci bound_dev_if = READ_ONCE(t->asoc->base.sk->sk_bound_dev_if); 101562306a36Sopenharmony_ci if (sctp_sk_bound_dev_eq(net, bound_dev_if, dif, sdif) && 101662306a36Sopenharmony_ci sctp_bind_addr_match(&t->asoc->base.bind_addr, 101762306a36Sopenharmony_ci laddr, sctp_sk(t->asoc->base.sk))) 101862306a36Sopenharmony_ci return t; 101962306a36Sopenharmony_ci sctp_transport_put(t); 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci return NULL; 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci/* return a transport without holding it, as it's only used under sock lock */ 102662306a36Sopenharmony_cistruct sctp_transport *sctp_epaddr_lookup_transport( 102762306a36Sopenharmony_ci const struct sctp_endpoint *ep, 102862306a36Sopenharmony_ci const union sctp_addr *paddr) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct rhlist_head *tmp, *list; 103162306a36Sopenharmony_ci struct sctp_transport *t; 103262306a36Sopenharmony_ci struct sctp_hash_cmp_arg arg = { 103362306a36Sopenharmony_ci .paddr = paddr, 103462306a36Sopenharmony_ci .net = ep->base.net, 103562306a36Sopenharmony_ci .lport = htons(ep->base.bind_addr.port), 103662306a36Sopenharmony_ci }; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci list = rhltable_lookup(&sctp_transport_hashtable, &arg, 103962306a36Sopenharmony_ci sctp_hash_params); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci rhl_for_each_entry_rcu(t, tmp, list, node) 104262306a36Sopenharmony_ci if (ep == t->asoc->ep) 104362306a36Sopenharmony_ci return t; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci return NULL; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci/* Look up an association. */ 104962306a36Sopenharmony_cistatic struct sctp_association *__sctp_lookup_association( 105062306a36Sopenharmony_ci struct net *net, 105162306a36Sopenharmony_ci const union sctp_addr *local, 105262306a36Sopenharmony_ci const union sctp_addr *peer, 105362306a36Sopenharmony_ci struct sctp_transport **pt, 105462306a36Sopenharmony_ci int dif, int sdif) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci struct sctp_transport *t; 105762306a36Sopenharmony_ci struct sctp_association *asoc = NULL; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci t = sctp_addrs_lookup_transport(net, local, peer, dif, sdif); 106062306a36Sopenharmony_ci if (!t) 106162306a36Sopenharmony_ci goto out; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci asoc = t->asoc; 106462306a36Sopenharmony_ci *pt = t; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ciout: 106762306a36Sopenharmony_ci return asoc; 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci/* Look up an association. protected by RCU read lock */ 107162306a36Sopenharmony_cistatic 107262306a36Sopenharmony_cistruct sctp_association *sctp_lookup_association(struct net *net, 107362306a36Sopenharmony_ci const union sctp_addr *laddr, 107462306a36Sopenharmony_ci const union sctp_addr *paddr, 107562306a36Sopenharmony_ci struct sctp_transport **transportp, 107662306a36Sopenharmony_ci int dif, int sdif) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci struct sctp_association *asoc; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci rcu_read_lock(); 108162306a36Sopenharmony_ci asoc = __sctp_lookup_association(net, laddr, paddr, transportp, dif, sdif); 108262306a36Sopenharmony_ci rcu_read_unlock(); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci return asoc; 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci/* Is there an association matching the given local and peer addresses? */ 108862306a36Sopenharmony_cibool sctp_has_association(struct net *net, 108962306a36Sopenharmony_ci const union sctp_addr *laddr, 109062306a36Sopenharmony_ci const union sctp_addr *paddr, 109162306a36Sopenharmony_ci int dif, int sdif) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci struct sctp_transport *transport; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (sctp_lookup_association(net, laddr, paddr, &transport, dif, sdif)) { 109662306a36Sopenharmony_ci sctp_transport_put(transport); 109762306a36Sopenharmony_ci return true; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci return false; 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci/* 110462306a36Sopenharmony_ci * SCTP Implementors Guide, 2.18 Handling of address 110562306a36Sopenharmony_ci * parameters within the INIT or INIT-ACK. 110662306a36Sopenharmony_ci * 110762306a36Sopenharmony_ci * D) When searching for a matching TCB upon reception of an INIT 110862306a36Sopenharmony_ci * or INIT-ACK chunk the receiver SHOULD use not only the 110962306a36Sopenharmony_ci * source address of the packet (containing the INIT or 111062306a36Sopenharmony_ci * INIT-ACK) but the receiver SHOULD also use all valid 111162306a36Sopenharmony_ci * address parameters contained within the chunk. 111262306a36Sopenharmony_ci * 111362306a36Sopenharmony_ci * 2.18.3 Solution description 111462306a36Sopenharmony_ci * 111562306a36Sopenharmony_ci * This new text clearly specifies to an implementor the need 111662306a36Sopenharmony_ci * to look within the INIT or INIT-ACK. Any implementation that 111762306a36Sopenharmony_ci * does not do this, may not be able to establish associations 111862306a36Sopenharmony_ci * in certain circumstances. 111962306a36Sopenharmony_ci * 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_cistatic struct sctp_association *__sctp_rcv_init_lookup(struct net *net, 112262306a36Sopenharmony_ci struct sk_buff *skb, 112362306a36Sopenharmony_ci const union sctp_addr *laddr, struct sctp_transport **transportp, 112462306a36Sopenharmony_ci int dif, int sdif) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct sctp_association *asoc; 112762306a36Sopenharmony_ci union sctp_addr addr; 112862306a36Sopenharmony_ci union sctp_addr *paddr = &addr; 112962306a36Sopenharmony_ci struct sctphdr *sh = sctp_hdr(skb); 113062306a36Sopenharmony_ci union sctp_params params; 113162306a36Sopenharmony_ci struct sctp_init_chunk *init; 113262306a36Sopenharmony_ci struct sctp_af *af; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci /* 113562306a36Sopenharmony_ci * This code will NOT touch anything inside the chunk--it is 113662306a36Sopenharmony_ci * strictly READ-ONLY. 113762306a36Sopenharmony_ci * 113862306a36Sopenharmony_ci * RFC 2960 3 SCTP packet Format 113962306a36Sopenharmony_ci * 114062306a36Sopenharmony_ci * Multiple chunks can be bundled into one SCTP packet up to 114162306a36Sopenharmony_ci * the MTU size, except for the INIT, INIT ACK, and SHUTDOWN 114262306a36Sopenharmony_ci * COMPLETE chunks. These chunks MUST NOT be bundled with any 114362306a36Sopenharmony_ci * other chunk in a packet. See Section 6.10 for more details 114462306a36Sopenharmony_ci * on chunk bundling. 114562306a36Sopenharmony_ci */ 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci /* Find the start of the TLVs and the end of the chunk. This is 114862306a36Sopenharmony_ci * the region we search for address parameters. 114962306a36Sopenharmony_ci */ 115062306a36Sopenharmony_ci init = (struct sctp_init_chunk *)skb->data; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci /* Walk the parameters looking for embedded addresses. */ 115362306a36Sopenharmony_ci sctp_walk_params(params, init) { 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* Note: Ignoring hostname addresses. */ 115662306a36Sopenharmony_ci af = sctp_get_af_specific(param_type2af(params.p->type)); 115762306a36Sopenharmony_ci if (!af) 115862306a36Sopenharmony_ci continue; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci if (!af->from_addr_param(paddr, params.addr, sh->source, 0)) 116162306a36Sopenharmony_ci continue; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci asoc = __sctp_lookup_association(net, laddr, paddr, transportp, dif, sdif); 116462306a36Sopenharmony_ci if (asoc) 116562306a36Sopenharmony_ci return asoc; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci return NULL; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci/* ADD-IP, Section 5.2 117262306a36Sopenharmony_ci * When an endpoint receives an ASCONF Chunk from the remote peer 117362306a36Sopenharmony_ci * special procedures may be needed to identify the association the 117462306a36Sopenharmony_ci * ASCONF Chunk is associated with. To properly find the association 117562306a36Sopenharmony_ci * the following procedures SHOULD be followed: 117662306a36Sopenharmony_ci * 117762306a36Sopenharmony_ci * D2) If the association is not found, use the address found in the 117862306a36Sopenharmony_ci * Address Parameter TLV combined with the port number found in the 117962306a36Sopenharmony_ci * SCTP common header. If found proceed to rule D4. 118062306a36Sopenharmony_ci * 118162306a36Sopenharmony_ci * D2-ext) If more than one ASCONF Chunks are packed together, use the 118262306a36Sopenharmony_ci * address found in the ASCONF Address Parameter TLV of each of the 118362306a36Sopenharmony_ci * subsequent ASCONF Chunks. If found, proceed to rule D4. 118462306a36Sopenharmony_ci */ 118562306a36Sopenharmony_cistatic struct sctp_association *__sctp_rcv_asconf_lookup( 118662306a36Sopenharmony_ci struct net *net, 118762306a36Sopenharmony_ci struct sctp_chunkhdr *ch, 118862306a36Sopenharmony_ci const union sctp_addr *laddr, 118962306a36Sopenharmony_ci __be16 peer_port, 119062306a36Sopenharmony_ci struct sctp_transport **transportp, 119162306a36Sopenharmony_ci int dif, int sdif) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci struct sctp_addip_chunk *asconf = (struct sctp_addip_chunk *)ch; 119462306a36Sopenharmony_ci struct sctp_af *af; 119562306a36Sopenharmony_ci union sctp_addr_param *param; 119662306a36Sopenharmony_ci union sctp_addr paddr; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (ntohs(ch->length) < sizeof(*asconf) + sizeof(struct sctp_paramhdr)) 119962306a36Sopenharmony_ci return NULL; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci /* Skip over the ADDIP header and find the Address parameter */ 120262306a36Sopenharmony_ci param = (union sctp_addr_param *)(asconf + 1); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci af = sctp_get_af_specific(param_type2af(param->p.type)); 120562306a36Sopenharmony_ci if (unlikely(!af)) 120662306a36Sopenharmony_ci return NULL; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (!af->from_addr_param(&paddr, param, peer_port, 0)) 120962306a36Sopenharmony_ci return NULL; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci return __sctp_lookup_association(net, laddr, &paddr, transportp, dif, sdif); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci/* SCTP-AUTH, Section 6.3: 121662306a36Sopenharmony_ci* If the receiver does not find a STCB for a packet containing an AUTH 121762306a36Sopenharmony_ci* chunk as the first chunk and not a COOKIE-ECHO chunk as the second 121862306a36Sopenharmony_ci* chunk, it MUST use the chunks after the AUTH chunk to look up an existing 121962306a36Sopenharmony_ci* association. 122062306a36Sopenharmony_ci* 122162306a36Sopenharmony_ci* This means that any chunks that can help us identify the association need 122262306a36Sopenharmony_ci* to be looked at to find this association. 122362306a36Sopenharmony_ci*/ 122462306a36Sopenharmony_cistatic struct sctp_association *__sctp_rcv_walk_lookup(struct net *net, 122562306a36Sopenharmony_ci struct sk_buff *skb, 122662306a36Sopenharmony_ci const union sctp_addr *laddr, 122762306a36Sopenharmony_ci struct sctp_transport **transportp, 122862306a36Sopenharmony_ci int dif, int sdif) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci struct sctp_association *asoc = NULL; 123162306a36Sopenharmony_ci struct sctp_chunkhdr *ch; 123262306a36Sopenharmony_ci int have_auth = 0; 123362306a36Sopenharmony_ci unsigned int chunk_num = 1; 123462306a36Sopenharmony_ci __u8 *ch_end; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* Walk through the chunks looking for AUTH or ASCONF chunks 123762306a36Sopenharmony_ci * to help us find the association. 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ci ch = (struct sctp_chunkhdr *)skb->data; 124062306a36Sopenharmony_ci do { 124162306a36Sopenharmony_ci /* Break out if chunk length is less then minimal. */ 124262306a36Sopenharmony_ci if (ntohs(ch->length) < sizeof(*ch)) 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci ch_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length)); 124662306a36Sopenharmony_ci if (ch_end > skb_tail_pointer(skb)) 124762306a36Sopenharmony_ci break; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci switch (ch->type) { 125062306a36Sopenharmony_ci case SCTP_CID_AUTH: 125162306a36Sopenharmony_ci have_auth = chunk_num; 125262306a36Sopenharmony_ci break; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci case SCTP_CID_COOKIE_ECHO: 125562306a36Sopenharmony_ci /* If a packet arrives containing an AUTH chunk as 125662306a36Sopenharmony_ci * a first chunk, a COOKIE-ECHO chunk as the second 125762306a36Sopenharmony_ci * chunk, and possibly more chunks after them, and 125862306a36Sopenharmony_ci * the receiver does not have an STCB for that 125962306a36Sopenharmony_ci * packet, then authentication is based on 126062306a36Sopenharmony_ci * the contents of the COOKIE- ECHO chunk. 126162306a36Sopenharmony_ci */ 126262306a36Sopenharmony_ci if (have_auth == 1 && chunk_num == 2) 126362306a36Sopenharmony_ci return NULL; 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci case SCTP_CID_ASCONF: 126762306a36Sopenharmony_ci if (have_auth || net->sctp.addip_noauth) 126862306a36Sopenharmony_ci asoc = __sctp_rcv_asconf_lookup( 126962306a36Sopenharmony_ci net, ch, laddr, 127062306a36Sopenharmony_ci sctp_hdr(skb)->source, 127162306a36Sopenharmony_ci transportp, dif, sdif); 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci default: 127462306a36Sopenharmony_ci break; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci if (asoc) 127862306a36Sopenharmony_ci break; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci ch = (struct sctp_chunkhdr *)ch_end; 128162306a36Sopenharmony_ci chunk_num++; 128262306a36Sopenharmony_ci } while (ch_end + sizeof(*ch) < skb_tail_pointer(skb)); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci return asoc; 128562306a36Sopenharmony_ci} 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci/* 128862306a36Sopenharmony_ci * There are circumstances when we need to look inside the SCTP packet 128962306a36Sopenharmony_ci * for information to help us find the association. Examples 129062306a36Sopenharmony_ci * include looking inside of INIT/INIT-ACK chunks or after the AUTH 129162306a36Sopenharmony_ci * chunks. 129262306a36Sopenharmony_ci */ 129362306a36Sopenharmony_cistatic struct sctp_association *__sctp_rcv_lookup_harder(struct net *net, 129462306a36Sopenharmony_ci struct sk_buff *skb, 129562306a36Sopenharmony_ci const union sctp_addr *laddr, 129662306a36Sopenharmony_ci struct sctp_transport **transportp, 129762306a36Sopenharmony_ci int dif, int sdif) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci struct sctp_chunkhdr *ch; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* We do not allow GSO frames here as we need to linearize and 130262306a36Sopenharmony_ci * then cannot guarantee frame boundaries. This shouldn't be an 130362306a36Sopenharmony_ci * issue as packets hitting this are mostly INIT or INIT-ACK and 130462306a36Sopenharmony_ci * those cannot be on GSO-style anyway. 130562306a36Sopenharmony_ci */ 130662306a36Sopenharmony_ci if (skb_is_gso(skb) && skb_is_gso_sctp(skb)) 130762306a36Sopenharmony_ci return NULL; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci ch = (struct sctp_chunkhdr *)skb->data; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci /* The code below will attempt to walk the chunk and extract 131262306a36Sopenharmony_ci * parameter information. Before we do that, we need to verify 131362306a36Sopenharmony_ci * that the chunk length doesn't cause overflow. Otherwise, we'll 131462306a36Sopenharmony_ci * walk off the end. 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_ci if (SCTP_PAD4(ntohs(ch->length)) > skb->len) 131762306a36Sopenharmony_ci return NULL; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci /* If this is INIT/INIT-ACK look inside the chunk too. */ 132062306a36Sopenharmony_ci if (ch->type == SCTP_CID_INIT || ch->type == SCTP_CID_INIT_ACK) 132162306a36Sopenharmony_ci return __sctp_rcv_init_lookup(net, skb, laddr, transportp, dif, sdif); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci return __sctp_rcv_walk_lookup(net, skb, laddr, transportp, dif, sdif); 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci/* Lookup an association for an inbound skb. */ 132762306a36Sopenharmony_cistatic struct sctp_association *__sctp_rcv_lookup(struct net *net, 132862306a36Sopenharmony_ci struct sk_buff *skb, 132962306a36Sopenharmony_ci const union sctp_addr *paddr, 133062306a36Sopenharmony_ci const union sctp_addr *laddr, 133162306a36Sopenharmony_ci struct sctp_transport **transportp, 133262306a36Sopenharmony_ci int dif, int sdif) 133362306a36Sopenharmony_ci{ 133462306a36Sopenharmony_ci struct sctp_association *asoc; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci asoc = __sctp_lookup_association(net, laddr, paddr, transportp, dif, sdif); 133762306a36Sopenharmony_ci if (asoc) 133862306a36Sopenharmony_ci goto out; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* Further lookup for INIT/INIT-ACK packets. 134162306a36Sopenharmony_ci * SCTP Implementors Guide, 2.18 Handling of address 134262306a36Sopenharmony_ci * parameters within the INIT or INIT-ACK. 134362306a36Sopenharmony_ci */ 134462306a36Sopenharmony_ci asoc = __sctp_rcv_lookup_harder(net, skb, laddr, transportp, dif, sdif); 134562306a36Sopenharmony_ci if (asoc) 134662306a36Sopenharmony_ci goto out; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (paddr->sa.sa_family == AF_INET) 134962306a36Sopenharmony_ci pr_debug("sctp: asoc not found for src:%pI4:%d dst:%pI4:%d\n", 135062306a36Sopenharmony_ci &laddr->v4.sin_addr, ntohs(laddr->v4.sin_port), 135162306a36Sopenharmony_ci &paddr->v4.sin_addr, ntohs(paddr->v4.sin_port)); 135262306a36Sopenharmony_ci else 135362306a36Sopenharmony_ci pr_debug("sctp: asoc not found for src:%pI6:%d dst:%pI6:%d\n", 135462306a36Sopenharmony_ci &laddr->v6.sin6_addr, ntohs(laddr->v6.sin6_port), 135562306a36Sopenharmony_ci &paddr->v6.sin6_addr, ntohs(paddr->v6.sin6_port)); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ciout: 135862306a36Sopenharmony_ci return asoc; 135962306a36Sopenharmony_ci} 1360