162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* SCTP kernel implementation 362306a36Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 462306a36Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 562306a36Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 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 * These functions manipulate an sctp event. The struct ulpevent is used 1162306a36Sopenharmony_ci * to carry notifications and data to the ULP (sockets). 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Please send any bug reports or fixes you make to the 1462306a36Sopenharmony_ci * email address(es): 1562306a36Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Written or modified by: 1862306a36Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 1962306a36Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 2062306a36Sopenharmony_ci * Ardelle Fan <ardelle.fan@intel.com> 2162306a36Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/types.h> 2662306a36Sopenharmony_ci#include <linux/skbuff.h> 2762306a36Sopenharmony_ci#include <net/sctp/structs.h> 2862306a36Sopenharmony_ci#include <net/sctp/sctp.h> 2962306a36Sopenharmony_ci#include <net/sctp/sm.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, 3262306a36Sopenharmony_ci struct sctp_association *asoc); 3362306a36Sopenharmony_cistatic void sctp_ulpevent_release_data(struct sctp_ulpevent *event); 3462306a36Sopenharmony_cistatic void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Initialize an ULP event from an given skb. */ 3862306a36Sopenharmony_cistatic void sctp_ulpevent_init(struct sctp_ulpevent *event, 3962306a36Sopenharmony_ci __u16 msg_flags, 4062306a36Sopenharmony_ci unsigned int len) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci memset(event, 0, sizeof(struct sctp_ulpevent)); 4362306a36Sopenharmony_ci event->msg_flags = msg_flags; 4462306a36Sopenharmony_ci event->rmem_len = len; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* Create a new sctp_ulpevent. */ 4862306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpevent_new(int size, __u16 msg_flags, 4962306a36Sopenharmony_ci gfp_t gfp) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct sctp_ulpevent *event; 5262306a36Sopenharmony_ci struct sk_buff *skb; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci skb = alloc_skb(size, gfp); 5562306a36Sopenharmony_ci if (!skb) 5662306a36Sopenharmony_ci goto fail; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci event = sctp_skb2event(skb); 5962306a36Sopenharmony_ci sctp_ulpevent_init(event, msg_flags, skb->truesize); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return event; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cifail: 6462306a36Sopenharmony_ci return NULL; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* Is this a MSG_NOTIFICATION? */ 6862306a36Sopenharmony_ciint sctp_ulpevent_is_notification(const struct sctp_ulpevent *event) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* Hold the association in case the msg_name needs read out of 7462306a36Sopenharmony_ci * the association. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_cistatic inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, 7762306a36Sopenharmony_ci const struct sctp_association *asoc) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct sctp_chunk *chunk = event->chunk; 8062306a36Sopenharmony_ci struct sk_buff *skb; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Cast away the const, as we are just wanting to 8362306a36Sopenharmony_ci * bump the reference count. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci sctp_association_hold((struct sctp_association *)asoc); 8662306a36Sopenharmony_ci skb = sctp_event2skb(event); 8762306a36Sopenharmony_ci event->asoc = (struct sctp_association *)asoc; 8862306a36Sopenharmony_ci atomic_add(event->rmem_len, &event->asoc->rmem_alloc); 8962306a36Sopenharmony_ci sctp_skb_set_owner_r(skb, asoc->base.sk); 9062306a36Sopenharmony_ci if (chunk && chunk->head_skb && !chunk->head_skb->sk) 9162306a36Sopenharmony_ci chunk->head_skb->sk = asoc->base.sk; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* A simple destructor to give up the reference to the association. */ 9562306a36Sopenharmony_cistatic inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct sctp_association *asoc = event->asoc; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci atomic_sub(event->rmem_len, &asoc->rmem_alloc); 10062306a36Sopenharmony_ci sctp_association_put(asoc); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* Create and initialize an SCTP_ASSOC_CHANGE event. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * Communication notifications inform the ULP that an SCTP association 10862306a36Sopenharmony_ci * has either begun or ended. The identifier for a new association is 10962306a36Sopenharmony_ci * provided by this notification. 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * Note: There is no field checking here. If a field is unused it will be 11262306a36Sopenharmony_ci * zero'd out. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_assoc_change( 11562306a36Sopenharmony_ci const struct sctp_association *asoc, 11662306a36Sopenharmony_ci __u16 flags, __u16 state, __u16 error, __u16 outbound, 11762306a36Sopenharmony_ci __u16 inbound, struct sctp_chunk *chunk, gfp_t gfp) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct sctp_ulpevent *event; 12062306a36Sopenharmony_ci struct sctp_assoc_change *sac; 12162306a36Sopenharmony_ci struct sk_buff *skb; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* If the lower layer passed in the chunk, it will be 12462306a36Sopenharmony_ci * an ABORT, so we need to include it in the sac_info. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci if (chunk) { 12762306a36Sopenharmony_ci /* Copy the chunk data to a new skb and reserve enough 12862306a36Sopenharmony_ci * head room to use as notification. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci skb = skb_copy_expand(chunk->skb, 13162306a36Sopenharmony_ci sizeof(struct sctp_assoc_change), 0, gfp); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (!skb) 13462306a36Sopenharmony_ci goto fail; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Embed the event fields inside the cloned skb. */ 13762306a36Sopenharmony_ci event = sctp_skb2event(skb); 13862306a36Sopenharmony_ci sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* Include the notification structure */ 14162306a36Sopenharmony_ci sac = skb_push(skb, sizeof(struct sctp_assoc_change)); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Trim the buffer to the right length. */ 14462306a36Sopenharmony_ci skb_trim(skb, sizeof(struct sctp_assoc_change) + 14562306a36Sopenharmony_ci ntohs(chunk->chunk_hdr->length) - 14662306a36Sopenharmony_ci sizeof(struct sctp_chunkhdr)); 14762306a36Sopenharmony_ci } else { 14862306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), 14962306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 15062306a36Sopenharmony_ci if (!event) 15162306a36Sopenharmony_ci goto fail; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci skb = sctp_event2skb(event); 15462306a36Sopenharmony_ci sac = skb_put(skb, sizeof(struct sctp_assoc_change)); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Socket Extensions for SCTP 15862306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * sac_type: 16162306a36Sopenharmony_ci * It should be SCTP_ASSOC_CHANGE. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci sac->sac_type = SCTP_ASSOC_CHANGE; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Socket Extensions for SCTP 16662306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * sac_state: 32 bits (signed integer) 16962306a36Sopenharmony_ci * This field holds one of a number of values that communicate the 17062306a36Sopenharmony_ci * event that happened to the association. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci sac->sac_state = state; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Socket Extensions for SCTP 17562306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * sac_flags: 16 bits (unsigned integer) 17862306a36Sopenharmony_ci * Currently unused. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_ci sac->sac_flags = 0; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Socket Extensions for SCTP 18362306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * sac_length: sizeof (__u32) 18662306a36Sopenharmony_ci * This field is the total length of the notification data, including 18762306a36Sopenharmony_ci * the notification header. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ci sac->sac_length = skb->len; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Socket Extensions for SCTP 19262306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * sac_error: 32 bits (signed integer) 19562306a36Sopenharmony_ci * 19662306a36Sopenharmony_ci * If the state was reached due to a error condition (e.g. 19762306a36Sopenharmony_ci * COMMUNICATION_LOST) any relevant error information is available in 19862306a36Sopenharmony_ci * this field. This corresponds to the protocol error codes defined in 19962306a36Sopenharmony_ci * [SCTP]. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci sac->sac_error = error; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Socket Extensions for SCTP 20462306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * sac_outbound_streams: 16 bits (unsigned integer) 20762306a36Sopenharmony_ci * sac_inbound_streams: 16 bits (unsigned integer) 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * The maximum number of streams allowed in each direction are 21062306a36Sopenharmony_ci * available in sac_outbound_streams and sac_inbound streams. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci sac->sac_outbound_streams = outbound; 21362306a36Sopenharmony_ci sac->sac_inbound_streams = inbound; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Socket Extensions for SCTP 21662306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 21762306a36Sopenharmony_ci * 21862306a36Sopenharmony_ci * sac_assoc_id: sizeof (sctp_assoc_t) 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * The association id field, holds the identifier for the association. 22162306a36Sopenharmony_ci * All notifications for a given association have the same association 22262306a36Sopenharmony_ci * identifier. For TCP style socket, this field is ignored. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 22562306a36Sopenharmony_ci sac->sac_assoc_id = sctp_assoc2id(asoc); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return event; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cifail: 23062306a36Sopenharmony_ci return NULL; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* Create and initialize an SCTP_PEER_ADDR_CHANGE event. 23462306a36Sopenharmony_ci * 23562306a36Sopenharmony_ci * Socket Extensions for SCTP - draft-01 23662306a36Sopenharmony_ci * 5.3.1.2 SCTP_PEER_ADDR_CHANGE 23762306a36Sopenharmony_ci * 23862306a36Sopenharmony_ci * When a destination address on a multi-homed peer encounters a change 23962306a36Sopenharmony_ci * an interface details event is sent. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_cistatic struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( 24262306a36Sopenharmony_ci const struct sctp_association *asoc, 24362306a36Sopenharmony_ci const struct sockaddr_storage *aaddr, 24462306a36Sopenharmony_ci int flags, int state, int error, gfp_t gfp) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct sctp_ulpevent *event; 24762306a36Sopenharmony_ci struct sctp_paddr_change *spc; 24862306a36Sopenharmony_ci struct sk_buff *skb; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), 25162306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 25262306a36Sopenharmony_ci if (!event) 25362306a36Sopenharmony_ci goto fail; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci skb = sctp_event2skb(event); 25662306a36Sopenharmony_ci spc = skb_put(skb, sizeof(struct sctp_paddr_change)); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Sockets API Extensions for SCTP 25962306a36Sopenharmony_ci * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * spc_type: 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * It should be SCTP_PEER_ADDR_CHANGE. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci spc->spc_type = SCTP_PEER_ADDR_CHANGE; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Sockets API Extensions for SCTP 26862306a36Sopenharmony_ci * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * spc_length: sizeof (__u32) 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * This field is the total length of the notification data, including 27362306a36Sopenharmony_ci * the notification header. 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_ci spc->spc_length = sizeof(struct sctp_paddr_change); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* Sockets API Extensions for SCTP 27862306a36Sopenharmony_ci * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE 27962306a36Sopenharmony_ci * 28062306a36Sopenharmony_ci * spc_flags: 16 bits (unsigned integer) 28162306a36Sopenharmony_ci * Currently unused. 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci spc->spc_flags = 0; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* Sockets API Extensions for SCTP 28662306a36Sopenharmony_ci * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * spc_state: 32 bits (signed integer) 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * This field holds one of a number of values that communicate the 29162306a36Sopenharmony_ci * event that happened to the address. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci spc->spc_state = state; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Sockets API Extensions for SCTP 29662306a36Sopenharmony_ci * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE 29762306a36Sopenharmony_ci * 29862306a36Sopenharmony_ci * spc_error: 32 bits (signed integer) 29962306a36Sopenharmony_ci * 30062306a36Sopenharmony_ci * If the state was reached due to any error condition (e.g. 30162306a36Sopenharmony_ci * ADDRESS_UNREACHABLE) any relevant error information is available in 30262306a36Sopenharmony_ci * this field. 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci spc->spc_error = error; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Socket Extensions for SCTP 30762306a36Sopenharmony_ci * 5.3.1.1 SCTP_ASSOC_CHANGE 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * spc_assoc_id: sizeof (sctp_assoc_t) 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * The association id field, holds the identifier for the association. 31262306a36Sopenharmony_ci * All notifications for a given association have the same association 31362306a36Sopenharmony_ci * identifier. For TCP style socket, this field is ignored. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 31662306a36Sopenharmony_ci spc->spc_assoc_id = sctp_assoc2id(asoc); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Sockets API Extensions for SCTP 31962306a36Sopenharmony_ci * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * spc_aaddr: sizeof (struct sockaddr_storage) 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * The affected address field, holds the remote peer's address that is 32462306a36Sopenharmony_ci * encountering the change of state. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Map ipv4 address into v4-mapped-on-v6 address. */ 32962306a36Sopenharmony_ci sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_to_user( 33062306a36Sopenharmony_ci sctp_sk(asoc->base.sk), 33162306a36Sopenharmony_ci (union sctp_addr *)&spc->spc_aaddr); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return event; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cifail: 33662306a36Sopenharmony_ci return NULL; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_civoid sctp_ulpevent_notify_peer_addr_change(struct sctp_transport *transport, 34062306a36Sopenharmony_ci int state, int error) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct sctp_association *asoc = transport->asoc; 34362306a36Sopenharmony_ci struct sockaddr_storage addr; 34462306a36Sopenharmony_ci struct sctp_ulpevent *event; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (asoc->state < SCTP_STATE_ESTABLISHED) 34762306a36Sopenharmony_ci return; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci memset(&addr, 0, sizeof(struct sockaddr_storage)); 35062306a36Sopenharmony_ci memcpy(&addr, &transport->ipaddr, transport->af_specific->sockaddr_len); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, 0, state, 35362306a36Sopenharmony_ci error, GFP_ATOMIC); 35462306a36Sopenharmony_ci if (event) 35562306a36Sopenharmony_ci asoc->stream.si->enqueue_event(&asoc->ulpq, event); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/* Create and initialize an SCTP_REMOTE_ERROR notification. 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci * Note: This assumes that the chunk->skb->data already points to the 36162306a36Sopenharmony_ci * operation error payload. 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * Socket Extensions for SCTP - draft-01 36462306a36Sopenharmony_ci * 5.3.1.3 SCTP_REMOTE_ERROR 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * A remote peer may send an Operational Error message to its peer. 36762306a36Sopenharmony_ci * This message indicates a variety of error conditions on an 36862306a36Sopenharmony_ci * association. The entire error TLV as it appears on the wire is 36962306a36Sopenharmony_ci * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP 37062306a36Sopenharmony_ci * specification [SCTP] and any extensions for a list of possible 37162306a36Sopenharmony_ci * error formats. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_cistruct sctp_ulpevent * 37462306a36Sopenharmony_cisctp_ulpevent_make_remote_error(const struct sctp_association *asoc, 37562306a36Sopenharmony_ci struct sctp_chunk *chunk, __u16 flags, 37662306a36Sopenharmony_ci gfp_t gfp) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct sctp_remote_error *sre; 37962306a36Sopenharmony_ci struct sctp_ulpevent *event; 38062306a36Sopenharmony_ci struct sctp_errhdr *ch; 38162306a36Sopenharmony_ci struct sk_buff *skb; 38262306a36Sopenharmony_ci __be16 cause; 38362306a36Sopenharmony_ci int elen; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ch = (struct sctp_errhdr *)(chunk->skb->data); 38662306a36Sopenharmony_ci cause = ch->cause; 38762306a36Sopenharmony_ci elen = SCTP_PAD4(ntohs(ch->length)) - sizeof(*ch); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* Pull off the ERROR header. */ 39062306a36Sopenharmony_ci skb_pull(chunk->skb, sizeof(*ch)); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Copy the skb to a new skb with room for us to prepend 39362306a36Sopenharmony_ci * notification with. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci skb = skb_copy_expand(chunk->skb, sizeof(*sre), 0, gfp); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* Pull off the rest of the cause TLV from the chunk. */ 39862306a36Sopenharmony_ci skb_pull(chunk->skb, elen); 39962306a36Sopenharmony_ci if (!skb) 40062306a36Sopenharmony_ci goto fail; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* Embed the event fields inside the cloned skb. */ 40362306a36Sopenharmony_ci event = sctp_skb2event(skb); 40462306a36Sopenharmony_ci sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci sre = skb_push(skb, sizeof(*sre)); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* Trim the buffer to the right length. */ 40962306a36Sopenharmony_ci skb_trim(skb, sizeof(*sre) + elen); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* RFC6458, Section 6.1.3. SCTP_REMOTE_ERROR */ 41262306a36Sopenharmony_ci memset(sre, 0, sizeof(*sre)); 41362306a36Sopenharmony_ci sre->sre_type = SCTP_REMOTE_ERROR; 41462306a36Sopenharmony_ci sre->sre_flags = 0; 41562306a36Sopenharmony_ci sre->sre_length = skb->len; 41662306a36Sopenharmony_ci sre->sre_error = cause; 41762306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 41862306a36Sopenharmony_ci sre->sre_assoc_id = sctp_assoc2id(asoc); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return event; 42162306a36Sopenharmony_cifail: 42262306a36Sopenharmony_ci return NULL; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* Create and initialize a SCTP_SEND_FAILED notification. 42662306a36Sopenharmony_ci * 42762306a36Sopenharmony_ci * Socket Extensions for SCTP - draft-01 42862306a36Sopenharmony_ci * 5.3.1.4 SCTP_SEND_FAILED 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_send_failed( 43162306a36Sopenharmony_ci const struct sctp_association *asoc, struct sctp_chunk *chunk, 43262306a36Sopenharmony_ci __u16 flags, __u32 error, gfp_t gfp) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct sctp_ulpevent *event; 43562306a36Sopenharmony_ci struct sctp_send_failed *ssf; 43662306a36Sopenharmony_ci struct sk_buff *skb; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Pull off any padding. */ 43962306a36Sopenharmony_ci int len = ntohs(chunk->chunk_hdr->length); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* Make skb with more room so we can prepend notification. */ 44262306a36Sopenharmony_ci skb = skb_copy_expand(chunk->skb, 44362306a36Sopenharmony_ci sizeof(struct sctp_send_failed), /* headroom */ 44462306a36Sopenharmony_ci 0, /* tailroom */ 44562306a36Sopenharmony_ci gfp); 44662306a36Sopenharmony_ci if (!skb) 44762306a36Sopenharmony_ci goto fail; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Pull off the common chunk header and DATA header. */ 45062306a36Sopenharmony_ci skb_pull(skb, sctp_datachk_len(&asoc->stream)); 45162306a36Sopenharmony_ci len -= sctp_datachk_len(&asoc->stream); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Embed the event fields inside the cloned skb. */ 45462306a36Sopenharmony_ci event = sctp_skb2event(skb); 45562306a36Sopenharmony_ci sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci ssf = skb_push(skb, sizeof(struct sctp_send_failed)); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Socket Extensions for SCTP 46062306a36Sopenharmony_ci * 5.3.1.4 SCTP_SEND_FAILED 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * ssf_type: 46362306a36Sopenharmony_ci * It should be SCTP_SEND_FAILED. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci ssf->ssf_type = SCTP_SEND_FAILED; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Socket Extensions for SCTP 46862306a36Sopenharmony_ci * 5.3.1.4 SCTP_SEND_FAILED 46962306a36Sopenharmony_ci * 47062306a36Sopenharmony_ci * ssf_flags: 16 bits (unsigned integer) 47162306a36Sopenharmony_ci * The flag value will take one of the following values 47262306a36Sopenharmony_ci * 47362306a36Sopenharmony_ci * SCTP_DATA_UNSENT - Indicates that the data was never put on 47462306a36Sopenharmony_ci * the wire. 47562306a36Sopenharmony_ci * 47662306a36Sopenharmony_ci * SCTP_DATA_SENT - Indicates that the data was put on the wire. 47762306a36Sopenharmony_ci * Note that this does not necessarily mean that the 47862306a36Sopenharmony_ci * data was (or was not) successfully delivered. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci ssf->ssf_flags = flags; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Socket Extensions for SCTP 48362306a36Sopenharmony_ci * 5.3.1.4 SCTP_SEND_FAILED 48462306a36Sopenharmony_ci * 48562306a36Sopenharmony_ci * ssf_length: sizeof (__u32) 48662306a36Sopenharmony_ci * This field is the total length of the notification data, including 48762306a36Sopenharmony_ci * the notification header. 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ci ssf->ssf_length = sizeof(struct sctp_send_failed) + len; 49062306a36Sopenharmony_ci skb_trim(skb, ssf->ssf_length); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Socket Extensions for SCTP 49362306a36Sopenharmony_ci * 5.3.1.4 SCTP_SEND_FAILED 49462306a36Sopenharmony_ci * 49562306a36Sopenharmony_ci * ssf_error: 16 bits (unsigned integer) 49662306a36Sopenharmony_ci * This value represents the reason why the send failed, and if set, 49762306a36Sopenharmony_ci * will be a SCTP protocol error code as defined in [SCTP] section 49862306a36Sopenharmony_ci * 3.3.10. 49962306a36Sopenharmony_ci */ 50062306a36Sopenharmony_ci ssf->ssf_error = error; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Socket Extensions for SCTP 50362306a36Sopenharmony_ci * 5.3.1.4 SCTP_SEND_FAILED 50462306a36Sopenharmony_ci * 50562306a36Sopenharmony_ci * ssf_info: sizeof (struct sctp_sndrcvinfo) 50662306a36Sopenharmony_ci * The original send information associated with the undelivered 50762306a36Sopenharmony_ci * message. 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_ci memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* Per TSVWG discussion with Randy. Allow the application to 51262306a36Sopenharmony_ci * reassemble a fragmented message. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Socket Extensions for SCTP 51762306a36Sopenharmony_ci * 5.3.1.4 SCTP_SEND_FAILED 51862306a36Sopenharmony_ci * 51962306a36Sopenharmony_ci * ssf_assoc_id: sizeof (sctp_assoc_t) 52062306a36Sopenharmony_ci * The association id field, sf_assoc_id, holds the identifier for the 52162306a36Sopenharmony_ci * association. All notifications for a given association have the 52262306a36Sopenharmony_ci * same association identifier. For TCP style socket, this field is 52362306a36Sopenharmony_ci * ignored. 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 52662306a36Sopenharmony_ci ssf->ssf_assoc_id = sctp_assoc2id(asoc); 52762306a36Sopenharmony_ci return event; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cifail: 53062306a36Sopenharmony_ci return NULL; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_send_failed_event( 53462306a36Sopenharmony_ci const struct sctp_association *asoc, struct sctp_chunk *chunk, 53562306a36Sopenharmony_ci __u16 flags, __u32 error, gfp_t gfp) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci struct sctp_send_failed_event *ssf; 53862306a36Sopenharmony_ci struct sctp_ulpevent *event; 53962306a36Sopenharmony_ci struct sk_buff *skb; 54062306a36Sopenharmony_ci int len; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci skb = skb_copy_expand(chunk->skb, sizeof(*ssf), 0, gfp); 54362306a36Sopenharmony_ci if (!skb) 54462306a36Sopenharmony_ci return NULL; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci len = ntohs(chunk->chunk_hdr->length); 54762306a36Sopenharmony_ci len -= sctp_datachk_len(&asoc->stream); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci skb_pull(skb, sctp_datachk_len(&asoc->stream)); 55062306a36Sopenharmony_ci event = sctp_skb2event(skb); 55162306a36Sopenharmony_ci sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci ssf = skb_push(skb, sizeof(*ssf)); 55462306a36Sopenharmony_ci ssf->ssf_type = SCTP_SEND_FAILED_EVENT; 55562306a36Sopenharmony_ci ssf->ssf_flags = flags; 55662306a36Sopenharmony_ci ssf->ssf_length = sizeof(*ssf) + len; 55762306a36Sopenharmony_ci skb_trim(skb, ssf->ssf_length); 55862306a36Sopenharmony_ci ssf->ssf_error = error; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci ssf->ssfe_info.snd_sid = chunk->sinfo.sinfo_stream; 56162306a36Sopenharmony_ci ssf->ssfe_info.snd_ppid = chunk->sinfo.sinfo_ppid; 56262306a36Sopenharmony_ci ssf->ssfe_info.snd_context = chunk->sinfo.sinfo_context; 56362306a36Sopenharmony_ci ssf->ssfe_info.snd_assoc_id = chunk->sinfo.sinfo_assoc_id; 56462306a36Sopenharmony_ci ssf->ssfe_info.snd_flags = chunk->chunk_hdr->flags; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 56762306a36Sopenharmony_ci ssf->ssf_assoc_id = sctp_assoc2id(asoc); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return event; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci/* Create and initialize a SCTP_SHUTDOWN_EVENT notification. 57362306a36Sopenharmony_ci * 57462306a36Sopenharmony_ci * Socket Extensions for SCTP - draft-01 57562306a36Sopenharmony_ci * 5.3.1.5 SCTP_SHUTDOWN_EVENT 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( 57862306a36Sopenharmony_ci const struct sctp_association *asoc, 57962306a36Sopenharmony_ci __u16 flags, gfp_t gfp) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct sctp_ulpevent *event; 58262306a36Sopenharmony_ci struct sctp_shutdown_event *sse; 58362306a36Sopenharmony_ci struct sk_buff *skb; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_shutdown_event), 58662306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 58762306a36Sopenharmony_ci if (!event) 58862306a36Sopenharmony_ci goto fail; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci skb = sctp_event2skb(event); 59162306a36Sopenharmony_ci sse = skb_put(skb, sizeof(struct sctp_shutdown_event)); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* Socket Extensions for SCTP 59462306a36Sopenharmony_ci * 5.3.1.5 SCTP_SHUTDOWN_EVENT 59562306a36Sopenharmony_ci * 59662306a36Sopenharmony_ci * sse_type 59762306a36Sopenharmony_ci * It should be SCTP_SHUTDOWN_EVENT 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci sse->sse_type = SCTP_SHUTDOWN_EVENT; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* Socket Extensions for SCTP 60262306a36Sopenharmony_ci * 5.3.1.5 SCTP_SHUTDOWN_EVENT 60362306a36Sopenharmony_ci * 60462306a36Sopenharmony_ci * sse_flags: 16 bits (unsigned integer) 60562306a36Sopenharmony_ci * Currently unused. 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_ci sse->sse_flags = 0; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Socket Extensions for SCTP 61062306a36Sopenharmony_ci * 5.3.1.5 SCTP_SHUTDOWN_EVENT 61162306a36Sopenharmony_ci * 61262306a36Sopenharmony_ci * sse_length: sizeof (__u32) 61362306a36Sopenharmony_ci * This field is the total length of the notification data, including 61462306a36Sopenharmony_ci * the notification header. 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ci sse->sse_length = sizeof(struct sctp_shutdown_event); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* Socket Extensions for SCTP 61962306a36Sopenharmony_ci * 5.3.1.5 SCTP_SHUTDOWN_EVENT 62062306a36Sopenharmony_ci * 62162306a36Sopenharmony_ci * sse_assoc_id: sizeof (sctp_assoc_t) 62262306a36Sopenharmony_ci * The association id field, holds the identifier for the association. 62362306a36Sopenharmony_ci * All notifications for a given association have the same association 62462306a36Sopenharmony_ci * identifier. For TCP style socket, this field is ignored. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 62762306a36Sopenharmony_ci sse->sse_assoc_id = sctp_assoc2id(asoc); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return event; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cifail: 63262306a36Sopenharmony_ci return NULL; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci/* Create and initialize a SCTP_ADAPTATION_INDICATION notification. 63662306a36Sopenharmony_ci * 63762306a36Sopenharmony_ci * Socket Extensions for SCTP 63862306a36Sopenharmony_ci * 5.3.1.6 SCTP_ADAPTATION_INDICATION 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_adaptation_indication( 64162306a36Sopenharmony_ci const struct sctp_association *asoc, gfp_t gfp) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct sctp_ulpevent *event; 64462306a36Sopenharmony_ci struct sctp_adaptation_event *sai; 64562306a36Sopenharmony_ci struct sk_buff *skb; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_adaptation_event), 64862306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 64962306a36Sopenharmony_ci if (!event) 65062306a36Sopenharmony_ci goto fail; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci skb = sctp_event2skb(event); 65362306a36Sopenharmony_ci sai = skb_put(skb, sizeof(struct sctp_adaptation_event)); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci sai->sai_type = SCTP_ADAPTATION_INDICATION; 65662306a36Sopenharmony_ci sai->sai_flags = 0; 65762306a36Sopenharmony_ci sai->sai_length = sizeof(struct sctp_adaptation_event); 65862306a36Sopenharmony_ci sai->sai_adaptation_ind = asoc->peer.adaptation_ind; 65962306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 66062306a36Sopenharmony_ci sai->sai_assoc_id = sctp_assoc2id(asoc); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci return event; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cifail: 66562306a36Sopenharmony_ci return NULL; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci/* A message has been received. Package this message as a notification 66962306a36Sopenharmony_ci * to pass it to the upper layers. Go ahead and calculate the sndrcvinfo 67062306a36Sopenharmony_ci * even if filtered out later. 67162306a36Sopenharmony_ci * 67262306a36Sopenharmony_ci * Socket Extensions for SCTP 67362306a36Sopenharmony_ci * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, 67662306a36Sopenharmony_ci struct sctp_chunk *chunk, 67762306a36Sopenharmony_ci gfp_t gfp) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct sctp_ulpevent *event = NULL; 68062306a36Sopenharmony_ci struct sk_buff *skb = chunk->skb; 68162306a36Sopenharmony_ci struct sock *sk = asoc->base.sk; 68262306a36Sopenharmony_ci size_t padding, datalen; 68362306a36Sopenharmony_ci int rx_count; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* 68662306a36Sopenharmony_ci * check to see if we need to make space for this 68762306a36Sopenharmony_ci * new skb, expand the rcvbuffer if needed, or drop 68862306a36Sopenharmony_ci * the frame 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci if (asoc->ep->rcvbuf_policy) 69162306a36Sopenharmony_ci rx_count = atomic_read(&asoc->rmem_alloc); 69262306a36Sopenharmony_ci else 69362306a36Sopenharmony_ci rx_count = atomic_read(&sk->sk_rmem_alloc); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci datalen = ntohs(chunk->chunk_hdr->length); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (rx_count >= sk->sk_rcvbuf || !sk_rmem_schedule(sk, skb, datalen)) 69862306a36Sopenharmony_ci goto fail; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* Clone the original skb, sharing the data. */ 70162306a36Sopenharmony_ci skb = skb_clone(chunk->skb, gfp); 70262306a36Sopenharmony_ci if (!skb) 70362306a36Sopenharmony_ci goto fail; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* Now that all memory allocations for this chunk succeeded, we 70662306a36Sopenharmony_ci * can mark it as received so the tsn_map is updated correctly. 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci if (sctp_tsnmap_mark(&asoc->peer.tsn_map, 70962306a36Sopenharmony_ci ntohl(chunk->subh.data_hdr->tsn), 71062306a36Sopenharmony_ci chunk->transport)) 71162306a36Sopenharmony_ci goto fail_mark; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* First calculate the padding, so we don't inadvertently 71462306a36Sopenharmony_ci * pass up the wrong length to the user. 71562306a36Sopenharmony_ci * 71662306a36Sopenharmony_ci * RFC 2960 - Section 3.2 Chunk Field Descriptions 71762306a36Sopenharmony_ci * 71862306a36Sopenharmony_ci * The total length of a chunk(including Type, Length and Value fields) 71962306a36Sopenharmony_ci * MUST be a multiple of 4 bytes. If the length of the chunk is not a 72062306a36Sopenharmony_ci * multiple of 4 bytes, the sender MUST pad the chunk with all zero 72162306a36Sopenharmony_ci * bytes and this padding is not included in the chunk length field. 72262306a36Sopenharmony_ci * The sender should never pad with more than 3 bytes. The receiver 72362306a36Sopenharmony_ci * MUST ignore the padding bytes. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ci padding = SCTP_PAD4(datalen) - datalen; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* Fixup cloned skb with just this chunks data. */ 72862306a36Sopenharmony_ci skb_trim(skb, chunk->chunk_end - padding - skb->data); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* Embed the event fields inside the cloned skb. */ 73162306a36Sopenharmony_ci event = sctp_skb2event(skb); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* Initialize event with flags 0 and correct length 73462306a36Sopenharmony_ci * Since this is a clone of the original skb, only account for 73562306a36Sopenharmony_ci * the data of this chunk as other chunks will be accounted separately. 73662306a36Sopenharmony_ci */ 73762306a36Sopenharmony_ci sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff)); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* And hold the chunk as we need it for getting the IP headers 74062306a36Sopenharmony_ci * later in recvmsg 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci sctp_chunk_hold(chunk); 74362306a36Sopenharmony_ci event->chunk = chunk; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci sctp_ulpevent_receive_data(event, asoc); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci event->stream = ntohs(chunk->subh.data_hdr->stream); 74862306a36Sopenharmony_ci if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { 74962306a36Sopenharmony_ci event->flags |= SCTP_UNORDERED; 75062306a36Sopenharmony_ci event->cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci event->tsn = ntohl(chunk->subh.data_hdr->tsn); 75362306a36Sopenharmony_ci event->msg_flags |= chunk->chunk_hdr->flags; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci return event; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cifail_mark: 75862306a36Sopenharmony_ci kfree_skb(skb); 75962306a36Sopenharmony_cifail: 76062306a36Sopenharmony_ci return NULL; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci/* Create a partial delivery related event. 76462306a36Sopenharmony_ci * 76562306a36Sopenharmony_ci * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT 76662306a36Sopenharmony_ci * 76762306a36Sopenharmony_ci * When a receiver is engaged in a partial delivery of a 76862306a36Sopenharmony_ci * message this notification will be used to indicate 76962306a36Sopenharmony_ci * various events. 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_pdapi( 77262306a36Sopenharmony_ci const struct sctp_association *asoc, 77362306a36Sopenharmony_ci __u32 indication, __u32 sid, __u32 seq, 77462306a36Sopenharmony_ci __u32 flags, gfp_t gfp) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct sctp_ulpevent *event; 77762306a36Sopenharmony_ci struct sctp_pdapi_event *pd; 77862306a36Sopenharmony_ci struct sk_buff *skb; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_pdapi_event), 78162306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 78262306a36Sopenharmony_ci if (!event) 78362306a36Sopenharmony_ci goto fail; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci skb = sctp_event2skb(event); 78662306a36Sopenharmony_ci pd = skb_put(skb, sizeof(struct sctp_pdapi_event)); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* pdapi_type 78962306a36Sopenharmony_ci * It should be SCTP_PARTIAL_DELIVERY_EVENT 79062306a36Sopenharmony_ci * 79162306a36Sopenharmony_ci * pdapi_flags: 16 bits (unsigned integer) 79262306a36Sopenharmony_ci * Currently unused. 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_ci pd->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT; 79562306a36Sopenharmony_ci pd->pdapi_flags = flags; 79662306a36Sopenharmony_ci pd->pdapi_stream = sid; 79762306a36Sopenharmony_ci pd->pdapi_seq = seq; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* pdapi_length: 32 bits (unsigned integer) 80062306a36Sopenharmony_ci * 80162306a36Sopenharmony_ci * This field is the total length of the notification data, including 80262306a36Sopenharmony_ci * the notification header. It will generally be sizeof (struct 80362306a36Sopenharmony_ci * sctp_pdapi_event). 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_ci pd->pdapi_length = sizeof(struct sctp_pdapi_event); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* pdapi_indication: 32 bits (unsigned integer) 80862306a36Sopenharmony_ci * 80962306a36Sopenharmony_ci * This field holds the indication being sent to the application. 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_ci pd->pdapi_indication = indication; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* pdapi_assoc_id: sizeof (sctp_assoc_t) 81462306a36Sopenharmony_ci * 81562306a36Sopenharmony_ci * The association id field, holds the identifier for the association. 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 81862306a36Sopenharmony_ci pd->pdapi_assoc_id = sctp_assoc2id(asoc); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci return event; 82162306a36Sopenharmony_cifail: 82262306a36Sopenharmony_ci return NULL; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_authkey( 82662306a36Sopenharmony_ci const struct sctp_association *asoc, __u16 key_id, 82762306a36Sopenharmony_ci __u32 indication, gfp_t gfp) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct sctp_ulpevent *event; 83062306a36Sopenharmony_ci struct sctp_authkey_event *ak; 83162306a36Sopenharmony_ci struct sk_buff *skb; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_authkey_event), 83462306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 83562306a36Sopenharmony_ci if (!event) 83662306a36Sopenharmony_ci goto fail; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci skb = sctp_event2skb(event); 83962306a36Sopenharmony_ci ak = skb_put(skb, sizeof(struct sctp_authkey_event)); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci ak->auth_type = SCTP_AUTHENTICATION_EVENT; 84262306a36Sopenharmony_ci ak->auth_flags = 0; 84362306a36Sopenharmony_ci ak->auth_length = sizeof(struct sctp_authkey_event); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci ak->auth_keynumber = key_id; 84662306a36Sopenharmony_ci ak->auth_altkeynumber = 0; 84762306a36Sopenharmony_ci ak->auth_indication = indication; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* 85062306a36Sopenharmony_ci * The association id field, holds the identifier for the association. 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 85362306a36Sopenharmony_ci ak->auth_assoc_id = sctp_assoc2id(asoc); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci return event; 85662306a36Sopenharmony_cifail: 85762306a36Sopenharmony_ci return NULL; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci/* 86162306a36Sopenharmony_ci * Socket Extensions for SCTP 86262306a36Sopenharmony_ci * 6.3.10. SCTP_SENDER_DRY_EVENT 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( 86562306a36Sopenharmony_ci const struct sctp_association *asoc, gfp_t gfp) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct sctp_ulpevent *event; 86862306a36Sopenharmony_ci struct sctp_sender_dry_event *sdry; 86962306a36Sopenharmony_ci struct sk_buff *skb; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event), 87262306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 87362306a36Sopenharmony_ci if (!event) 87462306a36Sopenharmony_ci return NULL; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci skb = sctp_event2skb(event); 87762306a36Sopenharmony_ci sdry = skb_put(skb, sizeof(struct sctp_sender_dry_event)); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT; 88062306a36Sopenharmony_ci sdry->sender_dry_flags = 0; 88162306a36Sopenharmony_ci sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event); 88262306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 88362306a36Sopenharmony_ci sdry->sender_dry_assoc_id = sctp_assoc2id(asoc); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return event; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event( 88962306a36Sopenharmony_ci const struct sctp_association *asoc, __u16 flags, __u16 stream_num, 89062306a36Sopenharmony_ci __be16 *stream_list, gfp_t gfp) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci struct sctp_stream_reset_event *sreset; 89362306a36Sopenharmony_ci struct sctp_ulpevent *event; 89462306a36Sopenharmony_ci struct sk_buff *skb; 89562306a36Sopenharmony_ci int length, i; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci length = sizeof(struct sctp_stream_reset_event) + 2 * stream_num; 89862306a36Sopenharmony_ci event = sctp_ulpevent_new(length, MSG_NOTIFICATION, gfp); 89962306a36Sopenharmony_ci if (!event) 90062306a36Sopenharmony_ci return NULL; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci skb = sctp_event2skb(event); 90362306a36Sopenharmony_ci sreset = skb_put(skb, length); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci sreset->strreset_type = SCTP_STREAM_RESET_EVENT; 90662306a36Sopenharmony_ci sreset->strreset_flags = flags; 90762306a36Sopenharmony_ci sreset->strreset_length = length; 90862306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 90962306a36Sopenharmony_ci sreset->strreset_assoc_id = sctp_assoc2id(asoc); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci for (i = 0; i < stream_num; i++) 91262306a36Sopenharmony_ci sreset->strreset_stream_list[i] = ntohs(stream_list[i]); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci return event; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event( 91862306a36Sopenharmony_ci const struct sctp_association *asoc, __u16 flags, __u32 local_tsn, 91962306a36Sopenharmony_ci __u32 remote_tsn, gfp_t gfp) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct sctp_assoc_reset_event *areset; 92262306a36Sopenharmony_ci struct sctp_ulpevent *event; 92362306a36Sopenharmony_ci struct sk_buff *skb; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_assoc_reset_event), 92662306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 92762306a36Sopenharmony_ci if (!event) 92862306a36Sopenharmony_ci return NULL; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci skb = sctp_event2skb(event); 93162306a36Sopenharmony_ci areset = skb_put(skb, sizeof(struct sctp_assoc_reset_event)); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci areset->assocreset_type = SCTP_ASSOC_RESET_EVENT; 93462306a36Sopenharmony_ci areset->assocreset_flags = flags; 93562306a36Sopenharmony_ci areset->assocreset_length = sizeof(struct sctp_assoc_reset_event); 93662306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 93762306a36Sopenharmony_ci areset->assocreset_assoc_id = sctp_assoc2id(asoc); 93862306a36Sopenharmony_ci areset->assocreset_local_tsn = local_tsn; 93962306a36Sopenharmony_ci areset->assocreset_remote_tsn = remote_tsn; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci return event; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistruct sctp_ulpevent *sctp_ulpevent_make_stream_change_event( 94562306a36Sopenharmony_ci const struct sctp_association *asoc, __u16 flags, 94662306a36Sopenharmony_ci __u32 strchange_instrms, __u32 strchange_outstrms, gfp_t gfp) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci struct sctp_stream_change_event *schange; 94962306a36Sopenharmony_ci struct sctp_ulpevent *event; 95062306a36Sopenharmony_ci struct sk_buff *skb; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci event = sctp_ulpevent_new(sizeof(struct sctp_stream_change_event), 95362306a36Sopenharmony_ci MSG_NOTIFICATION, gfp); 95462306a36Sopenharmony_ci if (!event) 95562306a36Sopenharmony_ci return NULL; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci skb = sctp_event2skb(event); 95862306a36Sopenharmony_ci schange = skb_put(skb, sizeof(struct sctp_stream_change_event)); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci schange->strchange_type = SCTP_STREAM_CHANGE_EVENT; 96162306a36Sopenharmony_ci schange->strchange_flags = flags; 96262306a36Sopenharmony_ci schange->strchange_length = sizeof(struct sctp_stream_change_event); 96362306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 96462306a36Sopenharmony_ci schange->strchange_assoc_id = sctp_assoc2id(asoc); 96562306a36Sopenharmony_ci schange->strchange_instrms = strchange_instrms; 96662306a36Sopenharmony_ci schange->strchange_outstrms = strchange_outstrms; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci return event; 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci/* Return the notification type, assuming this is a notification 97262306a36Sopenharmony_ci * event. 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ci__u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci union sctp_notification *notification; 97762306a36Sopenharmony_ci struct sk_buff *skb; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci skb = sctp_event2skb(event); 98062306a36Sopenharmony_ci notification = (union sctp_notification *) skb->data; 98162306a36Sopenharmony_ci return notification->sn_header.sn_type; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci/* RFC6458, Section 5.3.2. SCTP Header Information Structure 98562306a36Sopenharmony_ci * (SCTP_SNDRCV, DEPRECATED) 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_civoid sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, 98862306a36Sopenharmony_ci struct msghdr *msghdr) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct sctp_sndrcvinfo sinfo; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (sctp_ulpevent_is_notification(event)) 99362306a36Sopenharmony_ci return; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci memset(&sinfo, 0, sizeof(sinfo)); 99662306a36Sopenharmony_ci sinfo.sinfo_stream = event->stream; 99762306a36Sopenharmony_ci sinfo.sinfo_ssn = event->ssn; 99862306a36Sopenharmony_ci sinfo.sinfo_ppid = event->ppid; 99962306a36Sopenharmony_ci sinfo.sinfo_flags = event->flags; 100062306a36Sopenharmony_ci sinfo.sinfo_tsn = event->tsn; 100162306a36Sopenharmony_ci sinfo.sinfo_cumtsn = event->cumtsn; 100262306a36Sopenharmony_ci sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc); 100362306a36Sopenharmony_ci /* Context value that is set via SCTP_CONTEXT socket option. */ 100462306a36Sopenharmony_ci sinfo.sinfo_context = event->asoc->default_rcv_context; 100562306a36Sopenharmony_ci /* These fields are not used while receiving. */ 100662306a36Sopenharmony_ci sinfo.sinfo_timetolive = 0; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV, 100962306a36Sopenharmony_ci sizeof(sinfo), &sinfo); 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci/* RFC6458, Section 5.3.5 SCTP Receive Information Structure 101362306a36Sopenharmony_ci * (SCTP_SNDRCV) 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_civoid sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, 101662306a36Sopenharmony_ci struct msghdr *msghdr) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci struct sctp_rcvinfo rinfo; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (sctp_ulpevent_is_notification(event)) 102162306a36Sopenharmony_ci return; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci memset(&rinfo, 0, sizeof(struct sctp_rcvinfo)); 102462306a36Sopenharmony_ci rinfo.rcv_sid = event->stream; 102562306a36Sopenharmony_ci rinfo.rcv_ssn = event->ssn; 102662306a36Sopenharmony_ci rinfo.rcv_ppid = event->ppid; 102762306a36Sopenharmony_ci rinfo.rcv_flags = event->flags; 102862306a36Sopenharmony_ci rinfo.rcv_tsn = event->tsn; 102962306a36Sopenharmony_ci rinfo.rcv_cumtsn = event->cumtsn; 103062306a36Sopenharmony_ci rinfo.rcv_assoc_id = sctp_assoc2id(event->asoc); 103162306a36Sopenharmony_ci rinfo.rcv_context = event->asoc->default_rcv_context; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci put_cmsg(msghdr, IPPROTO_SCTP, SCTP_RCVINFO, 103462306a36Sopenharmony_ci sizeof(rinfo), &rinfo); 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci/* RFC6458, Section 5.3.6. SCTP Next Receive Information Structure 103862306a36Sopenharmony_ci * (SCTP_NXTINFO) 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_cistatic void __sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, 104162306a36Sopenharmony_ci struct msghdr *msghdr, 104262306a36Sopenharmony_ci const struct sk_buff *skb) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct sctp_nxtinfo nxtinfo; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci memset(&nxtinfo, 0, sizeof(nxtinfo)); 104762306a36Sopenharmony_ci nxtinfo.nxt_sid = event->stream; 104862306a36Sopenharmony_ci nxtinfo.nxt_ppid = event->ppid; 104962306a36Sopenharmony_ci nxtinfo.nxt_flags = event->flags; 105062306a36Sopenharmony_ci if (sctp_ulpevent_is_notification(event)) 105162306a36Sopenharmony_ci nxtinfo.nxt_flags |= SCTP_NOTIFICATION; 105262306a36Sopenharmony_ci nxtinfo.nxt_length = skb->len; 105362306a36Sopenharmony_ci nxtinfo.nxt_assoc_id = sctp_assoc2id(event->asoc); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci put_cmsg(msghdr, IPPROTO_SCTP, SCTP_NXTINFO, 105662306a36Sopenharmony_ci sizeof(nxtinfo), &nxtinfo); 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_civoid sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, 106062306a36Sopenharmony_ci struct msghdr *msghdr, 106162306a36Sopenharmony_ci struct sock *sk) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct sk_buff *skb; 106462306a36Sopenharmony_ci int err; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci skb = sctp_skb_recv_datagram(sk, MSG_PEEK | MSG_DONTWAIT, &err); 106762306a36Sopenharmony_ci if (skb != NULL) { 106862306a36Sopenharmony_ci __sctp_ulpevent_read_nxtinfo(sctp_skb2event(skb), 106962306a36Sopenharmony_ci msghdr, skb); 107062306a36Sopenharmony_ci /* Just release refcount here. */ 107162306a36Sopenharmony_ci kfree_skb(skb); 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci/* Do accounting for bytes received and hold a reference to the association 107662306a36Sopenharmony_ci * for each skb. 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_cistatic void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, 107962306a36Sopenharmony_ci struct sctp_association *asoc) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci struct sk_buff *skb, *frag; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci skb = sctp_event2skb(event); 108462306a36Sopenharmony_ci /* Set the owner and charge rwnd for bytes received. */ 108562306a36Sopenharmony_ci sctp_ulpevent_set_owner(event, asoc); 108662306a36Sopenharmony_ci sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb)); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (!skb->data_len) 108962306a36Sopenharmony_ci return; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci /* Note: Not clearing the entire event struct as this is just a 109262306a36Sopenharmony_ci * fragment of the real event. However, we still need to do rwnd 109362306a36Sopenharmony_ci * accounting. 109462306a36Sopenharmony_ci * In general, the skb passed from IP can have only 1 level of 109562306a36Sopenharmony_ci * fragments. But we allow multiple levels of fragments. 109662306a36Sopenharmony_ci */ 109762306a36Sopenharmony_ci skb_walk_frags(skb, frag) 109862306a36Sopenharmony_ci sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc); 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci/* Do accounting for bytes just read by user and release the references to 110262306a36Sopenharmony_ci * the association. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_cistatic void sctp_ulpevent_release_data(struct sctp_ulpevent *event) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci struct sk_buff *skb, *frag; 110762306a36Sopenharmony_ci unsigned int len; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* Current stack structures assume that the rcv buffer is 111062306a36Sopenharmony_ci * per socket. For UDP style sockets this is not true as 111162306a36Sopenharmony_ci * multiple associations may be on a single UDP-style socket. 111262306a36Sopenharmony_ci * Use the local private area of the skb to track the owning 111362306a36Sopenharmony_ci * association. 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci skb = sctp_event2skb(event); 111762306a36Sopenharmony_ci len = skb->len; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (!skb->data_len) 112062306a36Sopenharmony_ci goto done; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* Don't forget the fragments. */ 112362306a36Sopenharmony_ci skb_walk_frags(skb, frag) { 112462306a36Sopenharmony_ci /* NOTE: skb_shinfos are recursive. Although IP returns 112562306a36Sopenharmony_ci * skb's with only 1 level of fragments, SCTP reassembly can 112662306a36Sopenharmony_ci * increase the levels. 112762306a36Sopenharmony_ci */ 112862306a36Sopenharmony_ci sctp_ulpevent_release_frag_data(sctp_skb2event(frag)); 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_cidone: 113262306a36Sopenharmony_ci sctp_assoc_rwnd_increase(event->asoc, len); 113362306a36Sopenharmony_ci sctp_chunk_put(event->chunk); 113462306a36Sopenharmony_ci sctp_ulpevent_release_owner(event); 113562306a36Sopenharmony_ci} 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_cistatic void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci struct sk_buff *skb, *frag; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci skb = sctp_event2skb(event); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci if (!skb->data_len) 114462306a36Sopenharmony_ci goto done; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci /* Don't forget the fragments. */ 114762306a36Sopenharmony_ci skb_walk_frags(skb, frag) { 114862306a36Sopenharmony_ci /* NOTE: skb_shinfos are recursive. Although IP returns 114962306a36Sopenharmony_ci * skb's with only 1 level of fragments, SCTP reassembly can 115062306a36Sopenharmony_ci * increase the levels. 115162306a36Sopenharmony_ci */ 115262306a36Sopenharmony_ci sctp_ulpevent_release_frag_data(sctp_skb2event(frag)); 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cidone: 115662306a36Sopenharmony_ci sctp_chunk_put(event->chunk); 115762306a36Sopenharmony_ci sctp_ulpevent_release_owner(event); 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci/* Free a ulpevent that has an owner. It includes releasing the reference 116162306a36Sopenharmony_ci * to the owner, updating the rwnd in case of a DATA event and freeing the 116262306a36Sopenharmony_ci * skb. 116362306a36Sopenharmony_ci */ 116462306a36Sopenharmony_civoid sctp_ulpevent_free(struct sctp_ulpevent *event) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci if (sctp_ulpevent_is_notification(event)) 116762306a36Sopenharmony_ci sctp_ulpevent_release_owner(event); 116862306a36Sopenharmony_ci else 116962306a36Sopenharmony_ci sctp_ulpevent_release_data(event); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci kfree_skb(sctp_event2skb(event)); 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci/* Purge the skb lists holding ulpevents. */ 117562306a36Sopenharmony_ciunsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci struct sk_buff *skb; 117862306a36Sopenharmony_ci unsigned int data_unread = 0; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci while ((skb = skb_dequeue(list)) != NULL) { 118162306a36Sopenharmony_ci struct sctp_ulpevent *event = sctp_skb2event(skb); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (!sctp_ulpevent_is_notification(event)) 118462306a36Sopenharmony_ci data_unread += skb->len; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci sctp_ulpevent_free(event); 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return data_unread; 119062306a36Sopenharmony_ci} 1191