aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/outqueue.c
diff options
context:
space:
mode:
authorMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>2018-05-14 13:34:37 -0400
committerDavid S. Miller <davem@davemloft.net>2018-05-14 22:57:14 -0400
commit0d634b0c94c9d8298f24a58e4af56c85dc06bb35 (patch)
tree9c929ba54bb692bfa50fc7fd704251c12e1eccac /net/sctp/outqueue.c
parentb9fd683982c9d190cbccd8a32d885bf84bb4a12d (diff)
sctp: factor out sctp_outq_select_transport
We had two spots doing such complex operation and they were very close to each other, a bit more tailored to here or there. This patch unifies these under the same function, sctp_outq_select_transport, which knows how to handle control chunks and original transmissions (but not retransmissions). Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r--net/sctp/outqueue.c187
1 files changed, 90 insertions, 97 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 300bd0dfc7c1..bda50596d4bf 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -791,6 +791,90 @@ static int sctp_packet_singleton(struct sctp_transport *transport,
791 return sctp_packet_transmit(&singleton, gfp); 791 return sctp_packet_transmit(&singleton, gfp);
792} 792}
793 793
794static bool sctp_outq_select_transport(struct sctp_chunk *chunk,
795 struct sctp_association *asoc,
796 struct sctp_transport **transport,
797 struct list_head *transport_list)
798{
799 struct sctp_transport *new_transport = chunk->transport;
800 struct sctp_transport *curr = *transport;
801 bool changed = false;
802
803 if (!new_transport) {
804 if (!sctp_chunk_is_data(chunk)) {
805 /*
806 * If we have a prior transport pointer, see if
807 * the destination address of the chunk
808 * matches the destination address of the
809 * current transport. If not a match, then
810 * try to look up the transport with a given
811 * destination address. We do this because
812 * after processing ASCONFs, we may have new
813 * transports created.
814 */
815 if (curr && sctp_cmp_addr_exact(&chunk->dest,
816 &curr->ipaddr))
817 new_transport = curr;
818 else
819 new_transport = sctp_assoc_lookup_paddr(asoc,
820 &chunk->dest);
821 }
822
823 /* if we still don't have a new transport, then
824 * use the current active path.
825 */
826 if (!new_transport)
827 new_transport = asoc->peer.active_path;
828 } else {
829 __u8 type;
830
831 switch (new_transport->state) {
832 case SCTP_INACTIVE:
833 case SCTP_UNCONFIRMED:
834 case SCTP_PF:
835 /* If the chunk is Heartbeat or Heartbeat Ack,
836 * send it to chunk->transport, even if it's
837 * inactive.
838 *
839 * 3.3.6 Heartbeat Acknowledgement:
840 * ...
841 * A HEARTBEAT ACK is always sent to the source IP
842 * address of the IP datagram containing the
843 * HEARTBEAT chunk to which this ack is responding.
844 * ...
845 *
846 * ASCONF_ACKs also must be sent to the source.
847 */
848 type = chunk->chunk_hdr->type;
849 if (type != SCTP_CID_HEARTBEAT &&
850 type != SCTP_CID_HEARTBEAT_ACK &&
851 type != SCTP_CID_ASCONF_ACK)
852 new_transport = asoc->peer.active_path;
853 break;
854 default:
855 break;
856 }
857 }
858
859 /* Are we switching transports? Take care of transport locks. */
860 if (new_transport != curr) {
861 changed = true;
862 curr = new_transport;
863 *transport = curr;
864 if (list_empty(&curr->send_ready))
865 list_add_tail(&curr->send_ready, transport_list);
866
867 sctp_packet_config(&curr->packet, asoc->peer.i.init_tag,
868 asoc->peer.ecn_capable);
869 /* We've switched transports, so apply the
870 * Burst limit to the new transport.
871 */
872 sctp_transport_burst_limited(curr);
873 }
874
875 return changed;
876}
877
794/* 878/*
795 * Try to flush an outqueue. 879 * Try to flush an outqueue.
796 * 880 *
@@ -806,7 +890,6 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
806 struct sctp_association *asoc = q->asoc; 890 struct sctp_association *asoc = q->asoc;
807 __u32 vtag = asoc->peer.i.init_tag; 891 __u32 vtag = asoc->peer.i.init_tag;
808 struct sctp_transport *transport = NULL; 892 struct sctp_transport *transport = NULL;
809 struct sctp_transport *new_transport;
810 struct sctp_chunk *chunk, *tmp; 893 struct sctp_chunk *chunk, *tmp;
811 enum sctp_xmit status; 894 enum sctp_xmit status;
812 int error = 0; 895 int error = 0;
@@ -843,68 +926,12 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
843 926
844 list_del_init(&chunk->list); 927 list_del_init(&chunk->list);
845 928
846 /* Pick the right transport to use. */ 929 /* Pick the right transport to use. Should always be true for
847 new_transport = chunk->transport; 930 * the first chunk as we don't have a transport by then.
848
849 if (!new_transport) {
850 /*
851 * If we have a prior transport pointer, see if
852 * the destination address of the chunk
853 * matches the destination address of the
854 * current transport. If not a match, then
855 * try to look up the transport with a given
856 * destination address. We do this because
857 * after processing ASCONFs, we may have new
858 * transports created.
859 */
860 if (transport &&
861 sctp_cmp_addr_exact(&chunk->dest,
862 &transport->ipaddr))
863 new_transport = transport;
864 else
865 new_transport = sctp_assoc_lookup_paddr(asoc,
866 &chunk->dest);
867
868 /* if we still don't have a new transport, then
869 * use the current active path.
870 */
871 if (!new_transport)
872 new_transport = asoc->peer.active_path;
873 } else if ((new_transport->state == SCTP_INACTIVE) ||
874 (new_transport->state == SCTP_UNCONFIRMED) ||
875 (new_transport->state == SCTP_PF)) {
876 /* If the chunk is Heartbeat or Heartbeat Ack,
877 * send it to chunk->transport, even if it's
878 * inactive.
879 *
880 * 3.3.6 Heartbeat Acknowledgement:
881 * ...
882 * A HEARTBEAT ACK is always sent to the source IP
883 * address of the IP datagram containing the
884 * HEARTBEAT chunk to which this ack is responding.
885 * ...
886 *
887 * ASCONF_ACKs also must be sent to the source.
888 */
889 if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT &&
890 chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT_ACK &&
891 chunk->chunk_hdr->type != SCTP_CID_ASCONF_ACK)
892 new_transport = asoc->peer.active_path;
893 }
894
895 /* Are we switching transports?
896 * Take care of transport locks.
897 */ 931 */
898 if (new_transport != transport) { 932 if (sctp_outq_select_transport(chunk, asoc, &transport,
899 transport = new_transport; 933 &transport_list))
900 if (list_empty(&transport->send_ready)) {
901 list_add_tail(&transport->send_ready,
902 &transport_list);
903 }
904 packet = &transport->packet; 934 packet = &transport->packet;
905 sctp_packet_config(packet, vtag,
906 asoc->peer.ecn_capable);
907 }
908 935
909 switch (chunk->chunk_hdr->type) { 936 switch (chunk->chunk_hdr->type) {
910 /* 937 /*
@@ -1072,43 +1099,9 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
1072 goto sctp_flush_out; 1099 goto sctp_flush_out;
1073 } 1100 }
1074 1101
1075 /* If there is a specified transport, use it. 1102 if (sctp_outq_select_transport(chunk, asoc, &transport,
1076 * Otherwise, we want to use the active path. 1103 &transport_list))
1077 */
1078 new_transport = chunk->transport;
1079 if (!new_transport ||
1080 ((new_transport->state == SCTP_INACTIVE) ||
1081 (new_transport->state == SCTP_UNCONFIRMED) ||
1082 (new_transport->state == SCTP_PF)))
1083 new_transport = asoc->peer.active_path;
1084 if (new_transport->state == SCTP_UNCONFIRMED) {
1085 WARN_ONCE(1, "Attempt to send packet on unconfirmed path.");
1086 sctp_sched_dequeue_done(q, chunk);
1087 sctp_chunk_fail(chunk, 0);
1088 sctp_chunk_free(chunk);
1089 continue;
1090 }
1091
1092 /* Change packets if necessary. */
1093 if (new_transport != transport) {
1094 transport = new_transport;
1095
1096 /* Schedule to have this transport's
1097 * packet flushed.
1098 */
1099 if (list_empty(&transport->send_ready)) {
1100 list_add_tail(&transport->send_ready,
1101 &transport_list);
1102 }
1103
1104 packet = &transport->packet; 1104 packet = &transport->packet;
1105 sctp_packet_config(packet, vtag,
1106 asoc->peer.ecn_capable);
1107 /* We've switched transports, so apply the
1108 * Burst limit to the new transport.
1109 */
1110 sctp_transport_burst_limited(transport);
1111 }
1112 1105
1113 pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p " 1106 pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
1114 "skb->users:%d\n", 1107 "skb->users:%d\n",