summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/sctp/structs.h7
-rw-r--r--include/net/sctp/ulpevent.h2
-rw-r--r--net/sctp/inqueue.c7
-rw-r--r--net/sctp/ipv6.c9
-rw-r--r--net/sctp/protocol.c1
-rw-r--r--net/sctp/sm_statefuns.c3
-rw-r--r--net/sctp/socket.c10
-rw-r--r--net/sctp/ulpevent.c10
8 files changed, 38 insertions, 11 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 966c3a40039c..f6f201de6fa4 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1107,6 +1107,13 @@ struct sctp_input_cb {
};
#define SCTP_INPUT_CB(__skb) ((struct sctp_input_cb *)&((__skb)->cb[0]))
+static inline const struct sk_buff *sctp_gso_headskb(const struct sk_buff *skb)
+{
+ const struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
+
+ return chunk->head_skb ? : skb;
+}
+
/* These bind address data fields common between endpoints and associations */
struct sctp_bind_addr {
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h
index aa342645dbce..2c098cd7e7e2 100644
--- a/include/net/sctp/ulpevent.h
+++ b/include/net/sctp/ulpevent.h
@@ -48,11 +48,11 @@
*/
struct sctp_ulpevent {
struct sctp_association *asoc;
+ struct sctp_chunk *chunk;
unsigned int rmem_len;
__u32 ppid;
__u32 tsn;
__u32 cumtsn;
- int iif;
__u16 stream;
__u16 ssn;
__u16 flags;
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index edabbbdfca54..147d975b0455 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -218,6 +218,13 @@ new_skb:
chunk->has_asconf = 0;
chunk->end_of_packet = 0;
chunk->ecn_ce_done = 0;
+ if (chunk->head_skb) {
+ struct sctp_input_cb
+ *cb = SCTP_INPUT_CB(chunk->skb),
+ *head_cb = SCTP_INPUT_CB(chunk->head_skb);
+
+ cb->chunk = head_cb->chunk;
+ }
}
chunk->chunk_hdr = ch;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 0657d18a85bf..ae6f1a2178ba 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -420,6 +420,7 @@ static void sctp_v6_from_skb(union sctp_addr *addr, struct sk_buff *skb,
addr->v6.sin6_flowinfo = 0; /* FIXME */
addr->v6.sin6_scope_id = ((struct inet6_skb_parm *)skb->cb)->iif;
+ /* Always called on head skb, so this is safe */
sh = sctp_hdr(skb);
if (is_saddr) {
*port = sh->source;
@@ -710,8 +711,7 @@ static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
/* Where did this skb come from? */
static int sctp_v6_skb_iif(const struct sk_buff *skb)
{
- struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
- return opt->iif;
+ return IP6CB(skb)->iif;
}
/* Was this packet marked by Explicit Congestion Notification? */
@@ -780,15 +780,14 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
if (ip_hdr(skb)->version == 4) {
addr->v4.sin_family = AF_INET;
addr->v4.sin_port = sh->source;
- addr->v4.sin_addr.s_addr = ip_hdr(skb)->saddr;
+ addr->v4.sin_addr.s_addr = ip_hdr(skb)->saddr;
} else {
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_flowinfo = 0;
addr->v6.sin6_port = sh->source;
addr->v6.sin6_addr = ipv6_hdr(skb)->saddr;
if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
- struct sctp_ulpevent *ev = sctp_skb2event(skb);
- addr->v6.sin6_scope_id = ev->iif;
+ addr->v6.sin6_scope_id = sctp_v6_skb_iif(skb);
}
}
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 3b56ae55aba3..1adb9270e317 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -240,6 +240,7 @@ static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
port = &addr->v4.sin_port;
addr->v4.sin_family = AF_INET;
+ /* Always called on head skb, so this is safe */
sh = sctp_hdr(skb);
if (is_saddr) {
*port = sh->source;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index f1f08c8f277b..5aabf42065e2 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -6125,7 +6125,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
af = sctp_get_af_specific(
ipver2af(ip_hdr(chunk->skb)->version));
- if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
+ if (af && af->is_ce(sctp_gso_headskb(chunk->skb)) &&
+ asoc->peer.ecn_capable) {
/* Do real work as sideffect. */
sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
SCTP_U32(tsn));
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 71c7dc5ea62e..52fdd540a9ef 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2066,7 +2066,7 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
{
struct sctp_ulpevent *event = NULL;
struct sctp_sock *sp = sctp_sk(sk);
- struct sk_buff *skb;
+ struct sk_buff *skb, *head_skb;
int copied;
int err = 0;
int skb_len;
@@ -2102,12 +2102,16 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
if (err)
goto out_free;
- sock_recv_ts_and_drops(msg, sk, skb);
+ if (event->chunk && event->chunk->head_skb)
+ head_skb = event->chunk->head_skb;
+ else
+ head_skb = skb;
+ sock_recv_ts_and_drops(msg, sk, head_skb);
if (sctp_ulpevent_is_notification(event)) {
msg->msg_flags |= MSG_NOTIFICATION;
sp->pf->event_msgname(event, msg->msg_name, addr_len);
} else {
- sp->pf->skb_msgname(skb, msg->msg_name, addr_len);
+ sp->pf->skb_msgname(head_skb, msg->msg_name, addr_len);
}
/* Check if we allow SCTP_NXTINFO. */
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 706f5bc9f0c3..f6219b164b42 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -701,6 +701,12 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
sctp_ulpevent_receive_data(event, asoc);
+ /* And hold the chunk as we need it for getting the IP headers
+ * later in recvmsg
+ */
+ sctp_chunk_hold(chunk);
+ event->chunk = chunk;
+
event->stream = ntohs(chunk->subh.data_hdr->stream);
event->ssn = ntohs(chunk->subh.data_hdr->ssn);
event->ppid = chunk->subh.data_hdr->ppid;
@@ -710,11 +716,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
}
event->tsn = ntohl(chunk->subh.data_hdr->tsn);
event->msg_flags |= chunk->chunk_hdr->flags;
- event->iif = sctp_chunk_iif(chunk);
return event;
fail_mark:
+ sctp_chunk_put(chunk);
kfree_skb(skb);
fail:
return NULL;
@@ -1007,6 +1013,7 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
done:
sctp_assoc_rwnd_increase(event->asoc, len);
+ sctp_chunk_put(event->chunk);
sctp_ulpevent_release_owner(event);
}
@@ -1029,6 +1036,7 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event)
}
done:
+ sctp_chunk_put(event->chunk);
sctp_ulpevent_release_owner(event);
}