| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* SCTP kernel implementation |
|---|
| 2 | 3 | * (C) Copyright IBM Corp. 2001, 2004 |
|---|
| 3 | 4 | * Copyright (c) 1999-2000 Cisco, Inc. |
|---|
| .. | .. |
|---|
| 8 | 9 | * |
|---|
| 9 | 10 | * These functions manipulate an sctp event. The struct ulpevent is used |
|---|
| 10 | 11 | * to carry notifications and data to the ULP (sockets). |
|---|
| 11 | | - * |
|---|
| 12 | | - * This SCTP implementation is free software; |
|---|
| 13 | | - * you can redistribute it and/or modify it under the terms of |
|---|
| 14 | | - * the GNU General Public License as published by |
|---|
| 15 | | - * the Free Software Foundation; either version 2, or (at your option) |
|---|
| 16 | | - * any later version. |
|---|
| 17 | | - * |
|---|
| 18 | | - * This SCTP implementation is distributed in the hope that it |
|---|
| 19 | | - * will be useful, but WITHOUT ANY WARRANTY; without even the implied |
|---|
| 20 | | - * ************************ |
|---|
| 21 | | - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|---|
| 22 | | - * See the GNU General Public License for more details. |
|---|
| 23 | | - * |
|---|
| 24 | | - * You should have received a copy of the GNU General Public License |
|---|
| 25 | | - * along with GNU CC; see the file COPYING. If not, see |
|---|
| 26 | | - * <http://www.gnu.org/licenses/>. |
|---|
| 27 | 12 | * |
|---|
| 28 | 13 | * Please send any bug reports or fixes you make to the |
|---|
| 29 | 14 | * email address(es): |
|---|
| .. | .. |
|---|
| 253 | 238 | * When a destination address on a multi-homed peer encounters a change |
|---|
| 254 | 239 | * an interface details event is sent. |
|---|
| 255 | 240 | */ |
|---|
| 256 | | -struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( |
|---|
| 241 | +static struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( |
|---|
| 257 | 242 | const struct sctp_association *asoc, |
|---|
| 258 | 243 | const struct sockaddr_storage *aaddr, |
|---|
| 259 | 244 | int flags, int state, int error, gfp_t gfp) |
|---|
| .. | .. |
|---|
| 349 | 334 | |
|---|
| 350 | 335 | fail: |
|---|
| 351 | 336 | return NULL; |
|---|
| 337 | +} |
|---|
| 338 | + |
|---|
| 339 | +void sctp_ulpevent_notify_peer_addr_change(struct sctp_transport *transport, |
|---|
| 340 | + int state, int error) |
|---|
| 341 | +{ |
|---|
| 342 | + struct sctp_association *asoc = transport->asoc; |
|---|
| 343 | + struct sockaddr_storage addr; |
|---|
| 344 | + struct sctp_ulpevent *event; |
|---|
| 345 | + |
|---|
| 346 | + if (asoc->state < SCTP_STATE_ESTABLISHED) |
|---|
| 347 | + return; |
|---|
| 348 | + |
|---|
| 349 | + memset(&addr, 0, sizeof(struct sockaddr_storage)); |
|---|
| 350 | + memcpy(&addr, &transport->ipaddr, transport->af_specific->sockaddr_len); |
|---|
| 351 | + |
|---|
| 352 | + event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, 0, state, |
|---|
| 353 | + error, GFP_ATOMIC); |
|---|
| 354 | + if (event) |
|---|
| 355 | + asoc->stream.si->enqueue_event(&asoc->ulpq, event); |
|---|
| 352 | 356 | } |
|---|
| 353 | 357 | |
|---|
| 354 | 358 | /* Create and initialize an SCTP_REMOTE_ERROR notification. |
|---|
| .. | .. |
|---|
| 526 | 530 | return NULL; |
|---|
| 527 | 531 | } |
|---|
| 528 | 532 | |
|---|
| 533 | +struct sctp_ulpevent *sctp_ulpevent_make_send_failed_event( |
|---|
| 534 | + const struct sctp_association *asoc, struct sctp_chunk *chunk, |
|---|
| 535 | + __u16 flags, __u32 error, gfp_t gfp) |
|---|
| 536 | +{ |
|---|
| 537 | + struct sctp_send_failed_event *ssf; |
|---|
| 538 | + struct sctp_ulpevent *event; |
|---|
| 539 | + struct sk_buff *skb; |
|---|
| 540 | + int len; |
|---|
| 541 | + |
|---|
| 542 | + skb = skb_copy_expand(chunk->skb, sizeof(*ssf), 0, gfp); |
|---|
| 543 | + if (!skb) |
|---|
| 544 | + return NULL; |
|---|
| 545 | + |
|---|
| 546 | + len = ntohs(chunk->chunk_hdr->length); |
|---|
| 547 | + len -= sctp_datachk_len(&asoc->stream); |
|---|
| 548 | + |
|---|
| 549 | + skb_pull(skb, sctp_datachk_len(&asoc->stream)); |
|---|
| 550 | + event = sctp_skb2event(skb); |
|---|
| 551 | + sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); |
|---|
| 552 | + |
|---|
| 553 | + ssf = skb_push(skb, sizeof(*ssf)); |
|---|
| 554 | + ssf->ssf_type = SCTP_SEND_FAILED_EVENT; |
|---|
| 555 | + ssf->ssf_flags = flags; |
|---|
| 556 | + ssf->ssf_length = sizeof(*ssf) + len; |
|---|
| 557 | + skb_trim(skb, ssf->ssf_length); |
|---|
| 558 | + ssf->ssf_error = error; |
|---|
| 559 | + |
|---|
| 560 | + ssf->ssfe_info.snd_sid = chunk->sinfo.sinfo_stream; |
|---|
| 561 | + ssf->ssfe_info.snd_ppid = chunk->sinfo.sinfo_ppid; |
|---|
| 562 | + ssf->ssfe_info.snd_context = chunk->sinfo.sinfo_context; |
|---|
| 563 | + ssf->ssfe_info.snd_assoc_id = chunk->sinfo.sinfo_assoc_id; |
|---|
| 564 | + ssf->ssfe_info.snd_flags = chunk->chunk_hdr->flags; |
|---|
| 565 | + |
|---|
| 566 | + sctp_ulpevent_set_owner(event, asoc); |
|---|
| 567 | + ssf->ssf_assoc_id = sctp_assoc2id(asoc); |
|---|
| 568 | + |
|---|
| 569 | + return event; |
|---|
| 570 | +} |
|---|
| 571 | + |
|---|
| 529 | 572 | /* Create and initialize a SCTP_SHUTDOWN_EVENT notification. |
|---|
| 530 | 573 | * |
|---|
| 531 | 574 | * Socket Extensions for SCTP - draft-01 |
|---|
| .. | .. |
|---|
| 634 | 677 | gfp_t gfp) |
|---|
| 635 | 678 | { |
|---|
| 636 | 679 | struct sctp_ulpevent *event = NULL; |
|---|
| 637 | | - struct sk_buff *skb; |
|---|
| 638 | | - size_t padding, len; |
|---|
| 680 | + struct sk_buff *skb = chunk->skb; |
|---|
| 681 | + struct sock *sk = asoc->base.sk; |
|---|
| 682 | + size_t padding, datalen; |
|---|
| 639 | 683 | int rx_count; |
|---|
| 640 | 684 | |
|---|
| 641 | 685 | /* |
|---|
| .. | .. |
|---|
| 646 | 690 | if (asoc->ep->rcvbuf_policy) |
|---|
| 647 | 691 | rx_count = atomic_read(&asoc->rmem_alloc); |
|---|
| 648 | 692 | else |
|---|
| 649 | | - rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc); |
|---|
| 693 | + rx_count = atomic_read(&sk->sk_rmem_alloc); |
|---|
| 650 | 694 | |
|---|
| 651 | | - if (rx_count >= asoc->base.sk->sk_rcvbuf) { |
|---|
| 695 | + datalen = ntohs(chunk->chunk_hdr->length); |
|---|
| 652 | 696 | |
|---|
| 653 | | - if ((asoc->base.sk->sk_userlocks & SOCK_RCVBUF_LOCK) || |
|---|
| 654 | | - (!sk_rmem_schedule(asoc->base.sk, chunk->skb, |
|---|
| 655 | | - chunk->skb->truesize))) |
|---|
| 656 | | - goto fail; |
|---|
| 657 | | - } |
|---|
| 697 | + if (rx_count >= sk->sk_rcvbuf || !sk_rmem_schedule(sk, skb, datalen)) |
|---|
| 698 | + goto fail; |
|---|
| 658 | 699 | |
|---|
| 659 | 700 | /* Clone the original skb, sharing the data. */ |
|---|
| 660 | 701 | skb = skb_clone(chunk->skb, gfp); |
|---|
| .. | .. |
|---|
| 681 | 722 | * The sender should never pad with more than 3 bytes. The receiver |
|---|
| 682 | 723 | * MUST ignore the padding bytes. |
|---|
| 683 | 724 | */ |
|---|
| 684 | | - len = ntohs(chunk->chunk_hdr->length); |
|---|
| 685 | | - padding = SCTP_PAD4(len) - len; |
|---|
| 725 | + padding = SCTP_PAD4(datalen) - datalen; |
|---|
| 686 | 726 | |
|---|
| 687 | 727 | /* Fixup cloned skb with just this chunks data. */ |
|---|
| 688 | 728 | skb_trim(skb, chunk->chunk_end - padding - skb->data); |
|---|