|
55 | 55 | #include <net/sctp/sm.h>
|
56 | 56 |
|
57 | 57 | /* Forward declarations for internal functions. */
|
| 58 | +static void sctp_select_active_and_retran_path(struct sctp_association *asoc); |
58 | 59 | static void sctp_assoc_bh_rcv(struct work_struct *work);
|
59 | 60 | static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc);
|
60 | 61 | static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc);
|
@@ -774,9 +775,6 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
|
774 | 775 | sctp_transport_cmd_t command,
|
775 | 776 | sctp_sn_error_t error)
|
776 | 777 | {
|
777 |
| - struct sctp_transport *t = NULL; |
778 |
| - struct sctp_transport *first; |
779 |
| - struct sctp_transport *second; |
780 | 778 | struct sctp_ulpevent *event;
|
781 | 779 | struct sockaddr_storage addr;
|
782 | 780 | int spc_state = 0;
|
@@ -829,74 +827,22 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
|
829 | 827 | return;
|
830 | 828 | }
|
831 | 829 |
|
832 |
| - /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the |
833 |
| - * user. |
| 830 | + /* Generate and send a SCTP_PEER_ADDR_CHANGE notification |
| 831 | + * to the user. |
834 | 832 | */
|
835 | 833 | if (ulp_notify) {
|
836 | 834 | memset(&addr, 0, sizeof(struct sockaddr_storage));
|
837 | 835 | memcpy(&addr, &transport->ipaddr,
|
838 | 836 | transport->af_specific->sockaddr_len);
|
| 837 | + |
839 | 838 | event = sctp_ulpevent_make_peer_addr_change(asoc, &addr,
|
840 | 839 | 0, spc_state, error, GFP_ATOMIC);
|
841 | 840 | if (event)
|
842 | 841 | sctp_ulpq_tail_event(&asoc->ulpq, event);
|
843 | 842 | }
|
844 | 843 |
|
845 | 844 | /* Select new active and retran paths. */
|
846 |
| - |
847 |
| - /* Look for the two most recently used active transports. |
848 |
| - * |
849 |
| - * This code produces the wrong ordering whenever jiffies |
850 |
| - * rolls over, but we still get usable transports, so we don't |
851 |
| - * worry about it. |
852 |
| - */ |
853 |
| - first = NULL; second = NULL; |
854 |
| - |
855 |
| - list_for_each_entry(t, &asoc->peer.transport_addr_list, |
856 |
| - transports) { |
857 |
| - |
858 |
| - if ((t->state == SCTP_INACTIVE) || |
859 |
| - (t->state == SCTP_UNCONFIRMED) || |
860 |
| - (t->state == SCTP_PF)) |
861 |
| - continue; |
862 |
| - if (!first || t->last_time_heard > first->last_time_heard) { |
863 |
| - second = first; |
864 |
| - first = t; |
865 |
| - } else if (!second || |
866 |
| - t->last_time_heard > second->last_time_heard) |
867 |
| - second = t; |
868 |
| - } |
869 |
| - |
870 |
| - /* RFC 2960 6.4 Multi-Homed SCTP Endpoints |
871 |
| - * |
872 |
| - * By default, an endpoint should always transmit to the |
873 |
| - * primary path, unless the SCTP user explicitly specifies the |
874 |
| - * destination transport address (and possibly source |
875 |
| - * transport address) to use. |
876 |
| - * |
877 |
| - * [If the primary is active but not most recent, bump the most |
878 |
| - * recently used transport.] |
879 |
| - */ |
880 |
| - if (((asoc->peer.primary_path->state == SCTP_ACTIVE) || |
881 |
| - (asoc->peer.primary_path->state == SCTP_UNKNOWN)) && |
882 |
| - first != asoc->peer.primary_path) { |
883 |
| - second = first; |
884 |
| - first = asoc->peer.primary_path; |
885 |
| - } |
886 |
| - |
887 |
| - if (!second) |
888 |
| - second = first; |
889 |
| - /* If we failed to find a usable transport, just camp on the |
890 |
| - * primary, even if it is inactive. |
891 |
| - */ |
892 |
| - if (!first) { |
893 |
| - first = asoc->peer.primary_path; |
894 |
| - second = asoc->peer.primary_path; |
895 |
| - } |
896 |
| - |
897 |
| - /* Set the active and retran transports. */ |
898 |
| - asoc->peer.active_path = first; |
899 |
| - asoc->peer.retran_path = second; |
| 845 | + sctp_select_active_and_retran_path(asoc); |
900 | 846 | }
|
901 | 847 |
|
902 | 848 | /* Hold a reference to an association. */
|
@@ -1325,6 +1271,62 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
|
1325 | 1271 | __func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
|
1326 | 1272 | }
|
1327 | 1273 |
|
| 1274 | +static void sctp_select_active_and_retran_path(struct sctp_association *asoc) |
| 1275 | +{ |
| 1276 | + struct sctp_transport *trans, *trans_pri = NULL, *trans_sec = NULL; |
| 1277 | + |
| 1278 | + /* Look for the two most recently used active transports. */ |
| 1279 | + list_for_each_entry(trans, &asoc->peer.transport_addr_list, |
| 1280 | + transports) { |
| 1281 | + if (trans->state == SCTP_INACTIVE || |
| 1282 | + trans->state == SCTP_UNCONFIRMED || |
| 1283 | + trans->state == SCTP_PF) |
| 1284 | + continue; |
| 1285 | + if (trans_pri == NULL || |
| 1286 | + trans->last_time_heard > trans_pri->last_time_heard) { |
| 1287 | + trans_sec = trans_pri; |
| 1288 | + trans_pri = trans; |
| 1289 | + } else if (trans_sec == NULL || |
| 1290 | + trans->last_time_heard > trans_sec->last_time_heard) { |
| 1291 | + trans_sec = trans; |
| 1292 | + } |
| 1293 | + } |
| 1294 | + |
| 1295 | + /* RFC 2960 6.4 Multi-Homed SCTP Endpoints |
| 1296 | + * |
| 1297 | + * By default, an endpoint should always transmit to the primary |
| 1298 | + * path, unless the SCTP user explicitly specifies the |
| 1299 | + * destination transport address (and possibly source transport |
| 1300 | + * address) to use. [If the primary is active but not most recent, |
| 1301 | + * bump the most recently used transport.] |
| 1302 | + */ |
| 1303 | + if ((asoc->peer.primary_path->state == SCTP_ACTIVE || |
| 1304 | + asoc->peer.primary_path->state == SCTP_UNKNOWN) && |
| 1305 | + asoc->peer.primary_path != trans_pri) { |
| 1306 | + trans_sec = trans_pri; |
| 1307 | + trans_pri = asoc->peer.primary_path; |
| 1308 | + } |
| 1309 | + |
| 1310 | + /* We did not find anything useful for a possible retransmission |
| 1311 | + * path; either primary path that we found is the the same as |
| 1312 | + * the current one, or we didn't generally find an active one. |
| 1313 | + */ |
| 1314 | + if (trans_sec == NULL) |
| 1315 | + trans_sec = trans_pri; |
| 1316 | + |
| 1317 | + /* If we failed to find a usable transport, just camp on the |
| 1318 | + * primary, even if they are inactive. |
| 1319 | + */ |
| 1320 | + if (trans_pri == NULL) { |
| 1321 | + trans_pri = asoc->peer.primary_path; |
| 1322 | + trans_sec = asoc->peer.primary_path; |
| 1323 | + } |
| 1324 | + |
| 1325 | + /* Set the active and retran transports. */ |
| 1326 | + asoc->peer.active_path = trans_pri; |
| 1327 | + asoc->peer.retran_path = trans_sec; |
| 1328 | +} |
| 1329 | + |
1328 | 1330 | struct sctp_transport *
|
1329 | 1331 | sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
|
1330 | 1332 | struct sctp_transport *last_sent_to)
|
|
0 commit comments