Commit f8436e9f authored by David S. Miller's avatar David S. Miller

Merge conflicts with Yoshfuji's SNMP stats changes.

parents 57e3907f a2ba8aa8
...@@ -94,6 +94,9 @@ typedef enum { ...@@ -94,6 +94,9 @@ typedef enum {
SCTP_CMD_REPORT_FWDTSN, /* Report new cumulative TSN Ack. */ SCTP_CMD_REPORT_FWDTSN, /* Report new cumulative TSN Ack. */
SCTP_CMD_PROCESS_FWDTSN, /* Skips were reported, so process further. */ SCTP_CMD_PROCESS_FWDTSN, /* Skips were reported, so process further. */
SCTP_CMD_CLEAR_INIT_TAG, /* Clears association peer's inittag. */ SCTP_CMD_CLEAR_INIT_TAG, /* Clears association peer's inittag. */
SCTP_CMD_DEL_NON_PRIMARY, /* Removes non-primary peer transports. */
SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */
SCTP_CMD_FORCE_PRIM_RETRAN, /* Forces retrans. over primary path. */
SCTP_CMD_LAST SCTP_CMD_LAST
} sctp_verb_t; } sctp_verb_t;
......
...@@ -175,6 +175,10 @@ typedef enum { ...@@ -175,6 +175,10 @@ typedef enum {
SCTP_IERROR_BAD_TAG, SCTP_IERROR_BAD_TAG,
SCTP_IERROR_BIG_GAP, SCTP_IERROR_BIG_GAP,
SCTP_IERROR_DUP_TSN, SCTP_IERROR_DUP_TSN,
SCTP_IERROR_HIGH_TSN,
SCTP_IERROR_IGNORE_TSN,
SCTP_IERROR_NO_DATA,
SCTP_IERROR_BAD_STREAM,
} sctp_ierror_t; } sctp_ierror_t;
......
...@@ -322,6 +322,9 @@ void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep, ...@@ -322,6 +322,9 @@ void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
const struct sctp_chunk *chunk, const struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
struct sctp_chunk *err_chunk); struct sctp_chunk *err_chunk);
int sctp_eat_data(const struct sctp_association *asoc,
struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands);
/* 3rd level prototypes */ /* 3rd level prototypes */
__u32 sctp_generate_tag(const struct sctp_endpoint *); __u32 sctp_generate_tag(const struct sctp_endpoint *);
......
...@@ -1093,6 +1093,7 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc) ...@@ -1093,6 +1093,7 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc)
case SCTP_STATE_ESTABLISHED: case SCTP_STATE_ESTABLISHED:
case SCTP_STATE_SHUTDOWN_PENDING: case SCTP_STATE_SHUTDOWN_PENDING:
case SCTP_STATE_SHUTDOWN_RECEIVED: case SCTP_STATE_SHUTDOWN_RECEIVED:
case SCTP_STATE_SHUTDOWN_SENT:
if ((asoc->rwnd > asoc->a_rwnd) && if ((asoc->rwnd > asoc->a_rwnd) &&
((asoc->rwnd - asoc->a_rwnd) >= ((asoc->rwnd - asoc->a_rwnd) >=
min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu))) min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu)))
......
...@@ -525,10 +525,10 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -525,10 +525,10 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
int rtx_timeout, int *start_timer) int rtx_timeout, int *start_timer)
{ {
struct list_head *lqueue; struct list_head *lqueue;
struct list_head *lchunk; struct list_head *lchunk, *lchunk1;
struct sctp_transport *transport = pkt->transport; struct sctp_transport *transport = pkt->transport;
sctp_xmit_t status; sctp_xmit_t status;
struct sctp_chunk *chunk; struct sctp_chunk *chunk, *chunk1;
struct sctp_association *asoc; struct sctp_association *asoc;
int error = 0; int error = 0;
...@@ -615,6 +615,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -615,6 +615,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
* the transmitted list. * the transmitted list.
*/ */
list_add_tail(lchunk, &transport->transmitted); list_add_tail(lchunk, &transport->transmitted);
/* Mark the chunk as ineligible for fast retransmit
* after it is retransmitted.
*/
chunk->fast_retransmit = 0;
*start_timer = 1; *start_timer = 1;
q->empty = 0; q->empty = 0;
...@@ -622,6 +628,18 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -622,6 +628,18 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
lchunk = sctp_list_dequeue(lqueue); lchunk = sctp_list_dequeue(lqueue);
break; break;
}; };
/* If we are here due to a retransmit timeout or a fast
* retransmit and if there are any chunks left in the retransmit
* queue that could not fit in the PMTU sized packet, they need * to be marked as ineligible for a subsequent fast retransmit.
*/
if (rtx_timeout && !lchunk) {
list_for_each(lchunk1, lqueue) {
chunk1 = list_entry(lchunk1, struct sctp_chunk,
transmitted_list);
chunk1->fast_retransmit = 0;
}
}
} }
return error; return error;
......
...@@ -1846,9 +1846,8 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, ...@@ -1846,9 +1846,8 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp))) if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
goto clean_up; goto clean_up;
spin_lock_bh(&sctp_assocs_id_lock); spin_lock_bh(&sctp_assocs_id_lock);
error = idr_get_new(&sctp_assocs_id, error = idr_get_new_above(&sctp_assocs_id, (void *)asoc, 1,
(void *)asoc, &assoc_id);
&assoc_id);
spin_unlock_bh(&sctp_assocs_id_lock); spin_unlock_bh(&sctp_assocs_id_lock);
if (error == -EAGAIN) if (error == -EAGAIN)
goto retry; goto retry;
......
...@@ -529,6 +529,23 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds, ...@@ -529,6 +529,23 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
} }
} }
/* Helper function to stop any pending T3-RTX timers */
static void sctp_cmd_t3_rtx_timers_stop(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc)
{
struct sctp_transport *t;
struct list_head *pos;
list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, struct sctp_transport, transports);
if (timer_pending(&t->T3_rtx_timer) &&
del_timer(&t->T3_rtx_timer)) {
sctp_transport_put(t);
}
}
}
/* Helper function to update the heartbeat timer. */ /* Helper function to update the heartbeat timer. */
static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc, struct sctp_association *asoc,
...@@ -749,6 +766,26 @@ static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq, ...@@ -749,6 +766,26 @@ static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq,
return; return;
} }
/* Helper function to remove the association non-primary peer
* transports.
*/
static void sctp_cmd_del_non_primary(struct sctp_association *asoc)
{
struct sctp_transport *t;
struct list_head *pos;
struct list_head *temp;
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
t = list_entry(pos, struct sctp_transport, transports);
if (!sctp_cmp_addr_exact(&t->ipaddr,
&asoc->peer.primary_addr)) {
sctp_assoc_del_peer(asoc, &t->ipaddr);
}
}
return;
}
/* These three macros allow us to pull the debugging code out of the /* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real * main flow of sctp_do_sm() to keep attention focused on the real
* functionality there. * functionality there.
...@@ -1048,6 +1085,27 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -1048,6 +1085,27 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
if (cmd->obj.ptr) if (cmd->obj.ptr)
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(cmd->obj.ptr)); SCTP_CHUNK(cmd->obj.ptr));
/* FIXME - Eventually come up with a cleaner way to
* enabling COOKIE-ECHO + DATA bundling during
* multihoming stale cookie scenarios, the following
* command plays with asoc->peer.retran_path to
* avoid the problem of sending the COOKIE-ECHO and
* DATA in different paths, which could result
* in the association being ABORTed if the DATA chunk
* is processed first by the server. Checking the
* init error counter simply causes this command
* to be executed only during failed attempts of
* association establishment.
*/
if ((asoc->peer.retran_path !=
asoc->peer.primary_path) &&
(asoc->counters[SCTP_COUNTER_INIT_ERROR] > 0)) {
sctp_add_cmd_sf(commands,
SCTP_CMD_FORCE_PRIM_RETRAN,
SCTP_NULL());
}
break; break;
case SCTP_CMD_GEN_SHUTDOWN: case SCTP_CMD_GEN_SHUTDOWN:
...@@ -1282,6 +1340,19 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -1282,6 +1340,19 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_CLEAR_INIT_TAG: case SCTP_CMD_CLEAR_INIT_TAG:
asoc->peer.i.init_tag = 0; asoc->peer.i.init_tag = 0;
break; break;
case SCTP_CMD_DEL_NON_PRIMARY:
sctp_cmd_del_non_primary(asoc);
break;
case SCTP_CMD_T3_RTX_TIMERS_STOP:
sctp_cmd_t3_rtx_timers_stop(commands, asoc);
break;
case SCTP_CMD_FORCE_PRIM_RETRAN:
t = asoc->peer.retran_path;
asoc->peer.retran_path = asoc->peer.primary_path;
error = sctp_outq_uncork(&asoc->outqueue);
local_cork = 0;
asoc->peer.retran_path = t;
break;
default: default:
printk(KERN_WARNING "Impossible command: %u, %p\n", printk(KERN_WARNING "Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr); cmd->verb, cmd->obj.ptr);
......
This diff is collapsed.
...@@ -1697,6 +1697,32 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -1697,6 +1697,32 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
if (copy_from_user(&params, optval, optlen)) if (copy_from_user(&params, optval, optlen))
return -EFAULT; return -EFAULT;
/*
* API 7. Socket Options (setting the default value for the endpoint)
* All options that support specific settings on an association by
* filling in either an association id variable or a sockaddr_storage
* SHOULD also support setting of the same value for the entire endpoint
* (i.e. future associations). To accomplish this the following logic is
* used when setting one of these options:
* c) If neither the sockaddr_storage or association identification is
* set i.e. the sockaddr_storage is set to all 0's (INADDR_ANY) and
* the association identification is 0, the settings are a default
* and to be applied to the endpoint (all future associations).
*/
/* update default value for endpoint (all future associations) */
if (!params.spp_assoc_id &&
sctp_is_any(( union sctp_addr *)&params.spp_address)) {
if (params.spp_hbinterval)
sctp_sk(sk)->paddrparam.spp_hbinterval =
params.spp_hbinterval;
if (sctp_max_retrans_path)
sctp_sk(sk)->paddrparam.spp_pathmaxrxt =
params.spp_pathmaxrxt;
return 0;
}
trans = sctp_addr_id2transport(sk, &params.spp_address, trans = sctp_addr_id2transport(sk, &params.spp_address,
params.spp_assoc_id); params.spp_assoc_id);
if (!trans) if (!trans)
...@@ -2864,6 +2890,17 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, ...@@ -2864,6 +2890,17 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
if (copy_from_user(&params, optval, len)) if (copy_from_user(&params, optval, len))
return -EFAULT; return -EFAULT;
/* If no association id is specified retrieve the default value
* for the endpoint that will be used for all future associations
*/
if (!params.spp_assoc_id &&
sctp_is_any(( union sctp_addr *)&params.spp_address)) {
params.spp_hbinterval = sctp_sk(sk)->paddrparam.spp_hbinterval;
params.spp_pathmaxrxt = sctp_sk(sk)->paddrparam.spp_pathmaxrxt;
goto done;
}
trans = sctp_addr_id2transport(sk, &params.spp_address, trans = sctp_addr_id2transport(sk, &params.spp_address,
params.spp_assoc_id); params.spp_assoc_id);
if (!trans) if (!trans)
...@@ -2883,6 +2920,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, ...@@ -2883,6 +2920,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
*/ */
params.spp_pathmaxrxt = trans->error_threshold; params.spp_pathmaxrxt = trans->error_threshold;
done:
if (copy_to_user(optval, &params, len)) if (copy_to_user(optval, &params, len))
return -EFAULT; return -EFAULT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment