void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned);
void sctp_assoc_set_primary(struct sctp_association *,
struct sctp_transport *);
+void sctp_assoc_del_nonprimary_peers(struct sctp_association *,
+ struct sctp_transport *);
int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *,
gfp_t);
int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *,
return NULL;
}
+/* Remove all transports except a give one */
+void sctp_assoc_del_nonprimary_peers(struct sctp_association *asoc,
+ struct sctp_transport *primary)
+{
+ struct sctp_transport *temp;
+ struct sctp_transport *t;
+
+ list_for_each_entry_safe(t, temp, &asoc->peer.transport_addr_list,
+ transports) {
+ /* if the current transport is not the primary one, delete it */
+ if (t != primary)
+ sctp_assoc_rm_peer(asoc, t);
+ }
+
+ return;
+}
+
/* Engage in transport control operations.
* Mark the transport up or down and send a notification to the user.
* Select and update the new active and retran paths.
struct sctp_transport *peer;
struct sctp_af *af;
union sctp_addr addr;
- struct list_head *pos;
union sctp_addr_param *addr_param;
addr_param = (union sctp_addr_param *)
return SCTP_ERROR_INV_PARAM;
af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
+
+ /* ADDIP 4.2.1 This parameter MUST NOT contain a broadcast
+ * or multicast address.
+ * (note: wildcard is permitted and requires special handling so
+ * make sure we check for that)
+ */
+ if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb))
+ return SCTP_ERROR_INV_PARAM;
+
switch (asconf_param->param_hdr.type) {
case SCTP_PARAM_ADD_IP:
+ /* Section 4.2.1:
+ * If the address 0.0.0.0 or ::0 is provided, the source
+ * address of the packet MUST be added.
+ */
+ if (af->is_any(&addr))
+ memcpy(&addr, &asconf->source, sizeof(addr));
+
/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
* request and does not have the local resources to add this
* new address to the association, it MUST return an Error
* MUST send an Error Cause TLV with the error cause set to the
* new error code 'Request to Delete Last Remaining IP Address'.
*/
- pos = asoc->peer.transport_addr_list.next;
- if (pos->next == &asoc->peer.transport_addr_list)
+ if (asoc->peer.transport_count == 1)
return SCTP_ERROR_DEL_LAST_IP;
/* ADDIP 4.3 D8) If a request is received to delete an IP
if (sctp_cmp_addr_exact(sctp_source(asconf), &addr))
return SCTP_ERROR_DEL_SRC_IP;
- sctp_assoc_del_peer(asoc, &addr);
+ /* Section 4.2.2
+ * If the address 0.0.0.0 or ::0 is provided, all
+ * addresses of the peer except the source address of the
+ * packet MUST be deleted.
+ */
+ if (af->is_any(&addr)) {
+ sctp_assoc_set_primary(asoc, asconf->transport);
+ sctp_assoc_del_nonprimary_peers(asoc,
+ asconf->transport);
+ } else
+ sctp_assoc_del_peer(asoc, &addr);
break;
case SCTP_PARAM_SET_PRIMARY:
+ /* ADDIP Section 4.2.4
+ * If the address 0.0.0.0 or ::0 is provided, the receiver
+ * MAY mark the source address of the packet as its
+ * primary.
+ */
+ if (af->is_any(&addr))
+ memcpy(&addr.v4, sctp_source(asconf), sizeof(addr));
+
peer = sctp_assoc_lookup_paddr(asoc, &addr);
if (!peer)
return SCTP_ERROR_INV_PARAM;