| .. | .. |
|---|
| 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. |
|---|
| .. | .. |
|---|
| 7 | 8 | * Copyright (c) 2001 La Monte H.P. Yarroll |
|---|
| 8 | 9 | * |
|---|
| 9 | 10 | * This abstraction carries sctp events to the ULP (sockets). |
|---|
| 10 | | - * |
|---|
| 11 | | - * This SCTP implementation is free software; |
|---|
| 12 | | - * you can redistribute it and/or modify it under the terms of |
|---|
| 13 | | - * the GNU General Public License as published by |
|---|
| 14 | | - * the Free Software Foundation; either version 2, or (at your option) |
|---|
| 15 | | - * any later version. |
|---|
| 16 | | - * |
|---|
| 17 | | - * This SCTP implementation is distributed in the hope that it |
|---|
| 18 | | - * will be useful, but WITHOUT ANY WARRANTY; without even the implied |
|---|
| 19 | | - * ************************ |
|---|
| 20 | | - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|---|
| 21 | | - * See the GNU General Public License for more details. |
|---|
| 22 | | - * |
|---|
| 23 | | - * You should have received a copy of the GNU General Public License |
|---|
| 24 | | - * along with GNU CC; see the file COPYING. If not, see |
|---|
| 25 | | - * <http://www.gnu.org/licenses/>. |
|---|
| 26 | 11 | * |
|---|
| 27 | 12 | * Please send any bug reports or fixes you make to the |
|---|
| 28 | 13 | * email address(es): |
|---|
| .. | .. |
|---|
| 116 | 101 | event = sctp_ulpq_reasm(ulpq, event); |
|---|
| 117 | 102 | |
|---|
| 118 | 103 | /* Do ordering if needed. */ |
|---|
| 119 | | - if ((event) && (event->msg_flags & MSG_EOR)) { |
|---|
| 104 | + if (event) { |
|---|
| 120 | 105 | /* Create a temporary list to collect chunks on. */ |
|---|
| 121 | 106 | skb_queue_head_init(&temp); |
|---|
| 122 | 107 | __skb_queue_tail(&temp, sctp_event2skb(event)); |
|---|
| 123 | 108 | |
|---|
| 124 | | - event = sctp_ulpq_order(ulpq, event); |
|---|
| 109 | + if (event->msg_flags & MSG_EOR) |
|---|
| 110 | + event = sctp_ulpq_order(ulpq, event); |
|---|
| 125 | 111 | } |
|---|
| 126 | 112 | |
|---|
| 127 | 113 | /* Send event to the ULP. 'event' is the sctp_ulpevent for |
|---|
| .. | .. |
|---|
| 129 | 115 | */ |
|---|
| 130 | 116 | if (event) { |
|---|
| 131 | 117 | event_eor = (event->msg_flags & MSG_EOR) ? 1 : 0; |
|---|
| 132 | | - sctp_ulpq_tail_event(ulpq, event); |
|---|
| 118 | + sctp_ulpq_tail_event(ulpq, &temp); |
|---|
| 133 | 119 | } |
|---|
| 134 | 120 | |
|---|
| 135 | 121 | return event_eor; |
|---|
| .. | .. |
|---|
| 193 | 179 | return sctp_clear_pd(ulpq->asoc->base.sk, ulpq->asoc); |
|---|
| 194 | 180 | } |
|---|
| 195 | 181 | |
|---|
| 196 | | -/* If the SKB of 'event' is on a list, it is the first such member |
|---|
| 197 | | - * of that list. |
|---|
| 198 | | - */ |
|---|
| 199 | | -int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) |
|---|
| 182 | +int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sk_buff_head *skb_list) |
|---|
| 200 | 183 | { |
|---|
| 201 | 184 | struct sock *sk = ulpq->asoc->base.sk; |
|---|
| 202 | 185 | struct sctp_sock *sp = sctp_sk(sk); |
|---|
| 203 | | - struct sk_buff_head *queue, *skb_list; |
|---|
| 204 | | - struct sk_buff *skb = sctp_event2skb(event); |
|---|
| 186 | + struct sctp_ulpevent *event; |
|---|
| 187 | + struct sk_buff_head *queue; |
|---|
| 188 | + struct sk_buff *skb; |
|---|
| 205 | 189 | int clear_pd = 0; |
|---|
| 206 | 190 | |
|---|
| 207 | | - skb_list = (struct sk_buff_head *) skb->prev; |
|---|
| 191 | + skb = __skb_peek(skb_list); |
|---|
| 192 | + event = sctp_skb2event(skb); |
|---|
| 208 | 193 | |
|---|
| 209 | 194 | /* If the socket is just going to throw this away, do not |
|---|
| 210 | 195 | * even try to deliver it. |
|---|
| .. | .. |
|---|
| 219 | 204 | sk_incoming_cpu_update(sk); |
|---|
| 220 | 205 | } |
|---|
| 221 | 206 | /* Check if the user wishes to receive this event. */ |
|---|
| 222 | | - if (!sctp_ulpevent_is_enabled(event, &sp->subscribe)) |
|---|
| 207 | + if (!sctp_ulpevent_is_enabled(event, ulpq->asoc->subscribe)) |
|---|
| 223 | 208 | goto out_free; |
|---|
| 224 | 209 | |
|---|
| 225 | 210 | /* If we are in partial delivery mode, post to the lobby until |
|---|
| .. | .. |
|---|
| 257 | 242 | } |
|---|
| 258 | 243 | } |
|---|
| 259 | 244 | |
|---|
| 260 | | - /* If we are harvesting multiple skbs they will be |
|---|
| 261 | | - * collected on a list. |
|---|
| 262 | | - */ |
|---|
| 263 | | - if (skb_list) |
|---|
| 264 | | - skb_queue_splice_tail_init(skb_list, queue); |
|---|
| 265 | | - else |
|---|
| 266 | | - __skb_queue_tail(queue, skb); |
|---|
| 245 | + skb_queue_splice_tail_init(skb_list, queue); |
|---|
| 267 | 246 | |
|---|
| 268 | 247 | /* Did we just complete partial delivery and need to get |
|---|
| 269 | 248 | * rolling again? Move pending data to the receive |
|---|
| .. | .. |
|---|
| 459 | 438 | * element in the queue, then count it towards |
|---|
| 460 | 439 | * possible PD. |
|---|
| 461 | 440 | */ |
|---|
| 462 | | - if (pos == ulpq->reasm.next) { |
|---|
| 441 | + if (skb_queue_is_first(&ulpq->reasm, pos)) { |
|---|
| 463 | 442 | pd_first = pos; |
|---|
| 464 | 443 | pd_last = pos; |
|---|
| 465 | 444 | pd_len = pos->len; |
|---|
| .. | .. |
|---|
| 507 | 486 | cevent = sctp_skb2event(pd_first); |
|---|
| 508 | 487 | pd_point = sctp_sk(asoc->base.sk)->pd_point; |
|---|
| 509 | 488 | if (pd_point && pd_point <= pd_len) { |
|---|
| 510 | | - retval = sctp_make_reassembled_event(sock_net(asoc->base.sk), |
|---|
| 489 | + retval = sctp_make_reassembled_event(asoc->base.net, |
|---|
| 511 | 490 | &ulpq->reasm, |
|---|
| 512 | | - pd_first, |
|---|
| 513 | | - pd_last); |
|---|
| 491 | + pd_first, pd_last); |
|---|
| 514 | 492 | if (retval) |
|---|
| 515 | 493 | sctp_ulpq_set_pd(ulpq); |
|---|
| 516 | 494 | } |
|---|
| .. | .. |
|---|
| 518 | 496 | done: |
|---|
| 519 | 497 | return retval; |
|---|
| 520 | 498 | found: |
|---|
| 521 | | - retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk), |
|---|
| 499 | + retval = sctp_make_reassembled_event(ulpq->asoc->base.net, |
|---|
| 522 | 500 | &ulpq->reasm, first_frag, pos); |
|---|
| 523 | 501 | if (retval) |
|---|
| 524 | 502 | retval->msg_flags |= MSG_EOR; |
|---|
| .. | .. |
|---|
| 584 | 562 | * further. |
|---|
| 585 | 563 | */ |
|---|
| 586 | 564 | done: |
|---|
| 587 | | - retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk), |
|---|
| 588 | | - &ulpq->reasm, first_frag, last_frag); |
|---|
| 565 | + retval = sctp_make_reassembled_event(ulpq->asoc->base.net, &ulpq->reasm, |
|---|
| 566 | + first_frag, last_frag); |
|---|
| 589 | 567 | if (retval && is_last) |
|---|
| 590 | 568 | retval->msg_flags |= MSG_EOR; |
|---|
| 591 | 569 | |
|---|
| .. | .. |
|---|
| 685 | 663 | * further. |
|---|
| 686 | 664 | */ |
|---|
| 687 | 665 | done: |
|---|
| 688 | | - retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk), |
|---|
| 689 | | - &ulpq->reasm, first_frag, last_frag); |
|---|
| 666 | + retval = sctp_make_reassembled_event(ulpq->asoc->base.net, &ulpq->reasm, |
|---|
| 667 | + first_frag, last_frag); |
|---|
| 690 | 668 | return retval; |
|---|
| 691 | 669 | } |
|---|
| 692 | 670 | |
|---|
| .. | .. |
|---|
| 738 | 716 | static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq) |
|---|
| 739 | 717 | { |
|---|
| 740 | 718 | struct sctp_ulpevent *event = NULL; |
|---|
| 741 | | - struct sk_buff_head temp; |
|---|
| 742 | 719 | |
|---|
| 743 | 720 | if (skb_queue_empty(&ulpq->reasm)) |
|---|
| 744 | 721 | return; |
|---|
| 745 | 722 | |
|---|
| 746 | 723 | while ((event = sctp_ulpq_retrieve_reassembled(ulpq)) != NULL) { |
|---|
| 747 | | - /* Do ordering if needed. */ |
|---|
| 748 | | - if ((event) && (event->msg_flags & MSG_EOR)) { |
|---|
| 749 | | - skb_queue_head_init(&temp); |
|---|
| 750 | | - __skb_queue_tail(&temp, sctp_event2skb(event)); |
|---|
| 724 | + struct sk_buff_head temp; |
|---|
| 751 | 725 | |
|---|
| 726 | + skb_queue_head_init(&temp); |
|---|
| 727 | + __skb_queue_tail(&temp, sctp_event2skb(event)); |
|---|
| 728 | + |
|---|
| 729 | + /* Do ordering if needed. */ |
|---|
| 730 | + if (event->msg_flags & MSG_EOR) |
|---|
| 752 | 731 | event = sctp_ulpq_order(ulpq, event); |
|---|
| 753 | | - } |
|---|
| 754 | 732 | |
|---|
| 755 | 733 | /* Send event to the ULP. 'event' is the |
|---|
| 756 | 734 | * sctp_ulpevent for very first SKB on the temp' list. |
|---|
| 757 | 735 | */ |
|---|
| 758 | 736 | if (event) |
|---|
| 759 | | - sctp_ulpq_tail_event(ulpq, event); |
|---|
| 737 | + sctp_ulpq_tail_event(ulpq, &temp); |
|---|
| 760 | 738 | } |
|---|
| 761 | 739 | } |
|---|
| 762 | 740 | |
|---|
| 763 | 741 | |
|---|
| 764 | 742 | /* Helper function to gather skbs that have possibly become |
|---|
| 765 | | - * ordered by an an incoming chunk. |
|---|
| 743 | + * ordered by an incoming chunk. |
|---|
| 766 | 744 | */ |
|---|
| 767 | 745 | static void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, |
|---|
| 768 | 746 | struct sctp_ulpevent *event) |
|---|
| .. | .. |
|---|
| 956 | 934 | if (event) { |
|---|
| 957 | 935 | /* see if we have more ordered that we can deliver */ |
|---|
| 958 | 936 | sctp_ulpq_retrieve_ordered(ulpq, event); |
|---|
| 959 | | - sctp_ulpq_tail_event(ulpq, event); |
|---|
| 937 | + sctp_ulpq_tail_event(ulpq, &temp); |
|---|
| 960 | 938 | } |
|---|
| 961 | 939 | } |
|---|
| 962 | 940 | |
|---|
| .. | .. |
|---|
| 1082 | 1060 | event = sctp_ulpq_retrieve_first(ulpq); |
|---|
| 1083 | 1061 | /* Send event to the ULP. */ |
|---|
| 1084 | 1062 | if (event) { |
|---|
| 1085 | | - sctp_ulpq_tail_event(ulpq, event); |
|---|
| 1063 | + struct sk_buff_head temp; |
|---|
| 1064 | + |
|---|
| 1065 | + skb_queue_head_init(&temp); |
|---|
| 1066 | + __skb_queue_tail(&temp, sctp_event2skb(event)); |
|---|
| 1067 | + sctp_ulpq_tail_event(ulpq, &temp); |
|---|
| 1086 | 1068 | sctp_ulpq_set_pd(ulpq); |
|---|
| 1087 | 1069 | return; |
|---|
| 1088 | 1070 | } |
|---|
| .. | .. |
|---|
| 1106 | 1088 | freed += sctp_ulpq_renege_frags(ulpq, needed - freed); |
|---|
| 1107 | 1089 | } |
|---|
| 1108 | 1090 | /* If able to free enough room, accept this chunk. */ |
|---|
| 1109 | | - if (freed >= needed) { |
|---|
| 1091 | + if (sk_rmem_schedule(asoc->base.sk, chunk->skb, needed) && |
|---|
| 1092 | + freed >= needed) { |
|---|
| 1110 | 1093 | int retval = sctp_ulpq_tail_data(ulpq, chunk, gfp); |
|---|
| 1111 | 1094 | /* |
|---|
| 1112 | 1095 | * Enter partial delivery if chunk has not been |
|---|
| .. | .. |
|---|
| 1129 | 1112 | void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp) |
|---|
| 1130 | 1113 | { |
|---|
| 1131 | 1114 | struct sctp_ulpevent *ev = NULL; |
|---|
| 1132 | | - struct sock *sk; |
|---|
| 1133 | 1115 | struct sctp_sock *sp; |
|---|
| 1116 | + struct sock *sk; |
|---|
| 1134 | 1117 | |
|---|
| 1135 | 1118 | if (!ulpq->pd_mode) |
|---|
| 1136 | 1119 | return; |
|---|
| 1137 | 1120 | |
|---|
| 1138 | 1121 | sk = ulpq->asoc->base.sk; |
|---|
| 1139 | 1122 | sp = sctp_sk(sk); |
|---|
| 1140 | | - if (sctp_ulpevent_type_enabled(SCTP_PARTIAL_DELIVERY_EVENT, |
|---|
| 1141 | | - &sctp_sk(sk)->subscribe)) |
|---|
| 1123 | + if (sctp_ulpevent_type_enabled(ulpq->asoc->subscribe, |
|---|
| 1124 | + SCTP_PARTIAL_DELIVERY_EVENT)) |
|---|
| 1142 | 1125 | ev = sctp_ulpevent_make_pdapi(ulpq->asoc, |
|---|
| 1143 | 1126 | SCTP_PARTIAL_DELIVERY_ABORTED, |
|---|
| 1144 | 1127 | 0, 0, 0, gfp); |
|---|