aboutsummaryrefslogtreecommitdiff
path: root/net/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/associola.c76
-rw-r--r--net/sctp/bind_addr.c15
-rw-r--r--net/sctp/chunk.c23
-rw-r--r--net/sctp/command.c10
-rw-r--r--net/sctp/input.c3
-rw-r--r--net/sctp/ipv6.c31
-rw-r--r--net/sctp/objcnt.c9
-rw-r--r--net/sctp/output.c16
-rw-r--r--net/sctp/outqueue.c187
-rw-r--r--net/sctp/proc.c27
-rw-r--r--net/sctp/protocol.c80
-rw-r--r--net/sctp/sm_make_chunk.c57
-rw-r--r--net/sctp/sm_sideeffect.c32
-rw-r--r--net/sctp/sm_statefuns.c61
-rw-r--r--net/sctp/socket.c90
-rw-r--r--net/sctp/transport.c60
-rw-r--r--net/sctp/ulpevent.c2
17 files changed, 424 insertions, 355 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index d29f792e052..024c3ebd966 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -474,6 +474,15 @@ static void sctp_association_destroy(struct sctp_association *asoc)
void sctp_assoc_set_primary(struct sctp_association *asoc,
struct sctp_transport *transport)
{
+ int changeover = 0;
+
+ /* it's a changeover only if we already have a primary path
+ * that we are changing
+ */
+ if (asoc->peer.primary_path != NULL &&
+ asoc->peer.primary_path != transport)
+ changeover = 1 ;
+
asoc->peer.primary_path = transport;
/* Set a default msg_name for events. */
@@ -499,12 +508,12 @@ void sctp_assoc_set_primary(struct sctp_association *asoc,
* double switch to the same destination address.
*/
if (transport->cacc.changeover_active)
- transport->cacc.cycling_changeover = 1;
+ transport->cacc.cycling_changeover = changeover;
/* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that
* a changeover has occurred.
*/
- transport->cacc.changeover_active = 1;
+ transport->cacc.changeover_active = changeover;
/* 3) The sender MUST store the next TSN to be sent in
* next_tsn_at_change.
@@ -718,12 +727,11 @@ struct sctp_transport *sctp_assoc_lookup_paddr(
const union sctp_addr *address)
{
struct sctp_transport *t;
- struct list_head *pos;
/* Cycle through all transports searching for a peer address. */
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- t = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(t, &asoc->peer.transport_addr_list,
+ transports) {
if (sctp_cmp_addr_exact(address, &t->ipaddr))
return t;
}
@@ -762,7 +770,6 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
struct sctp_transport *second;
struct sctp_ulpevent *event;
struct sockaddr_storage addr;
- struct list_head *pos;
int spc_state = 0;
/* Record the transition on the transport. */
@@ -814,8 +821,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
*/
first = NULL; second = NULL;
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- t = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(t, &asoc->peer.transport_addr_list,
+ transports) {
if ((t->state == SCTP_INACTIVE) ||
(t->state == SCTP_UNCONFIRMED))
@@ -932,7 +939,6 @@ struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc,
{
struct sctp_transport *active;
struct sctp_transport *match;
- struct list_head *entry, *pos;
struct sctp_transport *transport;
struct sctp_chunk *chunk;
__be32 key = htonl(tsn);
@@ -956,8 +962,8 @@ struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc,
active = asoc->peer.active_path;
- list_for_each(entry, &active->transmitted) {
- chunk = list_entry(entry, struct sctp_chunk, transmitted_list);
+ list_for_each_entry(chunk, &active->transmitted,
+ transmitted_list) {
if (key == chunk->subh.data_hdr->tsn) {
match = active;
@@ -966,14 +972,13 @@ struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc,
}
/* If not found, go search all the other transports. */
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- transport = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+ transports) {
if (transport == active)
break;
- list_for_each(entry, &transport->transmitted) {
- chunk = list_entry(entry, struct sctp_chunk,
- transmitted_list);
+ list_for_each_entry(chunk, &transport->transmitted,
+ transmitted_list) {
if (key == chunk->subh.data_hdr->tsn) {
match = transport;
goto out;
@@ -1154,9 +1159,8 @@ void sctp_assoc_update(struct sctp_association *asoc,
} else {
/* Add any peer addresses from the new association. */
- list_for_each(pos, &new->peer.transport_addr_list) {
- trans = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(trans, &new->peer.transport_addr_list,
+ transports) {
if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr))
sctp_assoc_add_peer(asoc, &trans->ipaddr,
GFP_ATOMIC, trans->state);
@@ -1208,6 +1212,9 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
struct list_head *head = &asoc->peer.transport_addr_list;
struct list_head *pos;
+ if (asoc->peer.transport_count == 1)
+ return;
+
/* Find the next transport in a round-robin fashion. */
t = asoc->peer.retran_path;
pos = &t->transports;
@@ -1222,6 +1229,15 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
t = list_entry(pos, struct sctp_transport, transports);
+ /* We have exhausted the list, but didn't find any
+ * other active transports. If so, use the next
+ * transport.
+ */
+ if (t == asoc->peer.retran_path) {
+ t = next;
+ break;
+ }
+
/* Try to find an active transport. */
if ((t->state == SCTP_ACTIVE) ||
@@ -1234,15 +1250,6 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
if (!next)
next = t;
}
-
- /* We have exhausted the list, but didn't find any
- * other active transports. If so, use the next
- * transport.
- */
- if (t == asoc->peer.retran_path) {
- t = next;
- break;
- }
}
asoc->peer.retran_path = t;
@@ -1306,15 +1313,14 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(
void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
{
struct sctp_transport *t;
- struct list_head *pos;
__u32 pmtu = 0;
if (!asoc)
return;
/* Get the lowest pmtu of all the transports. */
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- t = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(t, &asoc->peer.transport_addr_list,
+ transports) {
if (t->pmtu_pending && t->dst) {
sctp_transport_update_pmtu(t, dst_mtu(t->dst));
t->pmtu_pending = 0;
@@ -1330,7 +1336,7 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
}
SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
- __FUNCTION__, asoc, asoc->pathmtu, asoc->frag_point);
+ __func__, asoc, asoc->pathmtu, asoc->frag_point);
}
/* Should we send a SACK to update our peer? */
@@ -1370,7 +1376,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
}
SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) "
- "- %u\n", __FUNCTION__, asoc, len, asoc->rwnd,
+ "- %u\n", __func__, asoc, len, asoc->rwnd,
asoc->rwnd_over, asoc->a_rwnd);
/* Send a window update SACK if the rwnd has increased by at least the
@@ -1381,7 +1387,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
if (sctp_peer_needs_update(asoc)) {
asoc->a_rwnd = asoc->rwnd;
SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p "
- "rwnd: %u a_rwnd: %u\n", __FUNCTION__,
+ "rwnd: %u a_rwnd: %u\n", __func__,
asoc, asoc->rwnd, asoc->a_rwnd);
sack = sctp_make_sack(asoc);
if (!sack)
@@ -1410,7 +1416,7 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len)
asoc->rwnd = 0;
}
SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n",
- __FUNCTION__, asoc, len, asoc->rwnd,
+ __func__, asoc, len, asoc->rwnd,
asoc->rwnd_over);
}
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index ceefda025e2..80e6df06967 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -67,15 +67,13 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
int flags)
{
struct sctp_sockaddr_entry *addr;
- struct list_head *pos;
int error = 0;
/* All addresses share the same port. */
dest->port = src->port;
/* Extract the addresses which are relevant for this scope. */
- list_for_each(pos, &src->address_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ list_for_each_entry(addr, &src->address_list, list) {
error = sctp_copy_one_addr(dest, &addr->a, scope,
gfp, flags);
if (error < 0)
@@ -87,9 +85,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
* the assumption that we must be sitting behind a NAT.
*/
if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) {
- list_for_each(pos, &src->address_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry,
- list);
+ list_for_each_entry(addr, &src->address_list, list) {
error = sctp_copy_one_addr(dest, &addr->a,
SCTP_SCOPE_LINK, gfp,
flags);
@@ -115,14 +111,12 @@ int sctp_bind_addr_dup(struct sctp_bind_addr *dest,
gfp_t gfp)
{
struct sctp_sockaddr_entry *addr;
- struct list_head *pos;
int error = 0;
/* All addresses share the same port. */
dest->port = src->port;
- list_for_each(pos, &src->address_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ list_for_each_entry(addr, &src->address_list, list) {
error = sctp_add_bind_addr(dest, &addr->a, 1, gfp);
if (error < 0)
break;
@@ -273,8 +267,7 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
addrparms = retval;
- list_for_each(pos, &bp->address_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ list_for_each_entry(addr, &bp->address_list, list) {
af = sctp_get_af_specific(addr->a.v4.sin_family);
len = af->to_addr_param(&addr->a, &rawaddr);
memcpy(addrparms.v, &rawaddr, len);
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 4d3128f5ccc..1748ef90950 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -66,9 +66,10 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp)
{
struct sctp_datamsg *msg;
msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
- if (msg)
+ if (msg) {
sctp_datamsg_init(msg);
- SCTP_DBG_OBJCNT_INC(datamsg);
+ SCTP_DBG_OBJCNT_INC(datamsg);
+ }
return msg;
}
@@ -136,20 +137,6 @@ void sctp_datamsg_put(struct sctp_datamsg *msg)
sctp_datamsg_destroy(msg);
}
-/* Free a message. Really just give up a reference, the
- * really free happens in sctp_datamsg_destroy().
- */
-void sctp_datamsg_free(struct sctp_datamsg *msg)
-{
- sctp_datamsg_put(msg);
-}
-
-/* Hold on to all the fragments until all chunks have been sent. */
-void sctp_datamsg_track(struct sctp_chunk *chunk)
-{
- sctp_chunk_hold(chunk);
-}
-
/* Assign a chunk to this datamsg. */
static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
{
@@ -189,7 +176,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
msecs_to_jiffies(sinfo->sinfo_timetolive);
msg->can_abandon = 1;
SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
- __FUNCTION__, msg, msg->expires_at, jiffies);
+ __func__, msg, msg->expires_at, jiffies);
}
max = asoc->frag_point;
@@ -295,7 +282,7 @@ errout:
chunk = list_entry(pos, struct sctp_chunk, frag_list);
sctp_chunk_free(chunk);
}
- sctp_datamsg_free(msg);
+ sctp_datamsg_put(msg);
return NULL;
}
diff --git a/net/sctp/command.c b/net/sctp/command.c
index bb977330002..c0044019db9 100644
--- a/net/sctp/command.c
+++ b/net/sctp/command.c
@@ -52,18 +52,12 @@ int sctp_init_cmd_seq(sctp_cmd_seq_t *seq)
/* Add a command to a sctp_cmd_seq_t.
* Return 0 if the command sequence is full.
*/
-int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj)
+void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj)
{
- if (seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS)
- goto fail;
+ BUG_ON(seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS);
seq->cmds[seq->next_free_slot].verb = verb;
seq->cmds[seq->next_free_slot++].obj = obj;
-
- return 1;
-
-fail:
- return 0;
}
/* Return the next command structure in a sctp_cmd_seq.
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 812ff1756c3..ca6b022b1df 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -409,7 +409,7 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
struct sctp_association *asoc,
struct sctp_transport *t)
{
- SCTP_DEBUG_PRINTK("%s\n", __FUNCTION__);
+ SCTP_DEBUG_PRINTK("%s\n", __func__);
sctp_do_sm(SCTP_EVENT_T_OTHER,
SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
@@ -725,7 +725,6 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l
}
ep = sctp_sk((sctp_get_ctl_sock()))->ep;
- epb = &ep->base;
hit:
sctp_endpoint_hold(ep);
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index b1e05d719f9..a2f4d4d5159 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -110,8 +110,9 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
spin_lock_bh(&sctp_local_addr_lock);
list_for_each_entry_safe(addr, temp,
&sctp_local_addr_list, list) {
- if (ipv6_addr_equal(&addr->a.v6.sin6_addr,
- &ifa->addr)) {
+ if (addr->a.sa.sa_family == AF_INET6 &&
+ ipv6_addr_equal(&addr->a.v6.sin6_addr,
+ &ifa->addr)) {
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
@@ -225,7 +226,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
"src:" NIP6_FMT " dst:" NIP6_FMT "\n",
- __FUNCTION__, skb, skb->len,
+ __func__, skb, skb->len,
NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
@@ -250,7 +251,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
- __FUNCTION__, NIP6(fl.fl6_dst));
+ __func__, NIP6(fl.fl6_dst));
if (saddr) {
ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
@@ -259,7 +260,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
NIP6(fl.fl6_src));
}
- dst = ip6_route_output(NULL, &fl);
+ dst = ip6_route_output(&init_net, NULL, &fl);
if (!dst->error) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
@@ -298,7 +299,8 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
/* Fills in the source address(saddr) based on the destination address(daddr)
* and asoc's bind address list.
*/
-static void sctp_v6_get_saddr(struct sctp_association *asoc,
+static void sctp_v6_get_saddr(struct sctp_sock *sk,
+ struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
@@ -312,10 +314,13 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
"daddr:" NIP6_FMT " ",
- __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
+ __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
if (!asoc) {
- ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
+ ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+ &daddr->v6.sin6_addr,
+ inet6_sk(&sk->inet.sk)->srcprefs,
+ &saddr->v6.sin6_addr);
SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
NIP6(saddr->v6.sin6_addr));
return;
@@ -350,7 +355,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
} else {
printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
"address for the dest:" NIP6_FMT "\n",
- __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
+ __func__, asoc, NIP6(daddr->v6.sin6_addr));
}
rcu_read_unlock();
@@ -633,7 +638,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
struct sctp6_sock *newsctp6sk;
- newsk = sk_alloc(sk->sk_net, PF_INET6, GFP_KERNEL, sk->sk_prot);
+ newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot);
if (!newsk)
goto out;
@@ -722,6 +727,11 @@ static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
}
+static void sctp_v6_ecn_capable(struct sock *sk)
+{
+ inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
+}
+
/* Initialize a PF_INET6 socket msg_name. */
static void sctp_inet6_msgname(char *msgname, int *addr_len)
{
@@ -992,6 +1002,7 @@ static struct sctp_af sctp_af_inet6 = {
.skb_iif = sctp_v6_skb_iif,
.is_ce = sctp_v6_is_ce,
.seq_dump_addr = sctp_v6_seq_dump_addr,
+ .ecn_capable = sctp_v6_ecn_capable,
.net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6),
#ifdef CONFIG_COMPAT
diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c
index cfeb07ea1b0..f73ec0ea93b 100644
--- a/net/sctp/objcnt.c
+++ b/net/sctp/objcnt.c
@@ -83,13 +83,12 @@ static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
*/
static int sctp_objcnt_seq_show(struct seq_file *seq, void *v)
{
- int i;
- char temp[128];
+ int i, len;
i = (int)*(loff_t *)v;
- sprintf(temp, "%s: %d", sctp_dbg_objcnt[i].label,
- atomic_read(sctp_dbg_objcnt[i].counter));
- seq_printf(seq, "%-127s\n", temp);
+ seq_printf(seq, "%s: %d%n", sctp_dbg_objcnt[i].label,
+ atomic_read(sctp_dbg_objcnt[i].counter), &len);
+ seq_printf(seq, "%*s\n", 127 - len, "");
return 0;
}
diff --git a/net/sctp/output.c b/net/sctp/output.c
index aa700feea76..6d45bae93b4 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -74,7 +74,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
{
struct sctp_chunk *chunk = NULL;
- SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __FUNCTION__,
+ SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__,
packet, vtag);
packet->vtag = vtag;
@@ -106,7 +106,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
struct sctp_association *asoc = transport->asoc;
size_t overhead;
- SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __FUNCTION__,
+ SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __func__,
packet, transport);
packet->transport = transport;
@@ -138,7 +138,7 @@ void sctp_packet_free(struct sctp_packet *packet)
{
struct sctp_chunk *chunk, *tmp;
- SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
+ SCTP_DEBUG_PRINTK("%s: packet:%p\n", __func__, packet);
list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
list_del_init(&chunk->list);
@@ -162,7 +162,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
sctp_xmit_t retval;
int error = 0;
- SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__,
+ SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__,
packet, chunk);
switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) {
@@ -264,7 +264,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
size_t pmtu;
int too_big;
- SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet,
+ SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet,
chunk);
/* Try to bundle AUTH chunk */
@@ -372,7 +372,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
unsigned char *auth = NULL; /* pointer to auth in skb data */
__u32 cksum_buf_len = sizeof(struct sctphdr);
- SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
+ SCTP_DEBUG_PRINTK("%s: packet:%p\n", __func__, packet);
/* Do NOT generate a chunkless packet. */
if (list_empty(&packet->chunk_list))
@@ -548,7 +548,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* Note: The works for IPv6 layer checks this bit too later
* in transmission. See IP6_ECN_flow_xmit().
*/
- INET_ECN_xmit(nskb->sk);
+ (*tp->af_specific->ecn_capable)(nskb->sk);
/* Set up the IP options. */
/* BUG: not implemented
@@ -677,7 +677,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
"transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, "
"pba: %d\n",
- __FUNCTION__, transport,
+ __func__, transport,
transport->cwnd,
transport->ssthresh,
transport->flight_size,
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 1bb3c5c35d2..ace6770e904 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -208,6 +208,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
INIT_LIST_HEAD(&q->sacked);
INIT_LIST_HEAD(&q->abandoned);
+ q->fast_rtx = 0;
q->outstanding_bytes = 0;
q->empty = 1;
q->cork = 0;
@@ -221,12 +222,12 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
void sctp_outq_teardown(struct sctp_outq *q)
{
struct sctp_transport *transport;
- struct list_head *lchunk, *pos, *temp;
+ struct list_head *lchunk, *temp;
struct sctp_chunk *chunk, *tmp;
/* Throw away unacknowledged chunks. */
- list_for_each(pos, &q->asoc->peer.transport_addr_list) {
- transport = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(transport, &q->asoc->peer.transport_addr_list,
+ transports) {
while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) {
chunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list);
@@ -469,7 +470,7 @@ void sctp_retransmit_mark(struct sctp_outq *q,
SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, "
"cwnd: %d, ssthresh: %d, flight_size: %d, "
- "pba: %d\n", __FUNCTION__,
+ "pba: %d\n", __func__,
transport, reason,
transport->cwnd, transport->ssthresh,
transport->flight_size,
@@ -494,16 +495,20 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
*/
if (transport == transport->asoc->peer.retran_path)
sctp_assoc_update_retran_path(transport->asoc);
+ transport->asoc->rtx_data_chunks +=
+ transport->asoc->unack_data;
break;
case SCTP_RTXR_FAST_RTX:
SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
+ q->fast_rtx = 1;
break;
case SCTP_RTXR_PMTUD:
SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
break;
case SCTP_RTXR_T1_RTX:
SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS);
+ transport->asoc->init_retries++;
break;
default:
BUG();
@@ -515,9 +520,15 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
* the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by
* following the procedures outlined in C1 - C5.
*/
- sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point);
+ if (reason == SCTP_RTXR_T3_RTX)
+ sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point);
- error = sctp_outq_flush(q, /* rtx_timeout */ 1);
+ /* Flush the queues only on timeout, since fast_rtx is only
+ * triggered during sack processing and the queue
+ * will be flushed at the end.
+ */
+ if (reason != SCTP_RTXR_FAST_RTX)
+ error = sctp_outq_flush(q, /* rtx_timeout */ 1);
if (error)
q->asoc->base.sk->sk_err = -error;
@@ -535,17 +546,23 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
int rtx_timeout, int *start_timer)
{
struct list_head *lqueue;
- struct list_head *lchunk, *lchunk1;
struct sctp_transport *transport = pkt->transport;
sctp_xmit_t status;
struct sctp_chunk *chunk, *chunk1;
struct sctp_association *asoc;
+ int fast_rtx;
int error = 0;
+ int timer = 0;
+ int done = 0;
asoc = q->asoc;
lqueue = &q->retransmit;
+ fast_rtx = q->fast_rtx;
- /* RFC 2960 6.3.3 Handle T3-rtx Expiration
+ /* This loop handles time-out retransmissions, fast retransmissions,
+ * and retransmissions due to opening of whindow.
+ *
+ * RFC 2960 6.3.3 Handle T3-rtx Expiration
*
* E3) Determine how many of the earliest (i.e., lowest TSN)
* outstanding DATA chunks for the address for which the
@@ -560,12 +577,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
* [Just to be painfully clear, if we are retransmitting
* because a timeout just happened, we should send only ONE
* packet of retransmitted data.]
+ *
+ * For fast retransmissions we also send only ONE packet. However,
+ * if we are just flushing the queue due to open window, we'll
+ * try to send as much as possible.
*/
- lchunk = sctp_list_dequeue(lqueue);
-
- while (lchunk) {
- chunk = list_entry(lchunk, struct sctp_chunk,
- transmitted_list);
+ list_for_each_entry_safe(chunk, chunk1, lqueue, transmitted_list) {
/* Make sure that Gap Acked TSNs are not retransmitted. A
* simple approach is just to move such TSNs out of the
@@ -573,58 +590,60 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
* next chunk.
*/
if (chunk->tsn_gap_acked) {
- list_add_tail(lchunk, &transport->transmitted);
- lchunk = sctp_list_dequeue(lqueue);
+ list_del(&chunk->transmitted_list);
+ list_add_tail(&chunk->transmitted_list,
+ &transport->transmitted);
continue;
}
+ /* If we are doing fast retransmit, ignore non-fast_rtransmit
+ * chunks
+ */
+ if (fast_rtx && !chunk->fast_retransmit)
+ continue;
+
/* Attempt to append this chunk to the packet. */
status = sctp_packet_append_chunk(pkt, chunk);
switch (status) {
case SCTP_XMIT_PMTU_FULL:
/* Send this packet. */
- if ((error = sctp_packet_transmit(pkt)) == 0)
- *start_timer = 1;
+ error = sctp_packet_transmit(pkt);
/* If we are retransmitting, we should only
* send a single packet.
*/
- if (rtx_timeout) {
- list_add(lchunk, lqueue);
- lchunk = NULL;
- }
+ if (rtx_timeout || fast_rtx)
+ done = 1;
- /* Bundle lchunk in the next round. */
+ /* Bundle next chunk in the next round. */
break;
case SCTP_XMIT_RWND_FULL:
/* Send this packet. */
- if ((error = sctp_packet_transmit(pkt)) == 0)
- *start_timer = 1;
+ error = sctp_packet_transmit(pkt);
/* Stop sending DATA as there is no more room
* at the receiver.
*/
- list_add(lchunk, lqueue);
- lchunk = NULL;
+ done = 1;
break;
case SCTP_XMIT_NAGLE_DELAY:
/* Send this packet. */
- if ((error = sctp_packet_transmit(pkt)) == 0)
- *start_timer = 1;
+ error = sctp_packet_transmit(pkt);
/* Stop sending DATA because of nagle delay. */
- list_add(lchunk, lqueue);
- lchunk = NULL;
+ done = 1;
break;
default:
/* The append was successful, so add this chunk to
* the transmitted list.
*/
- list_add_tail(lchunk, &transport->transmitted);
+ list_del(&chunk->transmitted_list);
+ list_add_tail(&chunk->transmitted_list,
+ &transport->transmitted);
/* Mark the chunk as ineligible for fast retransmit
* after it is retransmitted.
@@ -632,29 +651,44 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
if (chunk->fast_retransmit > 0)
chunk->fast_retransmit = -1;
- *start_timer = 1;
- q->empty = 0;
+ /* Force start T3-rtx timer when fast retransmitting
+ * the earliest outstanding TSN
+ */
+ if (!timer && fast_rtx &&
+ ntohl(chunk->subh.data_hdr->tsn) ==
+ asoc->ctsn_ack_point + 1)
+ timer = 2;
- /* Retrieve a new chunk to bundle. */
- lchunk = sctp_list_dequeue(lqueue);
+ q->empty = 0;
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);
- if (chunk1->fast_retransmit > 0)
- chunk1->fast_retransmit = -1;
- }
+ /* Set the timer if there were no errors */
+ if (!error && !timer)
+ timer = 1;
+
+ if (done)
+ 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 || fast_rtx) {
+ list_for_each_entry(chunk1, lqueue, transmitted_list) {
+ if (chunk1->fast_retransmit > 0)
+ chunk1->fast_retransmit = -1;
}
}
+ *start_timer = timer;
+
+ /* Clear fast retransmit hint */
+ if (fast_rtx)
+ q->fast_rtx = 0;
+
return error;
}
@@ -793,6 +827,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
break;
case SCTP_CID_ABORT:
+ if (sctp_test_T_bit(chunk)) {
+ packet->vtag = asoc->c.my_vtag;
+ }
case SCTP_CID_SACK:
case SCTP_CID_HEARTBEAT:
case SCTP_CID_HEARTBEAT_ACK:
@@ -858,7 +895,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
rtx_timeout, &start_timer);
if (start_timer)
- sctp_transport_reset_timers(transport);
+ sctp_transport_reset_timers(transport,
+ start_timer-1);
/* This can happen on COOKIE-ECHO resend. Only
* one chunk can get bundled with a COOKIE-ECHO.
@@ -973,7 +1011,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
list_add_tail(&chunk->transmitted_list,
&transport->transmitted);
- sctp_transport_reset_timers(transport);
+ sctp_transport_reset_timers(transport, start_timer-1);
q->empty = 0;
@@ -1034,7 +1072,6 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc,
static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,
struct sctp_association *asoc)
{
- struct list_head *ltransport, *lchunk;
struct sctp_transport *transport;
struct sctp_chunk *chunk;
__u32 highest_new_tsn, tsn;
@@ -1042,12 +1079,9 @@ static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,
highest_new_tsn = ntohl(sack->cum_tsn_ack);
- list_for_each(ltransport, transport_list) {
- transport = list_entry(ltransport, struct sctp_transport,
- transports);
- list_for_each(lchunk, &transport->transmitted) {
- chunk = list_entry(lchunk, struct sctp_chunk,
- transmitted_list);
+ list_for_each_entry(transport, transport_list, transports) {
+ list_for_each_entry(chunk, &transport->transmitted,
+ transmitted_list) {
tsn = ntohl(chunk->subh.data_hdr->tsn);
if (!chunk->tsn_gap_acked &&
@@ -1070,7 +1104,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
struct sctp_association *asoc = q->asoc;
struct sctp_transport *transport;
struct sctp_chunk *tchunk = NULL;
- struct list_head *lchunk, *transport_list, *pos, *temp;
+ struct list_head *lchunk, *transport_list, *temp;
sctp_sack_variable_t *frags = sack->variable;
__u32 sack_ctsn, ctsn, tsn;
__u32 highest_tsn, highest_new_tsn;
@@ -1096,9 +1130,8 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
*/
if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) {
primary->cacc.changeover_active = 0;
- list_for_each(pos, transport_list) {
- transport = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(transport, transport_list,
+ transports) {
transport->cacc.cycling_changeover = 0;
}
}
@@ -1113,9 +1146,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
*/
if (sack->num_gap_ack_blocks &&
primary->cacc.changeover_active) {
- list_for_each(pos, transport_list) {
- transport = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(transport, transport_list, transports) {
transport->cacc.cacc_saw_newack = 0;
}
}
@@ -1144,9 +1175,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
*
* This is a MASSIVE candidate for optimization.
*/
- list_for_each(pos, transport_list) {
- transport = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(transport, transport_list, transports) {
sctp_check_transmitted(q, &transport->transmitted,
transport, sack, highest_new_tsn);
/*
@@ -1158,9 +1187,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
count_of_newacks ++;
}
- list_for_each(pos, transport_list) {
- transport = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(transport, transport_list, transports) {
sctp_mark_missing(q, &transport->transmitted, transport,
highest_new_tsn, count_of_newacks);
}
@@ -1203,10 +1230,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
sctp_generate_fwdtsn(q, sack_ctsn);
SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",
- __FUNCTION__, sack_ctsn);
+ __func__, sack_ctsn);
SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, "
"%p is 0x%x. Adv peer ack point: 0x%x\n",
- __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point);
+ __func__, asoc, ctsn, asoc->adv_peer_ack_point);
/* See if all chunks are acked.
* Make sure the empty queue handler will get run later.
@@ -1217,9 +1244,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
if (!q->empty)
goto finish;
- list_for_each(pos, transport_list) {
- transport = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(transport, transport_list, transports) {
q->empty = q->empty && list_empty(&transport->transmitted);
if (!q->empty)
goto finish;
@@ -1441,7 +1466,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
if (tchunk->tsn_gap_acked) {
SCTP_DEBUG_PRINTK("%s: Receiver reneged on "
"data TSN: 0x%x\n",
- __FUNCTION__,
+ __func__,
tsn);
tchunk->tsn_gap_acked = 0;
@@ -1541,6 +1566,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
bytes_acked);
transport->flight_size -= bytes_acked;
+ if (transport->flight_size == 0)
+ transport->partial_bytes_acked = 0;
q->outstanding_bytes -= bytes_acked;
} else {
/* RFC 2960 6.1, sctpimpguide-06 2.15.2
@@ -1558,7 +1585,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
(sack_ctsn+2 == q->asoc->next_tsn)) {
SCTP_DEBUG_PRINTK("%s: SACK received for zero "
"window probe: %u\n",
- __FUNCTION__, sack_ctsn);
+ __func__, sack_ctsn);
q->asoc->overall_error_count = 0;
transport->error_count = 0;
}
@@ -1593,14 +1620,12 @@ static void sctp_mark_missing(struct sctp_outq *q,
int count_of_newacks)
{
struct sctp_chunk *chunk;
- struct list_head *pos;
__u32 tsn;
char do_fast_retransmit = 0;
struct sctp_transport *primary = q->asoc->peer.primary_path;
- list_for_each(pos, transmitted_queue) {
+ list_for_each_entry(chunk, transmitted_queue, transmitted_list) {
- chunk = list_entry(pos, struct sctp_chunk, transmitted_list);
tsn = ntohl(chunk->subh.data_hdr->tsn);
/* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all
@@ -1623,7 +1648,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
SCTP_DEBUG_PRINTK(
"%s: TSN 0x%x missing counter: %d\n",
- __FUNCTION__, tsn,
+ __func__, tsn,
chunk->tsn_missing_report);
}
}
@@ -1646,7 +1671,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d\n",
- __FUNCTION__, transport, transport->cwnd,
+ __func__, transport, transport->cwnd,
transport->ssthresh, transport->flight_size,
transport->partial_bytes_acked);
}
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 973f1dbc2ec..0aba759cb9b 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -124,7 +124,6 @@ void sctp_snmp_proc_exit(void)
/* Dump local addresses of an association/endpoint. */
static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
{
- struct list_head *pos;
struct sctp_association *asoc;
struct sctp_sockaddr_entry *laddr;
struct sctp_transport *peer;
@@ -137,8 +136,7 @@ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_commo
primary = &peer->saddr;
}
- list_for_each(pos, &epb->bind_addr.address_list) {
- laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ list_for_each_entry(laddr, &epb->bind_addr.address_list, list) {
addr = &laddr->a;
af = sctp_get_af_specific(addr->sa.sa_family);
if (primary && af->cmp_addr(addr, primary)) {
@@ -151,14 +149,13 @@ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_commo
/* Dump remote addresses of an association. */
static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc)
{
- struct list_head *pos;
struct sctp_transport *transport;
union sctp_addr *addr, *primary;
struct sctp_af *af;
primary = &assoc->peer.primary_addr;
- list_for_each(pos, &assoc->peer.transport_addr_list) {
- transport = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(transport, &assoc->peer.transport_addr_list,
+ transports) {
addr = &transport->ipaddr;
af = sctp_get_af_specific(addr->sa.sa_family);
if (af->cmp_addr(addr, primary)) {
@@ -279,8 +276,10 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
*pos = 0;
if (*pos == 0)
- seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
- "RPORT LADDRS <-> RADDRS\n");
+ seq_printf(seq, " ASSOC SOCK STY SST ST HBKT "
+ "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
+ "RPORT LADDRS <-> RADDRS "
+ "HBINT INS OUTS MAXRT T1X T2X RTXC\n");
return (void *)pos;
}
@@ -319,19 +318,25 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
assoc = sctp_assoc(epb);
sk = epb->sk;
seq_printf(seq,
- "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
+ "%8p %8p %-3d %-3d %-2d %-4d "
+ "%4d %8d %8d %7d %5lu %-5d %5d ",
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
- assoc->state, hash, assoc->assoc_id,
+ assoc->state, hash,
+ assoc->assoc_id,
assoc->sndbuf_used,
atomic_read(&assoc->rmem_alloc),
sock_i_uid(sk), sock_i_ino(sk),
epb->bind_addr.port,
assoc->peer.port);
-
seq_printf(seq, " ");
sctp_seq_dump_local_addrs(seq, epb);
seq_printf(seq, "<-> ");
sctp_seq_dump_remote_addrs(seq, assoc);
+ seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d ",
+ assoc->hbinterval, assoc->c.sinit_max_instreams,
+ assoc->c.sinit_num_ostreams, assoc->max_retrans,
+ assoc->init_retries, assoc->shutdown_retries,
+ assoc->rtx_data_chunks);
seq_printf(seq, "\n");
}
read_unlock(&head->lock);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index f90091a1b9c..9258dfe784a 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -74,7 +74,7 @@ DEFINE_SPINLOCK(sctp_assocs_id_lock);
* the Out-of-the-blue (OOTB) packets. A control sock will be created
* for this socket at the initialization time.
*/
-static struct socket *sctp_ctl_socket;
+static struct sock *sctp_ctl_sock;
static struct sctp_pf *sctp_pf_inet6_specific;
static struct sctp_pf *sctp_pf_inet_specific;
@@ -91,7 +91,7 @@ int sysctl_sctp_wmem[3];
/* Return the address of the control sock. */
struct sock *sctp_get_ctl_sock(void)
{
- return sctp_ctl_socket->sk;
+ return sctp_ctl_sock;
}
/* Set up the proc fs entry for the SCTP protocol. */
@@ -108,14 +108,23 @@ static __init int sctp_proc_init(void)
}
if (sctp_snmp_proc_init())
- goto out_nomem;
+ goto out_snmp_proc_init;
if (sctp_eps_proc_init())
- goto out_nomem;
+ goto out_eps_proc_init;
if (sctp_assocs_proc_init())
- goto out_nomem;
+ goto out_assocs_proc_init;
return 0;
+out_assocs_proc_init:
+ sctp_eps_proc_exit();
+out_eps_proc_init:
+ sctp_snmp_proc_exit();
+out_snmp_proc_init:
+ if (proc_net_sctp) {
+ proc_net_sctp = NULL;
+ remove_proc_entry("sctp", init_net.proc_net);
+ }
out_nomem:
return -ENOMEM;
}
@@ -363,7 +372,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr,
return 0;
/* Is this a broadcast address? */
- if (skb && ((struct rtable *)skb->dst)->rt_flags & RTCF_BROADCAST)
+ if (skb && skb->rtable->rt_flags & RTCF_BROADCAST)
return 0;
return 1;
@@ -451,7 +460,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
fl.fl4_src = saddr->v4.sin_addr.s_addr;
SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ",
- __FUNCTION__, NIPQUAD(fl.fl4_dst),
+ __func__, NIPQUAD(fl.fl4_dst),
NIPQUAD(fl.fl4_src));
if (!ip_route_output_key(&init_net, &rt, &fl)) {
@@ -470,11 +479,11 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
+ sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
continue;
- sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
goto out_unlock;
}
@@ -519,7 +528,8 @@ out:
/* For v4, the source address is cached in the route entry(dst). So no need
* to cache it separately and hence this is an empty routine.
*/
-static void sctp_v4_get_saddr(struct sctp_association *asoc,
+static void sctp_v4_get_saddr(struct sctp_sock *sk,
+ struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
@@ -539,7 +549,7 @@ static void sctp_v4_get_saddr(struct sctp_association *asoc,
/* What interface did this skb arrive on? */
static int sctp_v4_skb_iif(const struct sk_buff *skb)
{
- return ((struct rtable *)skb->dst)->rt_iif;
+ return skb->rtable->rt_iif;
}
/* Was this packet marked by Explicit Congestion Notification? */
@@ -554,7 +564,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
{
struct inet_sock *inet = inet_sk(sk);
struct inet_sock *newinet;
- struct sock *newsk = sk_alloc(sk->sk_net, PF_INET, GFP_KERNEL,
+ struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL,
sk->sk_prot);
if (!newsk)
@@ -616,6 +626,11 @@ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
}
+static void sctp_v4_ecn_capable(struct sock *sk)
+{
+ INET_ECN_xmit(sk);
+}
+
/* Event handler for inet address addition/deletion events.
* The sctp_local_addr_list needs to be protocted by a spin lock since
* multiple notifiers (say IPv4 and IPv6) may be running at the same
@@ -630,6 +645,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
struct sctp_sockaddr_entry *temp;
int found = 0;
+ if (dev_net(ifa->ifa_dev->dev) != &init_net)
+ return NOTIFY_DONE;
+
switch (ev) {
case NETDEV_UP:
addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
@@ -647,7 +665,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
spin_lock_bh(&sctp_local_addr_lock);
list_for_each_entry_safe(addr, temp,
&sctp_local_addr_list, list) {
- if (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) {
+ if (addr->a.sa.sa_family == AF_INET &&
+ addr->a.v4.sin_addr.s_addr ==
+ ifa->ifa_local) {
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
@@ -677,16 +697,13 @@ static int sctp_ctl_sock_init(void)
else
family = PF_INET;
- err = sock_create_kern(family, SOCK_SEQPACKET, IPPROTO_SCTP,
- &sctp_ctl_socket);
+ err = inet_ctl_sock_create(&sctp_ctl_sock, family,
+ SOCK_SEQPACKET, IPPROTO_SCTP, &init_net);
if (err < 0) {
printk(KERN_ERR
"SCTP: Failed to create the SCTP control socket.\n");
return err;
}
- sctp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
- inet_sk(sctp_ctl_socket->sk)->uc_ttl = -1;
-
return 0;
}
@@ -826,9 +843,9 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
{
SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
"src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n",
- __FUNCTION__, skb, skb->len,
- NIPQUAD(((struct rtable *)skb->dst)->rt_src),
- NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
+ __func__, skb, skb->len,
+ NIPQUAD(skb->rtable->rt_src),
+ NIPQUAD(skb->rtable->rt_dst));
SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
return ip_queue_xmit(skb, ipfragok);
@@ -932,6 +949,7 @@ static struct sctp_af sctp_af_inet = {
.skb_iif = sctp_v4_skb_iif,
.is_ce = sctp_v4_is_ce,
.seq_dump_addr = sctp_v4_seq_dump_addr,
+ .ecn_capable = sctp_v4_ecn_capable,
.net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in),
#ifdef CONFIG_COMPAT
@@ -972,24 +990,14 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family)
return 1;
}
-static int __init init_sctp_mibs(void)
+static inline int init_sctp_mibs(void)
{
- sctp_statistics[0] = alloc_percpu(struct sctp_mib);
- if (!sctp_statistics[0])
- return -ENOMEM;
- sctp_statistics[1] = alloc_percpu(struct sctp_mib);
- if (!sctp_statistics[1]) {
- free_percpu(sctp_statistics[0]);
- return -ENOMEM;
- }
- return 0;
-
+ return snmp_mib_init((void**)sctp_statistics, sizeof(struct sctp_mib));
}
-static void cleanup_sctp_mibs(void)
+static inline void cleanup_sctp_mibs(void)
{
- free_percpu(sctp_statistics[0]);
- free_percpu(sctp_statistics[1]);
+ snmp_mib_free((void**)sctp_statistics);
}
static void sctp_v4_pf_init(void)
@@ -1284,7 +1292,7 @@ err_v6_add_protocol:
sctp_v6_del_protocol();
err_add_protocol:
sctp_v4_del_protocol();
- sock_release(sctp_ctl_socket);
+ inet_ctl_sock_destroy(sctp_ctl_sock);
err_ctl_sock_init:
sctp_v6_protosw_exit();
err_v6_protosw_init:
@@ -1328,7 +1336,7 @@ SCTP_STATIC __exit void sctp_exit(void)
sctp_v4_del_protocol();
/* Free the control endpoint. */
- sock_release(sctp_ctl_socket);
+ inet_ctl_sock_destroy(sctp_ctl_sock);
/* Free protosw registrations */
sctp_v6_protosw_exit();
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 578630e8e00..bbc7107c86c 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1782,7 +1782,7 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
struct sctp_chunk **errp)
{
- char error[] = "The following parameter had invalid length:";
+ static const char error[] = "The following parameter had invalid length:";
size_t payload_len = WORD_ROUND(sizeof(error)) +
sizeof(sctp_paramhdr_t);
@@ -1982,7 +1982,10 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
struct sctp_chunk *chunk,
struct sctp_chunk **err_chunk)
{
+ struct sctp_hmac_algo_param *hmacs;
int retval = SCTP_IERROR_NO_ERROR;
+ __u16 n_elt, id = 0;
+ int i;
/* FIXME - This routine is not looking at each parameter per the
* chunk type, i.e., unrecognized parameters should be further
@@ -2056,9 +2059,29 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
break;
case SCTP_PARAM_HMAC_ALGO:
- if (sctp_auth_enable)
- break;
- /* Fall Through */
+ if (!sctp_auth_enable)
+ goto fallthrough;
+
+ hmacs = (struct sctp_hmac_algo_param *)param.p;
+ n_elt = (ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) >> 1;
+
+ /* SCTP-AUTH: Section 6.1
+ * The HMAC algorithm based on SHA-1 MUST be supported and
+ * included in the HMAC-ALGO parameter.
+ */
+ for (i = 0; i < n_elt; i++) {
+ id = ntohs(hmacs->hmac_ids[i]);
+
+ if (id == SCTP_AUTH_HMAC_ID_SHA1)
+ break;
+ }
+
+ if (id != SCTP_AUTH_HMAC_ID_SHA1) {
+ sctp_process_inv_paramlength(asoc, param.p, chunk,
+ err_chunk);
+ retval = SCTP_IERROR_ABORT;
+ }
+ break;
fallthrough:
default:
SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
@@ -2246,8 +2269,8 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
* high (for example, implementations MAY use the size of the receiver
* advertised window).
*/
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- transport = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+ transports) {
transport->ssthresh = asoc->peer.i.a_rwnd;
}
@@ -2395,7 +2418,8 @@ static int sctp_process_param(struct sctp_association *asoc,
break;
case SCTP_PARAM_IPV6_ADDRESS:
- asoc->peer.ipv6_address = 1;
+ if (PF_INET6 == asoc->base.sk->sk_family)
+ asoc->peer.ipv6_address = 1;
break;
case SCTP_PARAM_HOST_NAME_ADDRESS:
@@ -2806,6 +2830,19 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
addr_param = (union sctp_addr_param *)
((void *)asconf_param + sizeof(sctp_addip_param_t));
+ switch (addr_param->v4.param_hdr.type) {
+ case SCTP_PARAM_IPV6_ADDRESS:
+ if (!asoc->peer.ipv6_address)
+ return SCTP_ERROR_INV_PARAM;
+ break;
+ case SCTP_PARAM_IPV4_ADDRESS:
+ if (!asoc->peer.ipv4_address)
+ return SCTP_ERROR_INV_PARAM;
+ break;
+ default:
+ return SCTP_ERROR_INV_PARAM;
+ }
+
af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
if (unlikely(!af))
return SCTP_ERROR_INV_PARAM;
@@ -3043,7 +3080,6 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
union sctp_addr addr;
struct sctp_bind_addr *bp = &asoc->base.bind_addr;
union sctp_addr_param *addr_param;
- struct list_head *pos;
struct sctp_transport *transport;
struct sctp_sockaddr_entry *saddr;
int retval = 0;
@@ -3071,9 +3107,8 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
local_bh_disable();
retval = sctp_del_bind_addr(bp, &addr);
local_bh_enable();
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- transport = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+ transports) {
dst_release(transport->dst);
sctp_transport_route(transport, NULL,
sctp_sk(asoc->base.sk));
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 28eb38eb608..23a9f1a95b7 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -243,7 +243,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
sctp_bh_lock_sock(asoc->base.sk);
if (sock_owned_by_user(asoc->base.sk)) {
- SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
+ SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
/* Try again later. */
if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20)))
@@ -283,7 +283,7 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc,
sctp_bh_lock_sock(asoc->base.sk);
if (sock_owned_by_user(asoc->base.sk)) {
SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n",
- __FUNCTION__,
+ __func__,
timeout_type);
/* Try again later. */
@@ -361,7 +361,7 @@ void sctp_generate_heartbeat_event(unsigned long data)
sctp_bh_lock_sock(asoc->base.sk);
if (sock_owned_by_user(asoc->base.sk)) {
- SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
+ SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
/* Try again later. */
if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20)))
@@ -545,14 +545,12 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc)
{
struct sctp_transport *t;
- struct list_head *pos;
/* Start a heartbeat timer for each transport on the association.
* hold a reference on the transport to make sure none of
* the needed data structures go away.
*/
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- t = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))
sctp_transport_hold(t);
@@ -563,12 +561,11 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc)
{
struct sctp_transport *t;
- struct list_head *pos;
/* Stop all heartbeat timers. */
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- t = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(t, &asoc->peer.transport_addr_list,
+ transports) {
if (del_timer(&t->hb_timer))
sctp_transport_put(t);
}
@@ -579,10 +576,9 @@ 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);
+ list_for_each_entry(t, &asoc->peer.transport_addr_list,
+ transports) {
if (timer_pending(&t->T3_rtx_timer) &&
del_timer(&t->T3_rtx_timer)) {
sctp_transport_put(t);
@@ -593,7 +589,6 @@ static void sctp_cmd_t3_rtx_timers_stop(sctp_cmd_seq_t *cmds,
/* Helper function to update the heartbeat timer. */
static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
- struct sctp_association *asoc,
struct sctp_transport *t)
{
/* Update the heartbeat timer. */
@@ -1065,7 +1060,6 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
struct sctp_chunk *new_obj;
struct sctp_chunk *chunk = NULL;
struct sctp_packet *packet;
- struct list_head *pos;
struct timer_list *timer;
unsigned long timeout;
struct sctp_transport *t;
@@ -1397,9 +1391,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
/* If we've sent any data bundled with
* COOKIE-ECHO we need to resend.
*/
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- t = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(t, &asoc->peer.transport_addr_list,
+ transports) {
sctp_retransmit_mark(&asoc->outqueue, t,
SCTP_RTXR_T1_RTX);
}
@@ -1457,7 +1450,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_HB_TIMER_UPDATE:
t = cmd->obj.transport;
- sctp_cmd_hb_timer_update(commands, asoc, t);
+ sctp_cmd_hb_timer_update(commands, t);
break;
case SCTP_CMD_HB_TIMERS_STOP:
@@ -1536,6 +1529,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
error = sctp_auth_asoc_init_active_key(asoc,
GFP_ATOMIC);
break;
+ case SCTP_CMD_UPDATE_INITTAG:
+ asoc->peer.i.init_tag = cmd->obj.u32;
+ break;
default:
printk(KERN_WARNING "Impossible command: %u, %p\n",
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index f2ed6473fee..0c9d5a6950f 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1124,7 +1124,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
printk(KERN_WARNING
"%s association %p could not find address "
NIP6_FMT "\n",
- __FUNCTION__,
+ __func__,
asoc,
NIP6(from_addr.v6.sin6_addr));
} else {
@@ -1132,7 +1132,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
printk(KERN_WARNING
"%s association %p could not find address "
NIPQUAD_FMT "\n",
- __FUNCTION__,
+ __func__,
asoc,
NIPQUAD(from_addr.v4.sin_addr.s_addr));
}
@@ -1150,7 +1150,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
time_after(jiffies, hbinfo->sent_at + max_interval)) {
SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp "
"received for transport: %p\n",
- __FUNCTION__, link);
+ __func__, link);
return SCTP_DISPOSITION_DISCARD;
}
@@ -1226,7 +1226,6 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
sctp_cmd_seq_t *commands)
{
struct sctp_transport *new_addr, *addr;
- struct list_head *pos, *pos2;
int found;
/* Implementor's Guide - Sectin 5.2.2
@@ -1243,12 +1242,11 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
new_addr = NULL;
found = 0;
- list_for_each(pos, &new_asoc->peer.transport_addr_list) {
- new_addr = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(new_addr, &new_asoc->peer.transport_addr_list,
+ transports) {
found = 0;
- list_for_each(pos2, &asoc->peer.transport_addr_list) {
- addr = list_entry(pos2, struct sctp_transport,
- transports);
+ list_for_each_entry(addr, &asoc->peer.transport_addr_list,
+ transports) {
if (sctp_cmp_addr_exact(&new_addr->ipaddr,
&addr->ipaddr)) {
found = 1;
@@ -3135,12 +3133,8 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
if (!ev)
goto nomem;
- if (!sctp_add_cmd(commands, SCTP_CMD_EVENT_ULP,
- SCTP_ULPEVENT(ev))) {
- sctp_ulpevent_free(ev);
- goto nomem;
- }
-
+ sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+ SCTP_ULPEVENT(ev));
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
SCTP_CHUNK(chunk));
}
@@ -3668,7 +3662,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
skb_pull(chunk->skb, len);
tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
- SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+ SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn);
/* The TSN is too high--silently discard the chunk and count on it
* getting retransmitted later.
@@ -3728,7 +3722,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
skb_pull(chunk->skb, len);
tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
- SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+ SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn);
/* The TSN is too high--silently discard the chunk and count on it
* getting retransmitted later.
@@ -4144,6 +4138,24 @@ static sctp_disposition_t sctp_sf_abort_violation(
goto nomem;
if (asoc) {
+ /* Treat INIT-ACK as a special case during COOKIE-WAIT. */
+ if (chunk->chunk_hdr->type == SCTP_CID_INIT_ACK &&
+ !asoc->peer.i.init_tag) {
+ sctp_initack_chunk_t *initack;
+
+ initack = (sctp_initack_chunk_t *)chunk->chunk_hdr;
+ if (!sctp_chunk_length_valid(chunk,
+ sizeof(sctp_initack_chunk_t)))
+ abort->chunk_hdr->flags |= SCTP_CHUNK_FLAG_T;
+ else {
+ unsigned int inittag;
+
+ inittag = ntohl(initack->init_hdr.init_tag);
+ sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_INITTAG,
+ SCTP_U32(inittag));
+ }
+ }
+
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
@@ -4219,7 +4231,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
void *arg,
sctp_cmd_seq_t *commands)
{
- char err_str[]="The following chunk had invalid length:";
+ static const char err_str[]="The following chunk had invalid length:";
return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
sizeof(err_str));
@@ -4236,7 +4248,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands) {
- char err_str[] = "The following parameter had invalid length:";
+ static const char err_str[] = "The following parameter had invalid length:";
return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
sizeof(err_str));
@@ -4255,7 +4267,7 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
void *arg,
sctp_cmd_seq_t *commands)
{
- char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
+ static const char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
sizeof(err_str));
@@ -4274,7 +4286,7 @@ static sctp_disposition_t sctp_sf_violation_chunk(
void *arg,
sctp_cmd_seq_t *commands)
{
- char err_str[]="The following chunk violates protocol:";
+ static const char err_str[]="The following chunk violates protocol:";
if (!asoc)
return sctp_sf_violation(ep, asoc, type, arg, commands);
@@ -4349,6 +4361,7 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *repl;
+ struct sctp_association* my_asoc;
/* The comment below says that we enter COOKIE-WAIT AFTER
* sending the INIT, but that doesn't actually work in our
@@ -4372,8 +4385,8 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep,
/* Cast away the const modifier, as we want to just
* rerun it through as a sideffect.
*/
- sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC,
- SCTP_ASOC((struct sctp_association *) asoc));
+ my_asoc = (struct sctp_association *)asoc;
+ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(my_asoc));
/* Choose transport for INIT. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_CHOOSE_TRANSPORT,
@@ -5312,6 +5325,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS);
+ ((struct sctp_association *)asoc)->shutdown_retries++;
+
if (asoc->overall_error_count >= asoc->max_retrans) {
sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
SCTP_ERROR(ETIMEDOUT));
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index d994d822900..0dbcde6758e 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -513,7 +513,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
union sctp_addr saveaddr;
void *addr_buf;
struct sctp_af *af;
- struct list_head *pos;
struct list_head *p;
int i;
int retval = 0;
@@ -525,10 +524,9 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
ep = sp->ep;
SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
- __FUNCTION__, sk, addrs, addrcnt);
+ __func__, sk, addrs, addrcnt);
- list_for_each(pos, &ep->asocs) {
- asoc = list_entry(pos, struct sctp_association, asocs);
+ list_for_each_entry(asoc, &ep->asocs, asocs) {
if (!asoc->peer.asconf_capable)
continue;
@@ -699,7 +697,6 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
union sctp_addr *laddr;
void *addr_buf;
struct sctp_af *af;
- struct list_head *pos, *pos1;
struct sctp_sockaddr_entry *saddr;
int i;
int retval = 0;
@@ -711,10 +708,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
ep = sp->ep;
SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
- __FUNCTION__, sk, addrs, addrcnt);
+ __func__, sk, addrs, addrcnt);
- list_for_each(pos, &ep->asocs) {
- asoc = list_entry(pos, struct sctp_association, asocs);
+ list_for_each_entry(asoc, &ep->asocs, asocs) {
if (!asoc->peer.asconf_capable)
continue;
@@ -787,9 +783,8 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
* as some of the addresses in the bind address list are
* about to be deleted and cannot be used as source addresses.
*/
- list_for_each(pos1, &asoc->peer.transport_addr_list) {
- transport = list_entry(pos1, struct sctp_transport,
- transports);
+ list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+ transports) {
dst_release(transport->dst);
sctp_transport_route(transport, NULL,
sctp_sk(asoc->base.sk));
@@ -1197,7 +1192,7 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
struct sockaddr *kaddrs;
SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n",
- __FUNCTION__, sk, addrs, addrs_size);
+ __func__, sk, addrs, addrs_size);
if (unlikely(addrs_size <= 0))
return -EINVAL;
@@ -1397,7 +1392,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
long timeo;
__u16 sinfo_flags = 0;
struct sctp_datamsg *datamsg;
- struct list_head *pos;
int msg_flags = msg->msg_flags;
SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %zu)\n",
@@ -1727,9 +1721,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
}
/* Now send the (possibly) fragmented message. */
- list_for_each(pos, &datamsg->chunks) {
- chunk = list_entry(pos, struct sctp_chunk, frag_list);
- sctp_datamsg_track(chunk);
+ list_for_each_entry(chunk, &datamsg->chunks, frag_list) {
+ sctp_chunk_hold(chunk);
/* Do accounting for the write space. */
sctp_set_owner_w(chunk);
@@ -1748,7 +1741,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("We sent primitively.\n");
}
- sctp_datamsg_free(datamsg);
+ sctp_datamsg_put(datamsg);
if (err)
goto out_free;
else
@@ -2301,11 +2294,8 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
* transport.
*/
if (!trans && asoc) {
- struct list_head *pos;
-
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- trans = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+ transports) {
sctp_apply_peer_addr_params(&params, trans, asoc, sp,
hb_change, pmtud_change,
sackdelay_change);
@@ -2396,11 +2386,8 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
/* If change is for association, also apply to each transport. */
if (asoc) {
- struct list_head *pos;
-
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- trans = list_entry(pos, struct sctp_transport,
- transports);
+ list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+ transports) {
if (params.assoc_value) {
trans->sackdelay =
msecs_to_jiffies(params.assoc_value);
@@ -2632,13 +2619,10 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int o
if (assocparams.sasoc_asocmaxrxt != 0) {
__u32 path_sum = 0;
int paths = 0;
- struct list_head *pos;
struct sctp_transport *peer_addr;
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- peer_addr = list_entry(pos,
- struct sctp_transport,
- transports);
+ list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list,
+ transports) {
path_sum += peer_addr->pathmaxrxt;
paths++;
}
@@ -2716,7 +2700,6 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op
static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen)
{
struct sctp_association *asoc;
- struct list_head *pos;
struct sctp_sock *sp = sctp_sk(sk);
int val;
@@ -2729,8 +2712,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl
sp->user_frag = val;
/* Update the frag_point of the existing associations. */
- list_for_each(pos, &(sp->ep->asocs)) {
- asoc = list_entry(pos, struct sctp_association, asocs);
+ list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
}
@@ -3302,7 +3284,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr,
sctp_lock_sock(sk);
SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d\n",
- __FUNCTION__, sk, addr, addr_len);
+ __func__, sk, addr, addr_len);
/* Validate addr_len before calling common connect/connectx routine. */
af = sctp_get_af_specific(addr->sa_family);
@@ -3823,7 +3805,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
goto out;
}
- SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc);
+ SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc);
retval = sctp_do_peeloff(asoc, &newsock);
if (retval < 0)
@@ -3837,7 +3819,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
}
SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n",
- __FUNCTION__, sk, asoc, newsock->sk, retval);
+ __func__, sk, asoc, newsock->sk, retval);
/* Return the fd mapped to the new socket. */
peeloff.sd = retval;
@@ -4151,7 +4133,6 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
int __user *optlen)
{
struct sctp_association *asoc;
- struct list_head *pos;
int cnt = 0;
struct sctp_getaddrs_old getaddrs;
struct sctp_transport *from;
@@ -4176,8 +4157,8 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
return -EINVAL;
to = (void __user *)getaddrs.addrs;
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- from = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(from, &asoc->peer.transport_addr_list,
+ transports) {
memcpy(&temp, &from->ipaddr, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
@@ -4200,7 +4181,6 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
char __user *optval, int __user *optlen)
{
struct sctp_association *asoc;
- struct list_head *pos;
int cnt = 0;
struct sctp_getaddrs getaddrs;
struct sctp_transport *from;
@@ -4225,8 +4205,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
to = optval + offsetof(struct sctp_getaddrs,addrs);
space_left = len - offsetof(struct sctp_getaddrs,addrs);
- list_for_each(pos, &asoc->peer.transport_addr_list) {
- from = list_entry(pos, struct sctp_transport, transports);
+ list_for_each_entry(from, &asoc->peer.transport_addr_list,
+ transports) {
memcpy(&temp, &from->ipaddr, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
@@ -4421,7 +4401,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
if (copy_from_user(&getaddrs, optval, len))
return -EFAULT;
- if (getaddrs.addr_num <= 0) return -EINVAL;
+ if (getaddrs.addr_num <= 0 ||
+ getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr)))
+ return -EINVAL;
/*
* For UDP-style sockets, id specifies the association to query.
* If the id field is set to the value '0' then the locally bound
@@ -5761,8 +5743,8 @@ static struct sctp_bind_bucket *sctp_bucket_create(
struct sctp_bind_bucket *pp;
pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC);
- SCTP_DBG_OBJCNT_INC(bind_bucket);
if (pp) {
+ SCTP_DBG_OBJCNT_INC(bind_bucket);
pp->port = snum;
pp->fastreuse = 0;
INIT_HLIST_HEAD(&pp->owner);
@@ -5868,11 +5850,12 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
sctp_cmsgs_t *cmsgs)
{
struct cmsghdr *cmsg;
+ struct msghdr *my_msg = (struct msghdr *)msg;
for (cmsg = CMSG_FIRSTHDR(msg);
cmsg != NULL;
- cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) {
- if (!CMSG_OK(msg, cmsg))
+ cmsg = CMSG_NXTHDR(my_msg, cmsg)) {
+ if (!CMSG_OK(my_msg, cmsg))
return -EINVAL;
/* Should we parse this header or ignore? */
@@ -6193,11 +6176,9 @@ do_nonblock:
void sctp_write_space(struct sock *sk)
{
struct sctp_association *asoc;
- struct list_head *pos;
/* Wake up the tasks in each wait queue. */
- list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) {
- asoc = list_entry(pos, struct sctp_association, asocs);
+ list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) {
__sctp_write_space(asoc);
}
}
@@ -6233,7 +6214,7 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
long current_timeo = *timeo_p;
DEFINE_WAIT(wait);
- SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc,
+ SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __func__, asoc,
(long)(*timeo_p));
/* Increment the association's refcnt. */
@@ -6513,8 +6494,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
}
-DEFINE_PROTO_INUSE(sctp)
-
/* This proto struct describes the ULP interface for SCTP. */
struct proto sctp_prot = {
.name = "SCTP",
@@ -6544,11 +6523,9 @@ struct proto sctp_prot = {
.enter_memory_pressure = sctp_enter_memory_pressure,
.memory_allocated = &sctp_memory_allocated,
.sockets_allocated = &sctp_sockets_allocated,
- REF_PROTO_INUSE(sctp)
};
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-DEFINE_PROTO_INUSE(sctpv6)
struct proto sctpv6_prot = {
.name = "SCTPv6",
@@ -6578,6 +6555,5 @@ struct proto sctpv6_prot = {
.enter_memory_pressure = sctp_enter_memory_pressure,
.memory_allocated = &sctp_memory_allocated,
.sockets_allocated = &sctp_sockets_allocated,
- REF_PROTO_INUSE(sctpv6)
};
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index d9f8af852b5..3f34f61221e 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -79,6 +79,7 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer->rttvar = 0;
peer->srtt = 0;
peer->rto_pending = 0;
+ peer->fast_recovery = 0;
peer->last_time_heard = jiffies;
peer->last_time_used = jiffies;
@@ -190,7 +191,7 @@ static void sctp_transport_destroy(struct sctp_transport *transport)
/* Start T3_rtx timer if it is not already running and update the heartbeat
* timer. This routine is called every time a DATA chunk is sent.
*/
-void sctp_transport_reset_timers(struct sctp_transport *transport)
+void sctp_transport_reset_timers(struct sctp_transport *transport, int force)
{
/* RFC 2960 6.3.2 Retransmission Timer Rules
*
@@ -200,7 +201,7 @@ void sctp_transport_reset_timers(struct sctp_transport *transport)
* address.
*/
- if (!timer_pending(&transport->T3_rtx_timer))
+ if (force || !timer_pending(&transport->T3_rtx_timer))
if (!mod_timer(&transport->T3_rtx_timer,
jiffies + transport->rto))
sctp_transport_hold(transport);
@@ -260,7 +261,7 @@ void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
printk(KERN_WARNING "%s: Reported pmtu %d too low, "
"using default minimum of %d\n",
- __FUNCTION__, pmtu,
+ __func__, pmtu,
SCTP_DEFAULT_MINSEGMENT);
/* Use default minimum segment size and disable
* pmtu discovery on this transport.
@@ -291,7 +292,7 @@ void sctp_transport_route(struct sctp_transport *transport,
if (saddr)
memcpy(&transport->saddr, saddr, sizeof(union sctp_addr));
else
- af->get_saddr(asoc, dst, daddr, &transport->saddr);
+ af->get_saddr(opt, asoc, dst, daddr, &transport->saddr);
transport->dst = dst;
if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
@@ -388,7 +389,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
tp->rto_pending = 0;
SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d "
- "rttvar: %d, rto: %ld\n", __FUNCTION__,
+ "rttvar: %d, rto: %ld\n", __func__,
tp, rtt, tp->srtt, tp->rttvar, tp->rto);
}
@@ -403,11 +404,16 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
cwnd = transport->cwnd;
flight_size = transport->flight_size;
+ /* See if we need to exit Fast Recovery first */
+ if (transport->fast_recovery &&
+ TSN_lte(transport->fast_recovery_exit, sack_ctsn))
+ transport->fast_recovery = 0;
+
/* The appropriate cwnd increase algorithm is performed if, and only
- * if the cumulative TSN has advanced and the congestion window is
+ * if the cumulative TSN whould advanced and the congestion window is
* being fully utilized.
*/
- if ((transport->asoc->ctsn_ack_point >= sack_ctsn) ||
+ if (TSN_lte(sack_ctsn, transport->asoc->ctsn_ack_point) ||
(flight_size < cwnd))
return;
@@ -416,17 +422,23 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
pmtu = transport->asoc->pathmtu;
if (cwnd <= ssthresh) {
- /* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less
- * than or equal to ssthresh an SCTP endpoint MUST use the
- * slow start algorithm to increase cwnd only if the current
- * congestion window is being fully utilized and an incoming
- * SACK advances the Cumulative TSN Ack Point. Only when these
- * two conditions are met can the cwnd be increased otherwise
- * the cwnd MUST not be increased. If these conditions are met
- * then cwnd MUST be increased by at most the lesser of
- * 1) the total size of the previously outstanding DATA
- * chunk(s) acknowledged, and 2) the destination's path MTU.
+ /* RFC 4960 7.2.1
+ * o When cwnd is less than or equal to ssthresh, an SCTP
+ * endpoint MUST use the slow-start algorithm to increase
+ * cwnd only if the current congestion window is being fully
+ * utilized, an incoming SACK advances the Cumulative TSN
+ * Ack Point, and the data sender is not in Fast Recovery.
+ * Only when these three conditions are met can the cwnd be
+ * increased; otherwise, the cwnd MUST not be increased.
+ * If these conditions are met, then cwnd MUST be increased
+ * by, at most, the lesser of 1) the total size of the
+ * previously outstanding DATA chunk(s) acknowledged, and
+ * 2) the destination's path MTU. This upper bound protects
+ * against the ACK-Splitting attack outlined in [SAVAGE99].
*/
+ if (transport->fast_recovery)
+ return;
+
if (bytes_acked > pmtu)
cwnd += pmtu;
else
@@ -434,7 +446,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
SCTP_DEBUG_PRINTK("%s: SLOW START: transport: %p, "
"bytes_acked: %d, cwnd: %d, ssthresh: %d, "
"flight_size: %d, pba: %d\n",
- __FUNCTION__,
+ __func__,
transport, bytes_acked, cwnd,
ssthresh, flight_size, pba);
} else {
@@ -460,7 +472,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
SCTP_DEBUG_PRINTK("%s: CONGESTION AVOIDANCE: "
"transport: %p, bytes_acked: %d, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d\n",
- __FUNCTION__,
+ __func__,
transport, bytes_acked, cwnd,
ssthresh, flight_size, pba);
}
@@ -502,6 +514,13 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
* cwnd = ssthresh
* partial_bytes_acked = 0
*/
+ if (transport->fast_recovery)
+ return;
+
+ /* Mark Fast recovery */
+ transport->fast_recovery = 1;
+ transport->fast_recovery_exit = transport->asoc->next_tsn - 1;
+
transport->ssthresh = max(transport->cwnd/2,
4*transport->asoc->pathmtu);
transport->cwnd = transport->ssthresh;
@@ -546,7 +565,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
transport->partial_bytes_acked = 0;
SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: "
- "%d ssthresh: %d\n", __FUNCTION__,
+ "%d ssthresh: %d\n", __func__,
transport, reason,
transport->cwnd, transport->ssthresh);
}
@@ -586,6 +605,7 @@ void sctp_transport_reset(struct sctp_transport *t)
t->flight_size = 0;
t->error_count = 0;
t->rto_pending = 0;
+ t->fast_recovery = 0;
/* Initialize the state information for SFR-CACC */
t->cacc.changeover_active = 0;
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index b43f1f110f8..ce6cda6b699 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -859,7 +859,7 @@ __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event)
union sctp_notification *notification;
struct sk_buff *skb;
- skb = sctp_event2skb((struct sctp_ulpevent *)event);
+ skb = sctp_event2skb(event);
notification = (union sctp_notification *) skb->data;
return notification->sn_header.sn_type;
}