Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Mostly simple cases of overlapping changes (adding code nearby, a function whose name changes, for example). Signed-off-by: David S. Miller <davem@davemloft.net>
此提交包含在:
@@ -246,6 +246,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
|
||||
if (!sctp_ulpq_init(&asoc->ulpq, asoc))
|
||||
goto fail_init;
|
||||
|
||||
if (sctp_stream_new(asoc, gfp))
|
||||
goto fail_init;
|
||||
|
||||
/* Assume that peer would support both address types unless we are
|
||||
* told otherwise.
|
||||
*/
|
||||
@@ -264,7 +267,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
|
||||
/* AUTH related initializations */
|
||||
INIT_LIST_HEAD(&asoc->endpoint_shared_keys);
|
||||
if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp))
|
||||
goto fail_init;
|
||||
goto stream_free;
|
||||
|
||||
asoc->active_key_id = ep->active_key_id;
|
||||
asoc->prsctp_enable = ep->prsctp_enable;
|
||||
@@ -287,6 +290,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
|
||||
|
||||
return asoc;
|
||||
|
||||
stream_free:
|
||||
sctp_stream_free(asoc->stream);
|
||||
fail_init:
|
||||
sock_put(asoc->base.sk);
|
||||
sctp_endpoint_put(asoc->ep);
|
||||
@@ -1407,7 +1412,7 @@ sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
|
||||
/* Update the association's pmtu and frag_point by going through all the
|
||||
* transports. This routine is called when a transport's PMTU has changed.
|
||||
*/
|
||||
void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc)
|
||||
void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
|
||||
{
|
||||
struct sctp_transport *t;
|
||||
__u32 pmtu = 0;
|
||||
@@ -1419,8 +1424,8 @@ void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc)
|
||||
list_for_each_entry(t, &asoc->peer.transport_addr_list,
|
||||
transports) {
|
||||
if (t->pmtu_pending && t->dst) {
|
||||
sctp_transport_update_pmtu(sk, t,
|
||||
SCTP_TRUNC4(dst_mtu(t->dst)));
|
||||
sctp_transport_update_pmtu(
|
||||
t, SCTP_TRUNC4(dst_mtu(t->dst)));
|
||||
t->pmtu_pending = 0;
|
||||
}
|
||||
if (!pmtu || (t->pathmtu < pmtu))
|
||||
|
@@ -401,10 +401,10 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
|
||||
|
||||
if (t->param_flags & SPP_PMTUD_ENABLE) {
|
||||
/* Update transports view of the MTU */
|
||||
sctp_transport_update_pmtu(sk, t, pmtu);
|
||||
sctp_transport_update_pmtu(t, pmtu);
|
||||
|
||||
/* Update association pmtu. */
|
||||
sctp_assoc_sync_pmtu(sk, asoc);
|
||||
sctp_assoc_sync_pmtu(asoc);
|
||||
}
|
||||
|
||||
/* Retransmit with the new pmtu setting.
|
||||
|
@@ -86,43 +86,53 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag,
|
||||
{
|
||||
struct sctp_transport *tp = packet->transport;
|
||||
struct sctp_association *asoc = tp->asoc;
|
||||
struct sock *sk;
|
||||
|
||||
pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag);
|
||||
|
||||
packet->vtag = vtag;
|
||||
|
||||
if (asoc && tp->dst) {
|
||||
struct sock *sk = asoc->base.sk;
|
||||
/* do the following jobs only once for a flush schedule */
|
||||
if (!sctp_packet_empty(packet))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
if (__sk_dst_get(sk) != tp->dst) {
|
||||
dst_hold(tp->dst);
|
||||
sk_setup_caps(sk, tp->dst);
|
||||
}
|
||||
/* set packet max_size with pathmtu */
|
||||
packet->max_size = tp->pathmtu;
|
||||
if (!asoc)
|
||||
return;
|
||||
|
||||
if (sk_can_gso(sk)) {
|
||||
struct net_device *dev = tp->dst->dev;
|
||||
|
||||
packet->max_size = dev->gso_max_size;
|
||||
} else {
|
||||
packet->max_size = asoc->pathmtu;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
} else {
|
||||
packet->max_size = tp->pathmtu;
|
||||
/* update dst or transport pathmtu if in need */
|
||||
sk = asoc->base.sk;
|
||||
if (!sctp_transport_dst_check(tp)) {
|
||||
sctp_transport_route(tp, NULL, sctp_sk(sk));
|
||||
if (asoc->param_flags & SPP_PMTUD_ENABLE)
|
||||
sctp_assoc_sync_pmtu(asoc);
|
||||
} else if (!sctp_transport_pmtu_check(tp)) {
|
||||
if (asoc->param_flags & SPP_PMTUD_ENABLE)
|
||||
sctp_assoc_sync_pmtu(asoc);
|
||||
}
|
||||
|
||||
if (ecn_capable && sctp_packet_empty(packet)) {
|
||||
struct sctp_chunk *chunk;
|
||||
/* If there a is a prepend chunk stick it on the list before
|
||||
* any other chunks get appended.
|
||||
*/
|
||||
if (ecn_capable) {
|
||||
struct sctp_chunk *chunk = sctp_get_ecne_prepend(asoc);
|
||||
|
||||
/* If there a is a prepend chunk stick it on the list before
|
||||
* any other chunks get appended.
|
||||
*/
|
||||
chunk = sctp_get_ecne_prepend(asoc);
|
||||
if (chunk)
|
||||
sctp_packet_append_chunk(packet, chunk);
|
||||
}
|
||||
|
||||
if (!tp->dst)
|
||||
return;
|
||||
|
||||
/* set packet max_size with gso_max_size if gso is enabled*/
|
||||
rcu_read_lock();
|
||||
if (__sk_dst_get(sk) != tp->dst) {
|
||||
dst_hold(tp->dst);
|
||||
sk_setup_caps(sk, tp->dst);
|
||||
}
|
||||
packet->max_size = sk_can_gso(sk) ? tp->dst->dev->gso_max_size
|
||||
: asoc->pathmtu;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* Initialize the packet structure. */
|
||||
@@ -582,12 +592,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
|
||||
sh->vtag = htonl(packet->vtag);
|
||||
sh->checksum = 0;
|
||||
|
||||
/* update dst if in need */
|
||||
if (!sctp_transport_dst_check(tp)) {
|
||||
sctp_transport_route(tp, NULL, sctp_sk(sk));
|
||||
if (asoc && asoc->param_flags & SPP_PMTUD_ENABLE)
|
||||
sctp_assoc_sync_pmtu(sk, asoc);
|
||||
}
|
||||
/* drop packet if no dst */
|
||||
dst = dst_clone(tp->dst);
|
||||
if (!dst) {
|
||||
IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
|
||||
@@ -704,7 +709,7 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
|
||||
*/
|
||||
|
||||
if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) &&
|
||||
!chunk->msg->force_delay)
|
||||
!asoc->force_delay)
|
||||
/* Nothing unacked */
|
||||
return SCTP_XMIT_OK;
|
||||
|
||||
|
@@ -1036,8 +1036,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
|
||||
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
|
||||
* stream identifier.
|
||||
*/
|
||||
if (chunk->sinfo.sinfo_stream >=
|
||||
asoc->c.sinit_num_ostreams) {
|
||||
if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) {
|
||||
|
||||
/* Mark as failed send. */
|
||||
sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM);
|
||||
|
@@ -361,8 +361,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
|
||||
sctp_seq_dump_remote_addrs(seq, assoc);
|
||||
seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d "
|
||||
"%8d %8d %8d %8d",
|
||||
assoc->hbinterval, assoc->c.sinit_max_instreams,
|
||||
assoc->c.sinit_num_ostreams, assoc->max_retrans,
|
||||
assoc->hbinterval, assoc->stream->incnt,
|
||||
assoc->stream->outcnt, assoc->max_retrans,
|
||||
assoc->init_retries, assoc->shutdown_retries,
|
||||
assoc->rtx_data_chunks,
|
||||
atomic_read(&sk->sk_wmem_alloc),
|
||||
|
@@ -2460,15 +2460,10 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
|
||||
* association.
|
||||
*/
|
||||
if (!asoc->temp) {
|
||||
int error;
|
||||
|
||||
asoc->stream = sctp_stream_new(asoc->c.sinit_max_instreams,
|
||||
asoc->c.sinit_num_ostreams, gfp);
|
||||
if (!asoc->stream)
|
||||
if (sctp_stream_init(asoc, gfp))
|
||||
goto clean_up;
|
||||
|
||||
error = sctp_assoc_set_id(asoc, gfp);
|
||||
if (error)
|
||||
if (sctp_assoc_set_id(asoc, gfp))
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
|
@@ -3955,7 +3955,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(struct net *net,
|
||||
|
||||
/* Silently discard the chunk if stream-id is not valid */
|
||||
sctp_walk_fwdtsn(skip, chunk) {
|
||||
if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams)
|
||||
if (ntohs(skip->stream) >= asoc->stream->incnt)
|
||||
goto discard_noforce;
|
||||
}
|
||||
|
||||
@@ -4026,7 +4026,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
|
||||
|
||||
/* Silently discard the chunk if stream-id is not valid */
|
||||
sctp_walk_fwdtsn(skip, chunk) {
|
||||
if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams)
|
||||
if (ntohs(skip->stream) >= asoc->stream->incnt)
|
||||
goto gen_shutdown;
|
||||
}
|
||||
|
||||
@@ -6362,7 +6362,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
|
||||
* and discard the DATA chunk.
|
||||
*/
|
||||
sid = ntohs(data_hdr->stream);
|
||||
if (sid >= asoc->c.sinit_max_instreams) {
|
||||
if (sid >= asoc->stream->incnt) {
|
||||
/* Mark tsn as received even though we drop it */
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
|
||||
|
||||
|
@@ -1907,7 +1907,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
|
||||
}
|
||||
|
||||
if (asoc->pmtu_pending)
|
||||
sctp_assoc_pending_pmtu(sk, asoc);
|
||||
sctp_assoc_pending_pmtu(asoc);
|
||||
|
||||
/* If fragmentation is disabled and the message length exceeds the
|
||||
* association fragmentation point, return EMSGSIZE. The I-D
|
||||
@@ -1920,7 +1920,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
|
||||
}
|
||||
|
||||
/* Check for invalid stream. */
|
||||
if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) {
|
||||
if (sinfo->sinfo_stream >= asoc->stream->outcnt) {
|
||||
err = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
@@ -1965,7 +1965,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
|
||||
err = PTR_ERR(datamsg);
|
||||
goto out_free;
|
||||
}
|
||||
datamsg->force_delay = !!(msg->msg_flags & MSG_MORE);
|
||||
asoc->force_delay = !!(msg->msg_flags & MSG_MORE);
|
||||
|
||||
/* Now send the (possibly) fragmented message. */
|
||||
list_for_each_entry(chunk, &datamsg->chunks, frag_list) {
|
||||
@@ -2435,7 +2435,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
|
||||
if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {
|
||||
if (trans) {
|
||||
trans->pathmtu = params->spp_pathmtu;
|
||||
sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc);
|
||||
sctp_assoc_sync_pmtu(asoc);
|
||||
} else if (asoc) {
|
||||
asoc->pathmtu = params->spp_pathmtu;
|
||||
} else {
|
||||
@@ -2451,7 +2451,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
|
||||
(trans->param_flags & ~SPP_PMTUD) | pmtud_change;
|
||||
if (update) {
|
||||
sctp_transport_pmtu(trans, sctp_opt2sk(sp));
|
||||
sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc);
|
||||
sctp_assoc_sync_pmtu(asoc);
|
||||
}
|
||||
} else if (asoc) {
|
||||
asoc->param_flags =
|
||||
@@ -4497,8 +4497,8 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
|
||||
info->sctpi_rwnd = asoc->a_rwnd;
|
||||
info->sctpi_unackdata = asoc->unack_data;
|
||||
info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
|
||||
info->sctpi_instrms = asoc->c.sinit_max_instreams;
|
||||
info->sctpi_outstrms = asoc->c.sinit_num_ostreams;
|
||||
info->sctpi_instrms = asoc->stream->incnt;
|
||||
info->sctpi_outstrms = asoc->stream->outcnt;
|
||||
list_for_each(pos, &asoc->base.inqueue.in_chunk_list)
|
||||
info->sctpi_inqueue++;
|
||||
list_for_each(pos, &asoc->outqueue.out_chunk_list)
|
||||
@@ -4727,8 +4727,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
|
||||
status.sstat_unackdata = asoc->unack_data;
|
||||
|
||||
status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
|
||||
status.sstat_instrms = asoc->c.sinit_max_instreams;
|
||||
status.sstat_outstrms = asoc->c.sinit_num_ostreams;
|
||||
status.sstat_instrms = asoc->stream->incnt;
|
||||
status.sstat_outstrms = asoc->stream->outcnt;
|
||||
status.sstat_fragmentation_point = asoc->frag_point;
|
||||
status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
|
||||
memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
|
||||
|
@@ -35,33 +35,60 @@
|
||||
#include <net/sctp/sctp.h>
|
||||
#include <net/sctp/sm.h>
|
||||
|
||||
struct sctp_stream *sctp_stream_new(__u16 incnt, __u16 outcnt, gfp_t gfp)
|
||||
int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp)
|
||||
{
|
||||
struct sctp_stream *stream;
|
||||
int i;
|
||||
|
||||
stream = kzalloc(sizeof(*stream), gfp);
|
||||
if (!stream)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
stream->outcnt = outcnt;
|
||||
stream->outcnt = asoc->c.sinit_num_ostreams;
|
||||
stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp);
|
||||
if (!stream->out) {
|
||||
kfree(stream);
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i = 0; i < stream->outcnt; i++)
|
||||
stream->out[i].state = SCTP_STREAM_OPEN;
|
||||
|
||||
stream->incnt = incnt;
|
||||
asoc->stream = stream;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp)
|
||||
{
|
||||
struct sctp_stream *stream = asoc->stream;
|
||||
int i;
|
||||
|
||||
/* Initial stream->out size may be very big, so free it and alloc
|
||||
* a new one with new outcnt to save memory.
|
||||
*/
|
||||
kfree(stream->out);
|
||||
stream->outcnt = asoc->c.sinit_num_ostreams;
|
||||
stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp);
|
||||
if (!stream->out)
|
||||
goto nomem;
|
||||
|
||||
for (i = 0; i < stream->outcnt; i++)
|
||||
stream->out[i].state = SCTP_STREAM_OPEN;
|
||||
|
||||
stream->incnt = asoc->c.sinit_max_instreams;
|
||||
stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp);
|
||||
if (!stream->in) {
|
||||
kfree(stream->out);
|
||||
kfree(stream);
|
||||
return NULL;
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
return stream;
|
||||
return 0;
|
||||
|
||||
nomem:
|
||||
asoc->stream = NULL;
|
||||
kfree(stream);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void sctp_stream_free(struct sctp_stream *stream)
|
||||
|
@@ -251,14 +251,13 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
|
||||
transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
|
||||
}
|
||||
|
||||
void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 pmtu)
|
||||
void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
|
||||
{
|
||||
struct dst_entry *dst;
|
||||
struct dst_entry *dst = sctp_transport_dst_check(t);
|
||||
|
||||
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
|
||||
pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n",
|
||||
__func__, pmtu,
|
||||
SCTP_DEFAULT_MINSEGMENT);
|
||||
__func__, pmtu, SCTP_DEFAULT_MINSEGMENT);
|
||||
/* Use default minimum segment size and disable
|
||||
* pmtu discovery on this transport.
|
||||
*/
|
||||
@@ -267,17 +266,13 @@ void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 p
|
||||
t->pathmtu = pmtu;
|
||||
}
|
||||
|
||||
dst = sctp_transport_dst_check(t);
|
||||
if (!dst)
|
||||
t->af_specific->get_dst(t, &t->saddr, &t->fl, sk);
|
||||
|
||||
if (dst) {
|
||||
dst->ops->update_pmtu(dst, sk, NULL, pmtu);
|
||||
|
||||
dst->ops->update_pmtu(dst, t->asoc->base.sk, NULL, pmtu);
|
||||
dst = sctp_transport_dst_check(t);
|
||||
if (!dst)
|
||||
t->af_specific->get_dst(t, &t->saddr, &t->fl, sk);
|
||||
}
|
||||
|
||||
if (!dst)
|
||||
t->af_specific->get_dst(t, &t->saddr, &t->fl, t->asoc->base.sk);
|
||||
}
|
||||
|
||||
/* Caches the dst entry and source address for a transport's destination
|
||||
|
新增問題並參考
封鎖使用者