Skip to content

Commit

Permalink
Merge branch 'sctp-gso-frags-from-chunk'
Browse files Browse the repository at this point in the history
Marcelo Ricardo Leitner says:

====================
sctp: allow GSO frags to access the chunk too

Patchset is named after the most important fix in it. First two patches
are preparing the grounds for the 3rd patch.

After the 3rd, they are not strictly logically related to the patchset,
but I kept them together as they depend on each other.

More details on patch changelogs.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 14, 2016
2 parents ce3a380 + 2d47fd1 commit 398aae2
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 51 deletions.
23 changes: 23 additions & 0 deletions include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include <linux/workqueue.h> /* We need tq_struct. */
#include <linux/sctp.h> /* We need sctp* header structs. */
#include <net/sctp/auth.h> /* We need auth specific structs */
#include <net/ip.h> /* For inet_skb_parm */

/* A convenience structure for handling sockaddr structures.
* We should wean ourselves off this.
Expand Down Expand Up @@ -1092,6 +1093,28 @@ static inline void sctp_outq_cork(struct sctp_outq *q)
q->cork = 1;
}

/* SCTP skb control block.
* sctp_input_cb is currently used on rx and sock rx queue
*/
struct sctp_input_cb {
union {
struct inet_skb_parm h4;
#if IS_ENABLED(CONFIG_IPV6)
struct inet6_skb_parm h6;
#endif
} header;
struct sctp_chunk *chunk;
struct sctp_af *af;
};
#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 {

Expand Down
12 changes: 6 additions & 6 deletions include/net/sctp/ulpevent.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@
*/
struct sctp_ulpevent {
struct sctp_association *asoc;
__u16 stream;
__u16 ssn;
__u16 flags;
struct sctp_chunk *chunk;
unsigned int rmem_len;
__u32 ppid;
__u32 tsn;
__u32 cumtsn;
int msg_flags;
int iif;
unsigned int rmem_len;
__u16 stream;
__u16 ssn;
__u16 flags;
__u16 msg_flags;
};

/* Retrieve the skb this event sits inside of. */
Expand Down
12 changes: 1 addition & 11 deletions net/sctp/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,6 @@ static inline int sctp_rcv_checksum(struct net *net, struct sk_buff *skb)
return 0;
}

struct sctp_input_cb {
union {
struct inet_skb_parm h4;
#if IS_ENABLED(CONFIG_IPV6)
struct inet6_skb_parm h6;
#endif
} header;
struct sctp_chunk *chunk;
};
#define SCTP_INPUT_CB(__skb) ((struct sctp_input_cb *)&((__skb)->cb[0]))

/*
* This is the routine which IP calls when receiving an SCTP packet.
*/
Expand Down Expand Up @@ -151,6 +140,7 @@ int sctp_rcv(struct sk_buff *skb)
af = sctp_get_af_specific(family);
if (unlikely(!af))
goto discard_it;
SCTP_INPUT_CB(skb)->af = af;

/* Initialize local addresses for lookups. */
af->from_skb(&src, skb, 1);
Expand Down
9 changes: 8 additions & 1 deletion net/sctp/inqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
chunk->auth = 0;
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;
cb->af = head_cb->af;
}
}

chunk->chunk_hdr = ch;
Expand Down
9 changes: 4 additions & 5 deletions net/sctp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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? */
Expand Down Expand Up @@ -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);
}
}

Expand Down
1 change: 1 addition & 0 deletions net/sctp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 4 additions & 16 deletions net/sctp/sm_make_chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,9 @@ static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
/* What was the inbound interface for this chunk? */
int sctp_chunk_iif(const struct sctp_chunk *chunk)
{
struct sctp_af *af;
int iif = 0;

af = sctp_get_af_specific(ipver2af(ip_hdr(chunk->skb)->version));
if (af)
iif = af->skb_iif(chunk->skb);
struct sk_buff *skb = chunk->skb;

return iif;
return SCTP_INPUT_CB(skb)->af->skb_iif(skb);
}

/* RFC 2960 3.3.2 Initiation (INIT) (1)
Expand Down Expand Up @@ -1600,7 +1595,6 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
struct sctp_association *asoc;
struct sk_buff *skb;
sctp_scope_t scope;
struct sctp_af *af;

/* Create the bare association. */
scope = sctp_scope(sctp_source(chunk));
Expand All @@ -1610,16 +1604,10 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
asoc->temp = 1;
skb = chunk->skb;
/* Create an entry for the source address of the packet. */
af = sctp_get_af_specific(ipver2af(ip_hdr(skb)->version));
if (unlikely(!af))
goto fail;
af->from_skb(&asoc->c.peer_addr, skb, 1);
SCTP_INPUT_CB(skb)->af->from_skb(&asoc->c.peer_addr, skb, 1);

nodata:
return asoc;

fail:
sctp_association_free(asoc);
return NULL;
}

/* Build a cookie representing asoc.
Expand Down
9 changes: 3 additions & 6 deletions net/sctp/sm_statefuns.c
Original file line number Diff line number Diff line change
Expand Up @@ -6118,14 +6118,11 @@ static int sctp_eat_data(const struct sctp_association *asoc,
* chunk later.
*/

if (!chunk->ecn_ce_done) {
struct sctp_af *af;
if (asoc->peer.ecn_capable && !chunk->ecn_ce_done) {
struct sctp_af *af = SCTP_INPUT_CB(chunk->skb)->af;
chunk->ecn_ce_done = 1;

af = sctp_get_af_specific(
ipver2af(ip_hdr(chunk->skb)->version));

if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
if (af->is_ce(sctp_gso_headskb(chunk->skb))) {
/* Do real work as sideffect. */
sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
SCTP_U32(tsn));
Expand Down
10 changes: 7 additions & 3 deletions net/sctp/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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. */
Expand Down
14 changes: 11 additions & 3 deletions net/sctp/ulpevent.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event);

/* Initialize an ULP event from an given skb. */
static void sctp_ulpevent_init(struct sctp_ulpevent *event,
int msg_flags,
__u16 msg_flags,
unsigned int len)
{
memset(event, 0, sizeof(struct sctp_ulpevent));
Expand All @@ -60,7 +60,7 @@ static void sctp_ulpevent_init(struct sctp_ulpevent *event,
}

/* Create a new sctp_ulpevent. */
static struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags,
static struct sctp_ulpevent *sctp_ulpevent_new(int size, __u16 msg_flags,
gfp_t gfp)
{
struct sctp_ulpevent *event;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand Down

0 comments on commit 398aae2

Please sign in to comment.