Commit 0ee13079 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [PKTGEN]: Remove write-only variable.
  [NETFILTER]: xt_tcpudp: fix wrong struct in udp_checkentry
  [NET_SCHED] sch_prio.c: remove duplicate call of tc_classify()
  [BRIDGE]: Fix OOPS when bridging device without ethtool.
  [BRIDGE]: Packets leaking out of disabled/blocked ports.
  [TCP]: Allow minimum RTO to be configurable via routing metrics.
  SCTP: Fix to handle invalid parameter length correctly
  SCTP: Abort on COOKIE-ECHO if backlog is exceeded.
  SCTP: Correctly disable listening when backlog is 0.
  SCTP: Do not retransmit chunks that are newer then rtt.
  SCTP: Uncomfirmed transports can't become Inactive
  SCTP: Pick the correct port when binding to 0.
  SCTP: Use net_ratelimit to suppress error messages print too fast
  SCTP: Fix to encode PROTOCOL VIOLATION error cause correctly
  SCTP: Fix sctp_addto_chunk() to add pad with correct length
  SCTP: Assign stream sequence numbers to the entire message
  SCTP: properly clean up fragment and ordering queues during FWD-TSN.
  [PKTGEN]: Fix multiqueue oops.
  [BNX2]: Add write posting comment.
  [BNX2]: Use msleep().
parents 2d8348b4 88282c6e
......@@ -3934,11 +3934,13 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
/* Chip reset. */
REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
/* Reading back any register after chip reset will hang the
* bus on 5706 A0 and A1. The msleep below provides plenty
* of margin for write posting.
*/
if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
(CHIP_ID(bp) == CHIP_ID_5706_A1)) {
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ / 50);
}
(CHIP_ID(bp) == CHIP_ID_5706_A1))
msleep(20);
/* Reset takes approximate 30 usec */
for (i = 0; i < 10; i++) {
......
......@@ -351,6 +351,8 @@ enum
#define RTAX_INITCWND RTAX_INITCWND
RTAX_FEATURES,
#define RTAX_FEATURES RTAX_FEATURES
RTAX_RTO_MIN,
#define RTAX_RTO_MIN RTAX_RTO_MIN
__RTAX_MAX
};
......
......@@ -214,7 +214,7 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
const struct sctp_chunk *);
struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *,
const struct sctp_chunk *);
void sctp_init_cause(struct sctp_chunk *, __be16 cause, const void *, size_t);
void sctp_init_cause(struct sctp_chunk *, __be16 cause, size_t);
struct sctp_chunk *sctp_make_abort(const struct sctp_association *,
const struct sctp_chunk *,
const size_t hint);
......
......@@ -726,6 +726,7 @@ int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
struct iovec *data);
void sctp_chunk_free(struct sctp_chunk *);
void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
void *sctp_addto_param(struct sctp_chunk *, int len, const void *data);
struct sctp_chunk *sctp_chunkify(struct sk_buff *,
const struct sctp_association *,
struct sock *);
......
......@@ -83,6 +83,7 @@ int sctp_clear_pd(struct sock *sk, struct sctp_association *asoc);
/* Skip over an SSN. */
void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn);
void sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *, __u32);
#endif /* __sctp_ulpqueue_h__ */
......
......@@ -384,6 +384,11 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
if (hold_time(br) == 0)
return;
/* ignore packets unless we are using this port */
if (!(source->state == BR_STATE_LEARNING ||
source->state == BR_STATE_FORWARDING))
return;
fdb = fdb_find(head, addr);
if (likely(fdb)) {
/* attempt to update an entry for a local interface */
......
......@@ -33,17 +33,17 @@
*/
static int port_cost(struct net_device *dev)
{
if (dev->ethtool_ops->get_settings) {
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
int err = dev->ethtool_ops->get_settings(dev, &ecmd);
if (!err) {
if (dev->ethtool_ops && dev->ethtool_ops->get_settings) {
struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, };
if (!dev->ethtool_ops->get_settings(dev, &ecmd)) {
switch(ecmd.speed) {
case SPEED_100:
return 19;
case SPEED_1000:
return 4;
case SPEED_10000:
return 2;
case SPEED_1000:
return 4;
case SPEED_100:
return 19;
case SPEED_10:
return 100;
}
......
......@@ -101,9 +101,8 @@ static int br_handle_local_finish(struct sk_buff *skb)
{
struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
if (p && p->state != BR_STATE_DISABLED)
if (p)
br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
return 0; /* process further */
}
......
......@@ -380,7 +380,6 @@ struct pktgen_thread {
/* Field for thread to receive "posted" events terminate, stop ifs etc. */
u32 control;
int pid;
int cpu;
wait_queue_head_t queue;
......@@ -3331,8 +3330,9 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
}
if ((netif_queue_stopped(odev) ||
netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) ||
need_resched()) {
(pkt_dev->skb &&
netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping))) ||
need_resched()) {
idle_start = getCurUs();
if (!netif_running(odev)) {
......@@ -3462,8 +3462,6 @@ static int pktgen_thread_worker(void *arg)
init_waitqueue_head(&t->queue);
t->pid = current->pid;
pr_debug("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid);
max_before_softirq = t->max_before_softirq;
......
......@@ -555,6 +555,16 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)
tcp_grow_window(sk, skb);
}
static u32 tcp_rto_min(struct sock *sk)
{
struct dst_entry *dst = __sk_dst_get(sk);
u32 rto_min = TCP_RTO_MIN;
if (dst_metric_locked(dst, RTAX_RTO_MIN))
rto_min = dst->metrics[RTAX_RTO_MIN-1];
return rto_min;
}
/* Called to compute a smoothed rtt estimate. The data fed to this
* routine either comes from timestamps, or from segments that were
* known _not_ to have been retransmitted [see Karn/Partridge
......@@ -616,13 +626,13 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
if (tp->mdev_max < tp->rttvar)
tp->rttvar -= (tp->rttvar-tp->mdev_max)>>2;
tp->rtt_seq = tp->snd_nxt;
tp->mdev_max = TCP_RTO_MIN;
tp->mdev_max = tcp_rto_min(sk);
}
} else {
/* no previous measure. */
tp->srtt = m<<3; /* take the measured time to be rtt */
tp->mdev = m<<1; /* make sure rto = 3*rtt */
tp->mdev_max = tp->rttvar = max(tp->mdev, TCP_RTO_MIN);
tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));
tp->rtt_seq = tp->snd_nxt;
}
}
......
......@@ -188,7 +188,7 @@ udp_checkentry(const char *tablename,
void *matchinfo,
unsigned int hook_mask)
{
const struct xt_tcp *udpinfo = matchinfo;
const struct xt_udp *udpinfo = matchinfo;
/* Must specify no unknown invflags */
return !(udpinfo->invflags & ~XT_UDP_INV_MASK);
......
......@@ -44,7 +44,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
if (TC_H_MAJ(skb->priority) != sch->handle) {
err = tc_classify(skb, q->filter_list, &res);
#ifdef CONFIG_NET_CLS_ACT
switch (tc_classify(skb, q->filter_list, &res)) {
switch (err) {
case TC_ACT_STOLEN:
case TC_ACT_QUEUED:
*qerr = NET_XMIT_SUCCESS;
......
......@@ -727,7 +727,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
break;
case SCTP_TRANSPORT_DOWN:
transport->state = SCTP_INACTIVE;
/* if the transort was never confirmed, do not transition it
* to inactive state.
*/
if (transport->state != SCTP_UNCONFIRMED)
transport->state = SCTP_INACTIVE;
spc_state = SCTP_ADDR_UNREACHABLE;
break;
......
......@@ -421,6 +421,13 @@ void sctp_retransmit_mark(struct sctp_outq *q,
*/
if ((fast_retransmit && (chunk->fast_retransmit > 0)) ||
(!fast_retransmit && !chunk->tsn_gap_acked)) {
/* If this chunk was sent less then 1 rto ago, do not
* retransmit this chunk, but give the peer time
* to acknowlege it.
*/
if ((jiffies - chunk->sent_at) < transport->rto)
continue;
/* RFC 2960 6.2.1 Processing a Received SACK
*
* C) Any time a DATA chunk is marked for
......
......@@ -110,7 +110,7 @@ static const struct sctp_paramhdr prsctp_param = {
* abort chunk.
*/
void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
const void *payload, size_t paylen)
size_t paylen)
{
sctp_errhdr_t err;
__u16 len;
......@@ -120,7 +120,6 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
len = sizeof(sctp_errhdr_t) + paylen;
err.length = htons(len);
chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
sctp_addto_chunk(chunk, paylen, payload);
}
/* 3.3.2 Initiation (INIT) (1)
......@@ -780,8 +779,8 @@ struct sctp_chunk *sctp_make_abort_no_data(
/* Put the tsn back into network byte order. */
payload = htonl(tsn);
sctp_init_cause(retval, SCTP_ERROR_NO_DATA, (const void *)&payload,
sizeof(payload));
sctp_init_cause(retval, SCTP_ERROR_NO_DATA, sizeof(payload));
sctp_addto_chunk(retval, sizeof(payload), (const void *)&payload);
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
*
......@@ -823,7 +822,8 @@ struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc,
goto err_copy;
}
sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, payload, paylen);
sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, paylen);
sctp_addto_chunk(retval, paylen, payload);
if (paylen)
kfree(payload);
......@@ -850,15 +850,17 @@ struct sctp_chunk *sctp_make_abort_violation(
struct sctp_paramhdr phdr;
retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen
+ sizeof(sctp_chunkhdr_t));
+ sizeof(sctp_paramhdr_t));
if (!retval)
goto end;
sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen);
sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen
+ sizeof(sctp_paramhdr_t));
phdr.type = htons(chunk->chunk_hdr->type);
phdr.length = chunk->chunk_hdr->length;
sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr);
sctp_addto_chunk(retval, paylen, payload);
sctp_addto_param(retval, sizeof(sctp_paramhdr_t), &phdr);
end:
return retval;
......@@ -955,7 +957,8 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
if (!retval)
goto nodata;
sctp_init_cause(retval, cause_code, payload, paylen);
sctp_init_cause(retval, cause_code, paylen);
sctp_addto_chunk(retval, paylen, payload);
nodata:
return retval;
......@@ -1128,7 +1131,7 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
void *target;
void *padding;
int chunklen = ntohs(chunk->chunk_hdr->length);
int padlen = chunklen % 4;
int padlen = WORD_ROUND(chunklen) - chunklen;
padding = skb_put(chunk->skb, padlen);
target = skb_put(chunk->skb, len);
......@@ -1143,6 +1146,25 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
return target;
}
/* Append bytes to the end of a parameter. Will panic if chunk is not big
* enough.
*/
void *sctp_addto_param(struct sctp_chunk *chunk, int len, const void *data)
{
void *target;
int chunklen = ntohs(chunk->chunk_hdr->length);
target = skb_put(chunk->skb, len);
memcpy(target, data, len);
/* Adjust the chunk length field. */
chunk->chunk_hdr->length = htons(chunklen + len);
chunk->chunk_end = skb_tail_pointer(chunk->skb);
return target;
}
/* Append bytes from user space to the end of a chunk. Will panic if
* chunk is not big enough.
* Returns a kernel err value.
......@@ -1174,25 +1196,36 @@ int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
*/
void sctp_chunk_assign_ssn(struct sctp_chunk *chunk)
{
struct sctp_datamsg *msg;
struct sctp_chunk *lchunk;
struct sctp_stream *stream;
__u16 ssn;
__u16 sid;
if (chunk->has_ssn)
return;
/* This is the last possible instant to assign a SSN. */
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
ssn = 0;
} else {
sid = ntohs(chunk->subh.data_hdr->stream);
if (chunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)
ssn = sctp_ssn_next(&chunk->asoc->ssnmap->out, sid);
else
ssn = sctp_ssn_peek(&chunk->asoc->ssnmap->out, sid);
}
/* All fragments will be on the same stream */
sid = ntohs(chunk->subh.data_hdr->stream);
stream = &chunk->asoc->ssnmap->out;
chunk->subh.data_hdr->ssn = htons(ssn);
chunk->has_ssn = 1;
/* Now assign the sequence number to the entire message.
* All fragments must have the same stream sequence number.
*/
msg = chunk->msg;
list_for_each_entry(lchunk, &msg->chunks, frag_list) {
if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
ssn = 0;
} else {
if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)
ssn = sctp_ssn_next(stream, sid);
else
ssn = sctp_ssn_peek(stream, sid);
}
lchunk->subh.data_hdr->ssn = htons(ssn);
lchunk->has_ssn = 1;
}
}
/* Helper function to assign a TSN if needed. This assumes that both
......@@ -1466,7 +1499,8 @@ struct sctp_association *sctp_unpack_cookie(
__be32 n = htonl(usecs);
sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE,
&n, sizeof(n));
sizeof(n));
sctp_addto_chunk(*errp, sizeof(n), &n);
*error = -SCTP_IERROR_STALE_COOKIE;
} else
*error = -SCTP_IERROR_NOMEM;
......@@ -1556,7 +1590,8 @@ static int sctp_process_missing_param(const struct sctp_association *asoc,
report.num_missing = htonl(1);
report.type = paramtype;
sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM,
&report, sizeof(report));
sizeof(report));
sctp_addto_chunk(*errp, sizeof(report), &report);
}
/* Stop processing this chunk. */
......@@ -1574,7 +1609,7 @@ static int sctp_process_inv_mandatory(const struct sctp_association *asoc,
*errp = sctp_make_op_error_space(asoc, chunk, 0);
if (*errp)
sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0);
sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0);
/* Stop processing this chunk. */
return 0;
......@@ -1595,9 +1630,10 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
*errp = sctp_make_op_error_space(asoc, chunk, payload_len);
if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error,
sizeof(error));
sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param);
sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
sizeof(error) + sizeof(sctp_paramhdr_t));
sctp_addto_chunk(*errp, sizeof(error), error);
sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param);
}
return 0;
......@@ -1618,9 +1654,10 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
if (!*errp)
*errp = sctp_make_op_error_space(asoc, chunk, len);
if (*errp)
sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED,
param.v, len);
if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len);
sctp_addto_chunk(*errp, len, param.v);
}
/* Stop processing this chunk. */
return 0;
......@@ -1672,10 +1709,13 @@ static int sctp_process_unk_param(const struct sctp_association *asoc,
*errp = sctp_make_op_error_space(asoc, chunk,
ntohs(chunk->chunk_hdr->length));
if (*errp)
if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
param.v,
WORD_ROUND(ntohs(param.p->length)));
sctp_addto_chunk(*errp,
WORD_ROUND(ntohs(param.p->length)),
param.v);
}
break;
case SCTP_PARAM_ACTION_SKIP:
......@@ -1690,8 +1730,10 @@ static int sctp_process_unk_param(const struct sctp_association *asoc,
if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
param.v,
WORD_ROUND(ntohs(param.p->length)));
sctp_addto_chunk(*errp,
WORD_ROUND(ntohs(param.p->length)),
param.v);
} else {
/* If there is no memory for generating the ERROR
* report as specified, an ABORT will be triggered
......@@ -1791,7 +1833,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
* VIOLATION error. We build the ERROR chunk here and let the normal
* error handling code build and send the packet.
*/
if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) {
if (param.v != (void*)chunk->chunk_end) {
sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
return 0;
}
......
......@@ -1013,8 +1013,9 @@ static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
break;
case SCTP_DISPOSITION_VIOLATION:
printk(KERN_ERR "sctp protocol violation state %d "
"chunkid %d\n", state, subtype.chunk);
if (net_ratelimit())
printk(KERN_ERR "sctp protocol violation state %d "
"chunkid %d\n", state, subtype.chunk);
break;
case SCTP_DISPOSITION_NOT_IMPL:
......@@ -1130,6 +1131,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
/* Move the Cumulattive TSN Ack ahead. */
sctp_tsnmap_skip(&asoc->peer.tsn_map, cmd->obj.u32);
/* purge the fragmentation queue */
sctp_ulpq_reasm_flushtsn(&asoc->ulpq, cmd->obj.u32);
/* Abort any in progress partial delivery. */
sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
break;
......
......@@ -264,7 +264,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
struct sctp_chunk *err_chunk;
struct sctp_packet *packet;
sctp_unrecognized_param_t *unk_param;
struct sock *sk;
int len;
/* 6.10 Bundling
......@@ -285,16 +284,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
sk = ep->base.sk;
/* If the endpoint is not listening or if the number of associations
* on the TCP-style socket exceed the max backlog, respond with an
* ABORT.
*/
if (!sctp_sstate(sk, LISTENING) ||
(sctp_style(sk, TCP) &&
sk_acceptq_is_full(sk)))
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
* Tag.
*/
......@@ -590,6 +579,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
struct sctp_ulpevent *ev, *ai_ev = NULL;
int error = 0;
struct sctp_chunk *err_chk_p;
struct sock *sk;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
......@@ -605,6 +595,15 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* If the endpoint is not listening or if the number of associations
* on the TCP-style socket exceed the max backlog, respond with an
* ABORT.
*/
sk = ep->base.sk;
if (!sctp_sstate(sk, LISTENING) ||
(sctp_style(sk, TCP) && sk_acceptq_is_full(sk)))
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
/* "Decode" the chunk. We have no optional parameters so we
* are in good shape.
*/
......@@ -1032,19 +1031,21 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
/* This should never happen, but lets log it if so. */
if (unlikely(!link)) {
if (from_addr.sa.sa_family == AF_INET6) {
printk(KERN_WARNING
"%s association %p could not find address "
NIP6_FMT "\n",
__FUNCTION__,
asoc,
NIP6(from_addr.v6.sin6_addr));
if (net_ratelimit())
printk(KERN_WARNING
"%s association %p could not find address "
NIP6_FMT "\n",
__FUNCTION__,
asoc,
NIP6(from_addr.v6.sin6_addr));
} else {
printk(KERN_WARNING
"%s association %p could not find address "
NIPQUAD_FMT "\n",
__FUNCTION__,
asoc,
NIPQUAD(from_addr.v4.sin_addr.s_addr));
if (net_ratelimit())
printk(KERN_WARNING
"%s association %p could not find address "
NIPQUAD_FMT "\n",
__FUNCTION__,
asoc,
NIPQUAD(from_addr.v4.sin_addr.s_addr));
}
return SCTP_DISPOSITION_DISCARD;
}
......@@ -3362,7 +3363,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
abort = sctp_make_abort(asoc, asconf_ack,
sizeof(sctp_errhdr_t));
if (abort) {
sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, NULL, 0);
sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, 0);
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(abort));
}
......@@ -3392,7 +3393,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
abort = sctp_make_abort(asoc, asconf_ack,
sizeof(sctp_errhdr_t));
if (abort) {
sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, NULL, 0);
sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0);
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(abort));
}
......
......@@ -353,6 +353,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
* The function sctp_get_port_local() does duplicate address
* detection.
*/
addr->v4.sin_port = htons(snum);
if ((ret = sctp_get_port_local(sk, addr))) {
if (ret == (long) sk) {
/* This endpoint has a conflicting address. */
......@@ -5202,6 +5203,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
sctp_unhash_endpoint(ep);
sk->sk_state = SCTP_SS_CLOSED;
return 0;
}
/* Return if we are already listening. */
......@@ -5249,6 +5251,7 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
sctp_unhash_endpoint(ep);
sk->sk_state = SCTP_SS_CLOSED;
return 0;
}
if (sctp_sstate(sk, LISTENING))
......
......@@ -659,6 +659,46 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *u
return retval;
}
/*
* Flush out stale fragments from the reassembly queue when processing
* a Forward TSN.
*
* RFC 3758, Section 3.6
*
* After receiving and processing a FORWARD TSN, the data receiver MUST
* take cautions in updating its re-assembly queue. The receiver MUST
* remove any partially reassembled message, which is still missing one
* or more TSNs earlier than or equal to the new cumulative TSN point.
* In the event that the receiver has invoked the partial delivery API,
* a notification SHOULD also be generated to inform the upper layer API
* that the message being partially delivered will NOT be completed.
*/
void sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 fwd_tsn)
{
struct sk_buff *pos, *tmp;
struct sctp_ulpevent *event;
__u32 tsn;
if (skb_queue_empty(&ulpq->reasm))
return;
skb_queue_walk_safe(&ulpq->reasm, pos, tmp) {
event = sctp_skb2event(pos);
tsn = event->tsn;
/* Since the entire message must be abandoned by the
* sender (item A3 in Section 3.5, RFC 3758), we can
* free all fragments on the list that are less then
* or equal to ctsn_point
*/
if (TSN_lte(tsn, fwd_tsn)) {
__skb_unlink(pos, &ulpq->reasm);
sctp_ulpevent_free(event);
} else
break;
}
}
/* Helper function to gather skbs that have possibly become
* ordered by an an incoming chunk.
*/
......@@ -794,7 +834,7 @@ static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
/* Helper function to gather skbs that have possibly become
* ordered by forward tsn skipping their dependencies.
*/
static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq)
static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
{
struct sk_buff *pos, *tmp;
struct sctp_ulpevent *cevent;
......@@ -813,31 +853,40 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq)
csid = cevent->stream;
cssn = cevent->ssn;
if (cssn != sctp_ssn_peek(in, csid))
/* Have we gone too far? */
if (csid > sid)
break;
/* Found it, so mark in the ssnmap. */
sctp_ssn_next(in, csid);
/* Have we not gone far enough? */
if (csid < sid)
continue;
/* see if this ssn has been marked by skipping */
if (!SSN_lt(cssn, sctp_ssn_peek(in, csid)))
break;
__skb_unlink(pos, &ulpq->lobby);
if (!event) {
if (!event)
/* Create a temporary list to collect chunks on. */
event = sctp_skb2event(pos);
__skb_queue_tail(&temp, sctp_event2skb(event));
} else {
/* Attach all gathered skbs to the event. */
__skb_queue_tail(&temp, pos);
}
/* Attach all gathered skbs to the event. */
__skb_queue_tail(&temp, pos);
}
/* Send event to the ULP. 'event' is the sctp_ulpevent for
* very first SKB on the 'temp' list.
*/
if (event)
if (event) {
/* see if we have more ordered that we can deliver */
sctp_ulpq_retrieve_ordered(ulpq, event);
sctp_ulpq_tail_event(ulpq, event);
}
}
/* Skip over an SSN. */
/* Skip over an SSN. This is used during the processing of
* Forwared TSN chunk to skip over the abandoned ordered data
*/
void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn)
{
struct sctp_stream *in;
......@@ -855,7 +904,7 @@ void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn)
/* Go find any other chunks that were waiting for
* ordering and deliver them if needed.
*/
sctp_ulpq_reap_ordered(ulpq);
sctp_ulpq_reap_ordered(ulpq, sid);
return;
}
......
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